18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lib/ts_fsm.c A naive finite state machine text search approach 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: Thomas Graf <tgraf@suug.ch> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * ========================================================================== 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * A finite state machine consists of n states (struct ts_fsm_token) 108c2ecf20Sopenharmony_ci * representing the pattern as a finite automaton. The data is read 118c2ecf20Sopenharmony_ci * sequentially on an octet basis. Every state token specifies the number 128c2ecf20Sopenharmony_ci * of recurrences and the type of value accepted which can be either a 138c2ecf20Sopenharmony_ci * specific character or ctype based set of characters. The available 148c2ecf20Sopenharmony_ci * type of recurrences include 1, (0|1), [0 n], and [1 n]. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * The algorithm differs between strict/non-strict mode specifying 178c2ecf20Sopenharmony_ci * whether the pattern has to start at the first octet. Strict mode 188c2ecf20Sopenharmony_ci * is enabled by default and can be disabled by inserting 198c2ecf20Sopenharmony_ci * TS_FSM_HEAD_IGNORE as the first token in the chain. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The runtime performance of the algorithm should be around O(n), 228c2ecf20Sopenharmony_ci * however while in strict mode the average runtime can be better. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/types.h> 278c2ecf20Sopenharmony_ci#include <linux/string.h> 288c2ecf20Sopenharmony_ci#include <linux/ctype.h> 298c2ecf20Sopenharmony_ci#include <linux/textsearch.h> 308c2ecf20Sopenharmony_ci#include <linux/textsearch_fsm.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct ts_fsm 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci unsigned int ntokens; 358c2ecf20Sopenharmony_ci struct ts_fsm_token tokens[]; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* other values derived from ctype.h */ 398c2ecf20Sopenharmony_ci#define _A 0x100 /* ascii */ 408c2ecf20Sopenharmony_ci#define _W 0x200 /* wildcard */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Map to _ctype flags and some magic numbers */ 438c2ecf20Sopenharmony_cistatic const u16 token_map[TS_FSM_TYPE_MAX+1] = { 448c2ecf20Sopenharmony_ci [TS_FSM_SPECIFIC] = 0, 458c2ecf20Sopenharmony_ci [TS_FSM_WILDCARD] = _W, 468c2ecf20Sopenharmony_ci [TS_FSM_CNTRL] = _C, 478c2ecf20Sopenharmony_ci [TS_FSM_LOWER] = _L, 488c2ecf20Sopenharmony_ci [TS_FSM_UPPER] = _U, 498c2ecf20Sopenharmony_ci [TS_FSM_PUNCT] = _P, 508c2ecf20Sopenharmony_ci [TS_FSM_SPACE] = _S, 518c2ecf20Sopenharmony_ci [TS_FSM_DIGIT] = _D, 528c2ecf20Sopenharmony_ci [TS_FSM_XDIGIT] = _D | _X, 538c2ecf20Sopenharmony_ci [TS_FSM_ALPHA] = _U | _L, 548c2ecf20Sopenharmony_ci [TS_FSM_ALNUM] = _U | _L | _D, 558c2ecf20Sopenharmony_ci [TS_FSM_PRINT] = _P | _U | _L | _D | _SP, 568c2ecf20Sopenharmony_ci [TS_FSM_GRAPH] = _P | _U | _L | _D, 578c2ecf20Sopenharmony_ci [TS_FSM_ASCII] = _A, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const u16 token_lookup_tbl[256] = { 618c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 0- 3 */ 628c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 4- 7 */ 638c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C|_S, /* 8- 11 */ 648c2ecf20Sopenharmony_ci_W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C, _W|_A|_C, /* 12- 15 */ 658c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 16- 19 */ 668c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 20- 23 */ 678c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 24- 27 */ 688c2ecf20Sopenharmony_ci_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 28- 31 */ 698c2ecf20Sopenharmony_ci_W|_A|_S|_SP, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 32- 35 */ 708c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 36- 39 */ 718c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 40- 43 */ 728c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 44- 47 */ 738c2ecf20Sopenharmony_ci_W|_A|_D, _W|_A|_D, _W|_A|_D, _W|_A|_D, /* 48- 51 */ 748c2ecf20Sopenharmony_ci_W|_A|_D, _W|_A|_D, _W|_A|_D, _W|_A|_D, /* 52- 55 */ 758c2ecf20Sopenharmony_ci_W|_A|_D, _W|_A|_D, _W|_A|_P, _W|_A|_P, /* 56- 59 */ 768c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 60- 63 */ 778c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U|_X, /* 64- 67 */ 788c2ecf20Sopenharmony_ci_W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U, /* 68- 71 */ 798c2ecf20Sopenharmony_ci_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 72- 75 */ 808c2ecf20Sopenharmony_ci_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 76- 79 */ 818c2ecf20Sopenharmony_ci_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 80- 83 */ 828c2ecf20Sopenharmony_ci_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 84- 87 */ 838c2ecf20Sopenharmony_ci_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_P, /* 88- 91 */ 848c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 92- 95 */ 858c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L|_X, /* 96- 99 */ 868c2ecf20Sopenharmony_ci_W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L, /* 100-103 */ 878c2ecf20Sopenharmony_ci_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 104-107 */ 888c2ecf20Sopenharmony_ci_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 108-111 */ 898c2ecf20Sopenharmony_ci_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 112-115 */ 908c2ecf20Sopenharmony_ci_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 116-119 */ 918c2ecf20Sopenharmony_ci_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_P, /* 120-123 */ 928c2ecf20Sopenharmony_ci_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_C, /* 124-127 */ 938c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 128-131 */ 948c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 132-135 */ 958c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 136-139 */ 968c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 140-143 */ 978c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 144-147 */ 988c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 148-151 */ 998c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 152-155 */ 1008c2ecf20Sopenharmony_ci_W, _W, _W, _W, /* 156-159 */ 1018c2ecf20Sopenharmony_ci_W|_S|_SP, _W|_P, _W|_P, _W|_P, /* 160-163 */ 1028c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 164-167 */ 1038c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 168-171 */ 1048c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 172-175 */ 1058c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 176-179 */ 1068c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 180-183 */ 1078c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 184-187 */ 1088c2ecf20Sopenharmony_ci_W|_P, _W|_P, _W|_P, _W|_P, /* 188-191 */ 1098c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_U, /* 192-195 */ 1108c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_U, /* 196-199 */ 1118c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_U, /* 200-203 */ 1128c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_U, /* 204-207 */ 1138c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_U, /* 208-211 */ 1148c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_P, /* 212-215 */ 1158c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_U, /* 216-219 */ 1168c2ecf20Sopenharmony_ci_W|_U, _W|_U, _W|_U, _W|_L, /* 220-223 */ 1178c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L, /* 224-227 */ 1188c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L, /* 228-231 */ 1198c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L, /* 232-235 */ 1208c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L, /* 236-239 */ 1218c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L, /* 240-243 */ 1228c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_P, /* 244-247 */ 1238c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L, /* 248-251 */ 1248c2ecf20Sopenharmony_ci_W|_L, _W|_L, _W|_L, _W|_L}; /* 252-255 */ 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic inline int match_token(struct ts_fsm_token *t, u8 d) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (t->type) 1298c2ecf20Sopenharmony_ci return (token_lookup_tbl[d] & t->type) != 0; 1308c2ecf20Sopenharmony_ci else 1318c2ecf20Sopenharmony_ci return t->value == d; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic unsigned int fsm_find(struct ts_config *conf, struct ts_state *state) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct ts_fsm *fsm = ts_config_priv(conf); 1378c2ecf20Sopenharmony_ci struct ts_fsm_token *cur = NULL, *next; 1388c2ecf20Sopenharmony_ci unsigned int match_start, block_idx = 0, tok_idx; 1398c2ecf20Sopenharmony_ci unsigned block_len = 0, strict, consumed = state->offset; 1408c2ecf20Sopenharmony_ci const u8 *data; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define GET_NEXT_BLOCK() \ 1438c2ecf20Sopenharmony_ci({ consumed += block_idx; \ 1448c2ecf20Sopenharmony_ci block_idx = 0; \ 1458c2ecf20Sopenharmony_ci block_len = conf->get_next_block(consumed, &data, conf, state); }) 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define TOKEN_MISMATCH() \ 1488c2ecf20Sopenharmony_ci do { \ 1498c2ecf20Sopenharmony_ci if (strict) \ 1508c2ecf20Sopenharmony_ci goto no_match; \ 1518c2ecf20Sopenharmony_ci block_idx++; \ 1528c2ecf20Sopenharmony_ci goto startover; \ 1538c2ecf20Sopenharmony_ci } while(0) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define end_of_data() unlikely(block_idx >= block_len && !GET_NEXT_BLOCK()) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (end_of_data()) 1588c2ecf20Sopenharmony_ci goto no_match; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci strict = fsm->tokens[0].recur != TS_FSM_HEAD_IGNORE; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistartover: 1638c2ecf20Sopenharmony_ci match_start = consumed + block_idx; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (tok_idx = 0; tok_idx < fsm->ntokens; tok_idx++) { 1668c2ecf20Sopenharmony_ci cur = &fsm->tokens[tok_idx]; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (likely(tok_idx < (fsm->ntokens - 1))) 1698c2ecf20Sopenharmony_ci next = &fsm->tokens[tok_idx + 1]; 1708c2ecf20Sopenharmony_ci else 1718c2ecf20Sopenharmony_ci next = NULL; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci switch (cur->recur) { 1748c2ecf20Sopenharmony_ci case TS_FSM_SINGLE: 1758c2ecf20Sopenharmony_ci if (end_of_data()) 1768c2ecf20Sopenharmony_ci goto no_match; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!match_token(cur, data[block_idx])) 1798c2ecf20Sopenharmony_ci TOKEN_MISMATCH(); 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci case TS_FSM_PERHAPS: 1838c2ecf20Sopenharmony_ci if (end_of_data() || 1848c2ecf20Sopenharmony_ci !match_token(cur, data[block_idx])) 1858c2ecf20Sopenharmony_ci continue; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci case TS_FSM_MULTI: 1898c2ecf20Sopenharmony_ci if (end_of_data()) 1908c2ecf20Sopenharmony_ci goto no_match; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!match_token(cur, data[block_idx])) 1938c2ecf20Sopenharmony_ci TOKEN_MISMATCH(); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci block_idx++; 1968c2ecf20Sopenharmony_ci /* fall through */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci case TS_FSM_ANY: 1998c2ecf20Sopenharmony_ci if (next == NULL) 2008c2ecf20Sopenharmony_ci goto found_match; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (end_of_data()) 2038c2ecf20Sopenharmony_ci continue; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci while (!match_token(next, data[block_idx])) { 2068c2ecf20Sopenharmony_ci if (!match_token(cur, data[block_idx])) 2078c2ecf20Sopenharmony_ci TOKEN_MISMATCH(); 2088c2ecf20Sopenharmony_ci block_idx++; 2098c2ecf20Sopenharmony_ci if (end_of_data()) 2108c2ecf20Sopenharmony_ci goto no_match; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci continue; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * Optimization: Prefer small local loop over jumping 2168c2ecf20Sopenharmony_ci * back and forth until garbage at head is munched. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci case TS_FSM_HEAD_IGNORE: 2198c2ecf20Sopenharmony_ci if (end_of_data()) 2208c2ecf20Sopenharmony_ci continue; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci while (!match_token(next, data[block_idx])) { 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * Special case, don't start over upon 2258c2ecf20Sopenharmony_ci * a mismatch, give the user the 2268c2ecf20Sopenharmony_ci * chance to specify the type of data 2278c2ecf20Sopenharmony_ci * allowed to be ignored. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci if (!match_token(cur, data[block_idx])) 2308c2ecf20Sopenharmony_ci goto no_match; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci block_idx++; 2338c2ecf20Sopenharmony_ci if (end_of_data()) 2348c2ecf20Sopenharmony_ci goto no_match; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci match_start = consumed + block_idx; 2388c2ecf20Sopenharmony_ci continue; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci block_idx++; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (end_of_data()) 2458c2ecf20Sopenharmony_ci goto found_match; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cino_match: 2488c2ecf20Sopenharmony_ci return UINT_MAX; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cifound_match: 2518c2ecf20Sopenharmony_ci state->offset = consumed + block_idx; 2528c2ecf20Sopenharmony_ci return match_start; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic struct ts_config *fsm_init(const void *pattern, unsigned int len, 2568c2ecf20Sopenharmony_ci gfp_t gfp_mask, int flags) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci int i, err = -EINVAL; 2598c2ecf20Sopenharmony_ci struct ts_config *conf; 2608c2ecf20Sopenharmony_ci struct ts_fsm *fsm; 2618c2ecf20Sopenharmony_ci struct ts_fsm_token *tokens = (struct ts_fsm_token *) pattern; 2628c2ecf20Sopenharmony_ci unsigned int ntokens = len / sizeof(*tokens); 2638c2ecf20Sopenharmony_ci size_t priv_size = sizeof(*fsm) + len; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (len % sizeof(struct ts_fsm_token) || ntokens < 1) 2668c2ecf20Sopenharmony_ci goto errout; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (flags & TS_IGNORECASE) 2698c2ecf20Sopenharmony_ci goto errout; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci for (i = 0; i < ntokens; i++) { 2728c2ecf20Sopenharmony_ci struct ts_fsm_token *t = &tokens[i]; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (t->type > TS_FSM_TYPE_MAX || t->recur > TS_FSM_RECUR_MAX) 2758c2ecf20Sopenharmony_ci goto errout; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (t->recur == TS_FSM_HEAD_IGNORE && 2788c2ecf20Sopenharmony_ci (i != 0 || i == (ntokens - 1))) 2798c2ecf20Sopenharmony_ci goto errout; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci conf = alloc_ts_config(priv_size, gfp_mask); 2838c2ecf20Sopenharmony_ci if (IS_ERR(conf)) 2848c2ecf20Sopenharmony_ci return conf; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci conf->flags = flags; 2878c2ecf20Sopenharmony_ci fsm = ts_config_priv(conf); 2888c2ecf20Sopenharmony_ci fsm->ntokens = ntokens; 2898c2ecf20Sopenharmony_ci memcpy(fsm->tokens, pattern, len); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for (i = 0; i < fsm->ntokens; i++) { 2928c2ecf20Sopenharmony_ci struct ts_fsm_token *t = &fsm->tokens[i]; 2938c2ecf20Sopenharmony_ci t->type = token_map[t->type]; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return conf; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cierrout: 2998c2ecf20Sopenharmony_ci return ERR_PTR(err); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void *fsm_get_pattern(struct ts_config *conf) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct ts_fsm *fsm = ts_config_priv(conf); 3058c2ecf20Sopenharmony_ci return fsm->tokens; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic unsigned int fsm_get_pattern_len(struct ts_config *conf) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct ts_fsm *fsm = ts_config_priv(conf); 3118c2ecf20Sopenharmony_ci return fsm->ntokens * sizeof(struct ts_fsm_token); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic struct ts_ops fsm_ops = { 3158c2ecf20Sopenharmony_ci .name = "fsm", 3168c2ecf20Sopenharmony_ci .find = fsm_find, 3178c2ecf20Sopenharmony_ci .init = fsm_init, 3188c2ecf20Sopenharmony_ci .get_pattern = fsm_get_pattern, 3198c2ecf20Sopenharmony_ci .get_pattern_len = fsm_get_pattern_len, 3208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3218c2ecf20Sopenharmony_ci .list = LIST_HEAD_INIT(fsm_ops.list) 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int __init init_fsm(void) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci return textsearch_register(&fsm_ops); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void __exit exit_fsm(void) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci textsearch_unregister(&fsm_ops); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cimodule_init(init_fsm); 3378c2ecf20Sopenharmony_cimodule_exit(exit_fsm); 338