1 #ifndef maildir_search_h
2 #define maildir_search_h
3 
4 /*
5 ** Copyright 2002-2011 Double Precision, Inc.
6 ** See COPYING for distribution information.
7 */
8 
9 
10 /*
11 ** A deterministic automaton-based search mechanism.  Search for a particular
12 ** string in a middle of a larger body of text.
13 **
14 ** Allocate a struct maildir_searchengine by yourself, and call
15 ** maildir_search_init() to initialize.
16 **
17 ** Call maildir_search_destroy() to release any allocated memory.
18 **
19 ** Call maildir_search_start_str() to prep the structure for a particular search
20 ** string. Alternatively, call maildir_search_start_unicode() to specify the
21 ** search string as unicode characters. Alternatively,
22 ** call maildir_search_start_str_chset() to specify the search string in
23 ** a specific character. The search string get converted to unicode, then
24 ** converted to lowercase characters, removing leading/trailing whitespace,
25 ** and replacing multiple occurences of whitespace in the search string with
26 ** a single space character.
27 **
28 ** Call maildir_search_reset() to start the search, then call
29 ** maildir_search_step() for each character in the text. Use
30 ** maildir_search_step_unicode() if the search string was specified via
31 ** maildir_search_start_unicode(). Use maildir_search_step_unicode_lc() if
32 ** the search string was specified using via maildir_search_start_str_chset().
33 **
34 ** Call maildir_search_found() to check if the search string is found.
35 */
36 
37 #include "config.h"
38 
39 #include <courier-unicode.h>
40 
41 #include <string.h>
42 #include <stdlib.h>
43 
44 #ifdef  __cplusplus
45 extern "C" {
46 #endif
47 
48 struct maildir_searchengine {
49 	char32_t *string;
50 	size_t string_l;
51 	const char32_t *ptr;
52 	unsigned *r;    /* Retry backoff indexes */
53 	unsigned i;
54 	int spc;
55 	} ;
56 
57 #define maildir_search_init(sei) (memset((sei), 0, sizeof(struct maildir_searchengine)))
58 
59 #define maildir_search_destroy(sei) do { if ((sei)->string) free((sei)->string); if ( (sei)->r) free( (sei)->r); } while (0)
60 
61 int maildir_search_start_str(struct maildir_searchengine *engine,
62 			     const char *string);
63 int maildir_search_start_str_chset(struct maildir_searchengine *engine,
64 				   const char *string,
65 				   const char *chset);
66 int maildir_search_start_unicode(struct maildir_searchengine *engine,
67 				 const char32_t *string);
68 
69 
70 #define	maildir_search_reset(si)	((si)->i=0, (si)->ptr=(si)->string)
71 
72 #define	maildir_search_found(si)	((si)->ptr && \
73 					(si)->ptr[(si)->i] == '\0')
74 #define maildir_search_len(si)		((si)->string_l)
75 
76 #define maildir_search_step_unicode(sie,ch) do \
77         {\
78                 if ( (sie)->ptr && (sie)->ptr[(sie)->i]) \
79                 {\
80                         for (;;) \
81                         {\
82                                 if ( (char32_t)(sie)->ptr[(sie)->i] == (char32_t)(ch) )\
83                                         { (sie)->i++; break; }\
84                                 if ( (sie)->i == 0) break;\
85                                 (sie)->i=(sie)->r[(sie)->i];\
86                         }\
87                 }\
88         } while (0)
89 
90 #define maildir_search_step_unicode_lc(sie,ch) do	\
91 	{						\
92 		char32_t c=(ch);			\
93 		int spc=0;				\
94 							\
95 									\
96 		if (c == ' ' || c == '\t' || c == '\r' || c == '\n')	\
97 		{							\
98 			c=' ';						\
99 			spc=1;						\
100 		}							\
101 									\
102 		if (spc && (sie)->spc)					\
103 			;						\
104 		else							\
105 		{							\
106 			c=unicode_lc(c);				\
107 			maildir_search_step_unicode((sie),c);		\
108 		}							\
109 									\
110 		(sie)->spc=spc;						\
111 	} while(0)
112 
113 #define maildir_search_step(sie,ch) \
114 	maildir_search_step_unicode((sie), ((unsigned char)(ch)))
115 
116 #define maildir_search_atstart(sie) ((sie)->i == 0)
117 
118 #ifdef  __cplusplus
119 }
120 
121 /* A C++ wrapper for the above */
122 
123 #if HAVE_VECTOR
124 #include <vector>
125 #else
126 #if HAVE_VECTOR_H
127 #include <vector.h>
128 #endif
129 #endif
130 
131 #include <string>
132 
133 namespace mail {
134 
135 class Search {
136 
137 	struct maildir_searchengine sei;
138 
139 	std::string String;
140 
141 	std::vector<unsigned> rbuf;
142  public:
143 	Search();
144 	virtual ~Search();
145 
getSearchLen()146 	size_t getSearchLen()
147 	{
148 		return maildir_search_len(&sei);
149 	}
150 
setString(std::string s,std::string chset)151 	bool setString(std::string s, std::string chset)
152 	{
153 		String=s;
154 		return maildir_search_start_str_chset(&sei, s.c_str(),
155 						      chset.c_str()) == 0;
156 	}
157 
reset()158 	void reset()
159 	{
160 		maildir_search_reset(&sei);
161 	}
162 
163 	void operator<<(char c) { maildir_search_step(&sei, c); }
164 
165 	void operator<<(char32_t ch)
166 	{
167 		maildir_search_step_unicode_lc(&sei, ch);
168 	}
169 
atstart()170 	bool atstart() { return maildir_search_atstart(&sei); }
171 	operator bool() { return maildir_search_found(&sei); }
172 
173 	bool operator !() { return ! operator bool(); }
174 
175  private:
176 	Search(const Search &); /* UNDEFINED */
177 
178 	Search &operator=(const Search &); /* UNDEFINED */
179 
180 };
181 
182 }
183 
184 #endif
185 
186 #endif
187