0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/module.h>
0030 #include <linux/types.h>
0031 #include <linux/string.h>
0032 #include <linux/ctype.h>
0033 #include <linux/textsearch.h>
0034
0035 struct ts_kmp
0036 {
0037 u8 * pattern;
0038 unsigned int pattern_len;
0039 unsigned int prefix_tbl[];
0040 };
0041
0042 static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state)
0043 {
0044 struct ts_kmp *kmp = ts_config_priv(conf);
0045 unsigned int i, q = 0, text_len, consumed = state->offset;
0046 const u8 *text;
0047 const int icase = conf->flags & TS_IGNORECASE;
0048
0049 for (;;) {
0050 text_len = conf->get_next_block(consumed, &text, conf, state);
0051
0052 if (unlikely(text_len == 0))
0053 break;
0054
0055 for (i = 0; i < text_len; i++) {
0056 while (q > 0 && kmp->pattern[q]
0057 != (icase ? toupper(text[i]) : text[i]))
0058 q = kmp->prefix_tbl[q - 1];
0059 if (kmp->pattern[q]
0060 == (icase ? toupper(text[i]) : text[i]))
0061 q++;
0062 if (unlikely(q == kmp->pattern_len)) {
0063 state->offset = consumed + i + 1;
0064 return state->offset - kmp->pattern_len;
0065 }
0066 }
0067
0068 consumed += text_len;
0069 }
0070
0071 return UINT_MAX;
0072 }
0073
0074 static inline void compute_prefix_tbl(const u8 *pattern, unsigned int len,
0075 unsigned int *prefix_tbl, int flags)
0076 {
0077 unsigned int k, q;
0078 const u8 icase = flags & TS_IGNORECASE;
0079
0080 for (k = 0, q = 1; q < len; q++) {
0081 while (k > 0 && (icase ? toupper(pattern[k]) : pattern[k])
0082 != (icase ? toupper(pattern[q]) : pattern[q]))
0083 k = prefix_tbl[k-1];
0084 if ((icase ? toupper(pattern[k]) : pattern[k])
0085 == (icase ? toupper(pattern[q]) : pattern[q]))
0086 k++;
0087 prefix_tbl[q] = k;
0088 }
0089 }
0090
0091 static struct ts_config *kmp_init(const void *pattern, unsigned int len,
0092 gfp_t gfp_mask, int flags)
0093 {
0094 struct ts_config *conf;
0095 struct ts_kmp *kmp;
0096 int i;
0097 unsigned int prefix_tbl_len = len * sizeof(unsigned int);
0098 size_t priv_size = sizeof(*kmp) + len + prefix_tbl_len;
0099
0100 conf = alloc_ts_config(priv_size, gfp_mask);
0101 if (IS_ERR(conf))
0102 return conf;
0103
0104 conf->flags = flags;
0105 kmp = ts_config_priv(conf);
0106 kmp->pattern_len = len;
0107 compute_prefix_tbl(pattern, len, kmp->prefix_tbl, flags);
0108 kmp->pattern = (u8 *) kmp->prefix_tbl + prefix_tbl_len;
0109 if (flags & TS_IGNORECASE)
0110 for (i = 0; i < len; i++)
0111 kmp->pattern[i] = toupper(((u8 *)pattern)[i]);
0112 else
0113 memcpy(kmp->pattern, pattern, len);
0114
0115 return conf;
0116 }
0117
0118 static void *kmp_get_pattern(struct ts_config *conf)
0119 {
0120 struct ts_kmp *kmp = ts_config_priv(conf);
0121 return kmp->pattern;
0122 }
0123
0124 static unsigned int kmp_get_pattern_len(struct ts_config *conf)
0125 {
0126 struct ts_kmp *kmp = ts_config_priv(conf);
0127 return kmp->pattern_len;
0128 }
0129
0130 static struct ts_ops kmp_ops = {
0131 .name = "kmp",
0132 .find = kmp_find,
0133 .init = kmp_init,
0134 .get_pattern = kmp_get_pattern,
0135 .get_pattern_len = kmp_get_pattern_len,
0136 .owner = THIS_MODULE,
0137 .list = LIST_HEAD_INIT(kmp_ops.list)
0138 };
0139
0140 static int __init init_kmp(void)
0141 {
0142 return textsearch_register(&kmp_ops);
0143 }
0144
0145 static void __exit exit_kmp(void)
0146 {
0147 textsearch_unregister(&kmp_ops);
0148 }
0149
0150 MODULE_LICENSE("GPL");
0151
0152 module_init(init_kmp);
0153 module_exit(exit_kmp);