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