/src/aspell/lib/new_fmode.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // This file is part of The New Aspell |
2 | | // Copyright (C) 2004 by Christoph Hintermüller (JEH) under the GNU LGPL |
3 | | // license version 2.0 or 2.1. You should have received a copy of the |
4 | | // LGPL license along with this library if you did not you can find it |
5 | | // at http://www.gnu.org/. |
6 | | |
7 | | #include "settings.h" |
8 | | |
9 | | #ifdef USE_POSIX_REGEX |
10 | | # include <sys/types.h> |
11 | | # include <regex.h> |
12 | | #endif |
13 | | |
14 | | #include "stack_ptr.hpp" |
15 | | #include "cache-t.hpp" |
16 | | #include "string.hpp" |
17 | | #include "vector.hpp" |
18 | | #include "config.hpp" |
19 | | #include "errors.hpp" |
20 | | #include "filter.hpp" |
21 | | #include "string_enumeration.hpp" |
22 | | #include "string_list.hpp" |
23 | | #include "posib_err.hpp" |
24 | | #include "file_util.hpp" |
25 | | #include "fstream.hpp" |
26 | | #include "getdata.hpp" |
27 | | #include "strtonum.hpp" |
28 | | #include "asc_ctype.hpp" |
29 | | #include "iostream.hpp" |
30 | | |
31 | | #include "gettext.h" |
32 | | |
33 | | namespace acommon { |
34 | | |
35 | | class FilterMode { |
36 | | public: |
37 | | class MagicString { |
38 | | public: |
39 | 1.78k | MagicString(const String & mode) : mode_(mode), fileExtensions() {} |
40 | | MagicString(const String & magic, const String & mode) |
41 | 3.56k | : magic_(magic), mode_(mode) {} |
42 | | bool matchFile(FILE * in, const String & ext); |
43 | | static PosibErr<bool> testMagic(FILE * seekIn, String & magic, const String & mode); |
44 | 16.0k | void addExtension(const String & ext) { fileExtensions.push_back(ext); } |
45 | | bool hasExtension(const String & ext); |
46 | | void remExtension(const String & ext); |
47 | 16.0k | MagicString & operator += (const String & ext) {addExtension(ext);return *this;} |
48 | 0 | MagicString & operator -= (const String & ext) {remExtension(ext);return *this;} |
49 | 0 | MagicString & operator = (const String & ext) { |
50 | 0 | fileExtensions.clear(); |
51 | 0 | addExtension(ext); |
52 | 0 | return *this; |
53 | 0 | } |
54 | 24.9k | const String & magic() const { return magic_; } |
55 | 0 | const String & magicMode() const { return mode_; } |
56 | 28.0k | ~MagicString() {} |
57 | | private: |
58 | | String magic_; |
59 | | String mode_; |
60 | | Vector<String> fileExtensions; |
61 | | }; |
62 | | |
63 | | FilterMode(const String & name); |
64 | | PosibErr<bool> addModeExtension(const String & ext, String toMagic); |
65 | | PosibErr<bool> remModeExtension(const String & ext, String toMagic); |
66 | | bool lockFileToMode(const String & fileName,FILE * in = NULL); |
67 | | const String & modeName() const; |
68 | 5.35k | void setDescription(const String & desc) {desc_ = desc;} |
69 | 0 | const String & getDescription() const {return desc_;} |
70 | | PosibErr<void> expand(Config * config); |
71 | | PosibErr<void> build(FStream &, int line = 1, |
72 | | const char * fname = "mode file"); |
73 | | |
74 | | ~FilterMode(); |
75 | | private: |
76 | | //map extensions to magic keys |
77 | | String name_; |
78 | | String desc_; |
79 | | String file_; |
80 | | Vector<MagicString> magicKeys; |
81 | | struct KeyValue { |
82 | | String key; |
83 | | String value; |
84 | 0 | KeyValue() {} |
85 | 14.7k | KeyValue(ParmStr k, ParmStr v) : key(k), value(v) {} |
86 | | }; |
87 | | Vector<KeyValue> expansion; |
88 | | }; |
89 | | |
90 | | class FilterModeList : public Cacheable, public Vector<FilterMode> |
91 | | { |
92 | | public: |
93 | | typedef Config CacheConfig; |
94 | | typedef String CacheKey; |
95 | | String key; |
96 | | static PosibErr<FilterModeList *> get_new(const String & key, const Config *); |
97 | 711 | bool cache_key_eq(const String & okey) const { |
98 | 711 | return key == okey; |
99 | 711 | } |
100 | | }; |
101 | | |
102 | | class ModeNotifierImpl : public Notifier |
103 | | { |
104 | | private: |
105 | | ModeNotifierImpl(); |
106 | | ModeNotifierImpl(const ModeNotifierImpl &); |
107 | | ModeNotifierImpl & operator= (const ModeNotifierImpl & b); |
108 | | CachePtr<FilterModeList> filter_modes_; |
109 | | public: |
110 | | Config * config; |
111 | | PosibErr<FilterModeList *> get_filter_modes(); |
112 | | |
113 | | ModeNotifierImpl(Config * c) : config(c) |
114 | 1.58k | { |
115 | 1.58k | c->filter_mode_notifier = this; |
116 | 1.58k | } |
117 | | ModeNotifierImpl(const ModeNotifierImpl & other, Config * c) |
118 | | : filter_modes_(other.filter_modes_), config(c) |
119 | 0 | { |
120 | 0 | c->filter_mode_notifier = this; |
121 | 0 | } |
122 | | |
123 | 0 | ModeNotifierImpl * clone(Config * c) const {return new ModeNotifierImpl(*this, c);} |
124 | | |
125 | | PosibErr<void> item_updated(const KeyInfo * ki, ParmStr); |
126 | | PosibErr<void> list_updated(const KeyInfo * ki); |
127 | | |
128 | 1.58k | ~ModeNotifierImpl() {} |
129 | | }; |
130 | | |
131 | | FilterMode::FilterMode(const String & name) |
132 | 5.35k | : name_(name) {} |
133 | | |
134 | 16.0k | PosibErr<bool> FilterMode::addModeExtension(const String & ext, String toMagic) { |
135 | | |
136 | 16.0k | bool extOnly = false; |
137 | | |
138 | 16.0k | if ( ( toMagic == "" ) |
139 | 16.0k | || ( toMagic == "<noregex>" ) |
140 | 16.0k | || ( toMagic == "<nomagic>" ) |
141 | 16.0k | || ( toMagic == "<empty>" ) ) { |
142 | 5.35k | extOnly = true; |
143 | 5.35k | } |
144 | 10.7k | else { |
145 | | |
146 | 10.7k | RET_ON_ERR(FilterMode::MagicString::testMagic(NULL,toMagic,name_)); |
147 | | |
148 | 10.7k | } |
149 | | |
150 | 16.0k | Vector<MagicString>::iterator it; |
151 | | |
152 | 20.0k | for ( it = magicKeys.begin() ; it != magicKeys.end() ; it++ ) { |
153 | 14.7k | if ( ( extOnly |
154 | 14.7k | && ( it->magic() == "" ) ) |
155 | 14.7k | || ( it->magic() == toMagic ) ) { |
156 | 10.7k | *it += ext; |
157 | 10.7k | return true; |
158 | 10.7k | } |
159 | 14.7k | } |
160 | 5.35k | if ( it != magicKeys.end() ) { |
161 | 0 | return false; |
162 | 0 | } |
163 | 5.35k | if ( extOnly ) { |
164 | 1.78k | magicKeys.push_back(MagicString(name_)); |
165 | 1.78k | } |
166 | 3.56k | else { |
167 | 3.56k | magicKeys.push_back(MagicString(toMagic,name_)); |
168 | 3.56k | } |
169 | 7.58k | for ( it = magicKeys.begin() ; it != magicKeys.end() ; it++ ) { |
170 | 7.58k | if ( ( extOnly |
171 | 7.58k | && ( it->magic() == "" ) ) |
172 | 7.58k | || ( it->magic() == toMagic ) ) { |
173 | 5.35k | *it += ext; |
174 | 5.35k | return true; |
175 | 5.35k | } |
176 | 7.58k | } |
177 | 0 | return make_err(mode_extend_expand,name_.str()); |
178 | 5.35k | } |
179 | | |
180 | 0 | PosibErr<bool> FilterMode::remModeExtension(const String & ext, String toMagic) { |
181 | |
|
182 | 0 | bool extOnly = false; |
183 | |
|
184 | 0 | if ( ( toMagic == "" ) |
185 | 0 | || ( toMagic == "<nomagic>" ) |
186 | 0 | || ( toMagic == "<empty>" ) ) { |
187 | 0 | extOnly = true; |
188 | 0 | } |
189 | 0 | else { |
190 | |
|
191 | 0 | PosibErr<bool> pe = FilterMode::MagicString::testMagic(NULL,toMagic,name_); |
192 | |
|
193 | 0 | if ( pe.has_err() ) { |
194 | 0 | return PosibErrBase(pe); |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | 0 | for ( Vector<MagicString>::iterator it = magicKeys.begin() ; |
199 | 0 | it != magicKeys.end() ; it++ ) { |
200 | 0 | if ( ( extOnly |
201 | 0 | && ( it->magic() == "" ) ) |
202 | 0 | || ( it->magic() == toMagic ) ) { |
203 | 0 | *it -= ext; |
204 | 0 | return true; |
205 | 0 | } |
206 | 0 | } |
207 | 0 | return false; |
208 | 0 | } |
209 | | |
210 | 0 | bool FilterMode::lockFileToMode(const String & fileName,FILE * in) { |
211 | |
|
212 | 0 | Vector<unsigned int> extStart; |
213 | 0 | int first_point = fileName.size(); |
214 | |
|
215 | 0 | while ( first_point > 0 ) { |
216 | 0 | while ( ( --first_point >= 0 ) |
217 | 0 | && ( fileName[first_point] != '.' ) ) { |
218 | 0 | } |
219 | 0 | if ( ( first_point >= 0 ) |
220 | 0 | && ( fileName[first_point] == '.' ) ) { |
221 | 0 | extStart.push_back(first_point + 1); |
222 | 0 | } |
223 | 0 | } |
224 | 0 | if ( extStart.size() < 1 ) { |
225 | 0 | return false; |
226 | 0 | } |
227 | | |
228 | 0 | bool closeFile = false; |
229 | |
|
230 | 0 | if ( in == NULL ) { |
231 | 0 | in = fopen(fileName.str(),"rb"); |
232 | 0 | closeFile= true; |
233 | 0 | } |
234 | 0 | for ( Vector<unsigned int>::iterator extSIt = extStart.begin() ; |
235 | 0 | extSIt != extStart.end() ; extSIt ++ ) { |
236 | | |
237 | 0 | String ext(fileName); |
238 | |
|
239 | 0 | ext.erase(0,*extSIt); |
240 | 0 | for ( Vector<MagicString>::iterator it = magicKeys.begin() ; |
241 | 0 | it != magicKeys.end() ; it++ ) { |
242 | 0 | PosibErr<bool> magicMatch = it->matchFile(in,ext); |
243 | 0 | if ( magicMatch |
244 | 0 | || magicMatch.has_err() ) { |
245 | 0 | if ( closeFile ) { |
246 | 0 | fclose ( in ); |
247 | 0 | } |
248 | 0 | if ( magicMatch.has_err() ) { |
249 | 0 | magicMatch.ignore_err(); |
250 | 0 | return false; |
251 | 0 | } |
252 | 0 | return true; |
253 | 0 | } |
254 | 0 | } |
255 | 0 | } |
256 | 0 | if ( closeFile ) { |
257 | 0 | fclose(in); |
258 | 0 | } |
259 | 0 | return false; |
260 | 0 | } |
261 | | |
262 | 37.2k | const String & FilterMode::modeName() const { |
263 | 37.2k | return name_; |
264 | 37.2k | } |
265 | | |
266 | 17.3k | FilterMode::~FilterMode() { |
267 | 17.3k | } |
268 | | |
269 | 0 | bool FilterMode::MagicString::hasExtension(const String & ext) { |
270 | 0 | for ( Vector<String>::iterator it = fileExtensions.begin() ; |
271 | 0 | it != fileExtensions.end() ; it++ ) { |
272 | 0 | if ( *it == ext ) { |
273 | 0 | return true; |
274 | 0 | } |
275 | 0 | } |
276 | 0 | return false; |
277 | 0 | } |
278 | | |
279 | 0 | void FilterMode::MagicString::remExtension(const String & ext) { |
280 | 0 | Vector<String>::iterator it = fileExtensions.begin(); |
281 | 0 | while (it != fileExtensions.end()) { |
282 | 0 | if (*it == ext) { |
283 | 0 | it = fileExtensions.erase(it); |
284 | 0 | } else { |
285 | 0 | it++; |
286 | 0 | } |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | | |
291 | 0 | bool FilterMode::MagicString::matchFile(FILE * in,const String & ext) { |
292 | |
|
293 | 0 | Vector<String>::iterator extIt; |
294 | |
|
295 | 0 | for ( extIt = fileExtensions.begin() ; |
296 | 0 | extIt != fileExtensions.end() ; extIt ++ ) { |
297 | 0 | if ( *extIt == ext ) { |
298 | 0 | break; |
299 | 0 | } |
300 | 0 | } |
301 | 0 | if ( extIt == fileExtensions.end() ) { |
302 | 0 | return false; |
303 | 0 | } |
304 | | |
305 | 0 | PosibErr<bool> pe = testMagic(in,magic_,mode_); |
306 | |
|
307 | 0 | if ( pe.has_err() ) { |
308 | 0 | pe.ignore_err(); |
309 | 0 | return false; |
310 | 0 | } |
311 | 0 | return true; |
312 | 0 | } |
313 | | |
314 | | |
315 | 10.7k | PosibErr<bool> FilterMode::MagicString::testMagic(FILE * seekIn,String & magic, const String & mode) { |
316 | | |
317 | 10.7k | #ifdef USE_POSIX_REGEX |
318 | | |
319 | 10.7k | if ( magic.size() == 0 ) { |
320 | 0 | return true; |
321 | 0 | } |
322 | | |
323 | 10.7k | unsigned int magicFilePosition = 0; |
324 | | |
325 | 21.4k | while ( ( magicFilePosition < magic.size() ) |
326 | 21.4k | && ( magic[magicFilePosition] != ':' ) ) { |
327 | 10.7k | magicFilePosition++; |
328 | 10.7k | } |
329 | | |
330 | 10.7k | String number(magic); |
331 | | |
332 | 10.7k | number.erase(magicFilePosition,magic.size() - magicFilePosition); |
333 | | |
334 | 10.7k | const char * num = number.str(); |
335 | 10.7k | const char * numEnd = num + number.size(); |
336 | 10.7k | const char * endHere = numEnd; |
337 | 10.7k | long position = 0; |
338 | | |
339 | 10.7k | if ( ( number.size() == 0 ) |
340 | 10.7k | || ( (position = strtoi_c(num,&numEnd)) < 0 ) |
341 | 10.7k | || ( numEnd != endHere ) ) { |
342 | 0 | return make_err(file_magic_pos,"",magic.str()); |
343 | 0 | } |
344 | 10.7k | if ( ( magicFilePosition >= magic.size() ) |
345 | 10.7k | || ( ( seekIn != NULL ) |
346 | 10.7k | && ( fseek(seekIn,position,SEEK_SET) < 0 ) ) ) { |
347 | 0 | if ( seekIn != NULL ) { |
348 | 0 | rewind(seekIn); |
349 | 0 | } |
350 | 0 | return false; |
351 | 0 | } |
352 | | |
353 | | //increment magicFilePosition to skip the `:' |
354 | 10.7k | unsigned int seekRangePos = ++ magicFilePosition; |
355 | | |
356 | 31.2k | while ( ( magicFilePosition < magic.size() ) |
357 | 31.2k | && ( magic[magicFilePosition] != ':' ) ) { |
358 | 20.5k | magicFilePosition++; |
359 | 20.5k | } |
360 | | |
361 | 10.7k | String magicRegExp(magic); |
362 | | |
363 | 10.7k | magicRegExp.erase(0,magicFilePosition + 1); |
364 | 10.7k | if ( magicRegExp.size() == 0 ) { |
365 | 0 | if ( seekIn != NULL ) { |
366 | 0 | rewind(seekIn); |
367 | 0 | } |
368 | 0 | return make_err(missing_magic,mode.str(),magic.str()); //no regular expression given |
369 | 0 | } |
370 | | |
371 | 10.7k | number = magic; |
372 | 10.7k | number.erase(magicFilePosition,magic.size() - magicFilePosition); |
373 | 10.7k | number.erase(0,seekRangePos);//already incremented by one see above |
374 | 10.7k | num = (char*)number.str(); |
375 | 10.7k | endHere = numEnd = num + number.size(); |
376 | | |
377 | 10.7k | if ( ( number.size() == 0 ) |
378 | 10.7k | || ( (position = strtoi_c(num,&numEnd)) < 0 ) |
379 | 10.7k | || ( numEnd != endHere ) ) { |
380 | 0 | if ( seekIn != NULL ) { |
381 | 0 | rewind(seekIn); |
382 | 0 | } |
383 | 0 | return make_err(file_magic_range,mode.str(),magic.str());//no magic range given |
384 | 0 | } |
385 | | |
386 | 10.7k | regex_t seekMagic; |
387 | 10.7k | int regsucess = 0; |
388 | | |
389 | 10.7k | if ( (regsucess = regcomp(&seekMagic,magicRegExp.str(), |
390 | 10.7k | REG_NEWLINE|REG_NOSUB|REG_EXTENDED)) ){ |
391 | 0 | if ( seekIn != NULL ) { |
392 | 0 | rewind(seekIn); |
393 | 0 | } |
394 | |
|
395 | 0 | char regError[256]; |
396 | 0 | regerror(regsucess,&seekMagic,®Error[0],256); |
397 | 0 | return make_err(bad_magic,mode.str(),magic.str(),regError); |
398 | 0 | } |
399 | 10.7k | if ( seekIn == NULL ) { |
400 | 10.7k | regfree(&seekMagic); |
401 | 10.7k | return true; |
402 | 10.7k | } |
403 | | |
404 | 0 | char * buffer = new char[(position + 1)]; |
405 | |
|
406 | 0 | if ( buffer == NULL ) { |
407 | 0 | regfree(&seekMagic); |
408 | 0 | rewind(seekIn); |
409 | 0 | return false; |
410 | 0 | } |
411 | 0 | memset(buffer,0,(position + 1)); |
412 | 0 | if ( (position = fread(buffer,1,position,seekIn)) == 0 ) { |
413 | 0 | rewind(seekIn); |
414 | 0 | regfree(&seekMagic); |
415 | 0 | delete[] buffer; |
416 | 0 | return false; |
417 | 0 | } |
418 | 0 | if ( regexec(&seekMagic,buffer,0,NULL,0) ) { |
419 | 0 | delete[] buffer; |
420 | 0 | regfree(&seekMagic); |
421 | 0 | rewind(seekIn); |
422 | 0 | return false; |
423 | 0 | } |
424 | 0 | delete[] buffer; |
425 | 0 | regfree(&seekMagic); |
426 | 0 | rewind(seekIn); |
427 | 0 | return true; |
428 | |
|
429 | | #else |
430 | | |
431 | | return true; |
432 | | |
433 | | #endif |
434 | |
|
435 | 0 | } |
436 | | |
437 | 0 | PosibErr<void> FilterMode::expand(Config * config) { |
438 | |
|
439 | 0 | config->replace("clear-filter",""); |
440 | 0 | for ( Vector<KeyValue>::iterator it = expansion.begin() ; |
441 | 0 | it != expansion.end() ; it++ ) |
442 | 0 | { |
443 | 0 | PosibErr<void> pe = config->replace(it->key, it->value); |
444 | 0 | if (pe.has_err()) return pe.with_file(file_); |
445 | 0 | } |
446 | 0 | return no_err; |
447 | 0 | } |
448 | | |
449 | 5.35k | PosibErr<void> FilterMode::build(FStream & toParse, int line0, const char * fname) { |
450 | | |
451 | 5.35k | String buf; |
452 | 5.35k | DataPair dp; |
453 | | |
454 | 5.35k | file_ = fname; |
455 | | |
456 | 5.35k | dp.line_num = line0; |
457 | | |
458 | 20.0k | while ( getdata_pair(toParse, dp, buf) ) { |
459 | | |
460 | 14.7k | to_lower(dp.key); |
461 | | |
462 | 14.7k | if ( dp.key == "filter" ) { |
463 | | |
464 | 9.81k | to_lower(dp.value); |
465 | 9.81k | expansion.push_back(KeyValue("add-filter", dp.value)); |
466 | | |
467 | 9.81k | } else if ( dp.key == "option" ) { |
468 | | |
469 | 4.90k | split(dp); |
470 | | // FIXME: Add check for empty key |
471 | | |
472 | 4.90k | expansion.push_back(KeyValue(dp.key, dp.value)); |
473 | | |
474 | 4.90k | } else { |
475 | | |
476 | 0 | return make_err(bad_mode_key,dp.key).with_file(fname,dp.line_num); |
477 | 0 | } |
478 | 14.7k | } |
479 | | |
480 | 5.35k | return no_err; |
481 | 5.35k | } |
482 | | |
483 | | static GlobalCache<FilterModeList> filter_modes_cache("filter_modes"); |
484 | | |
485 | | PosibErr<void> set_mode_from_extension (Config * config, ParmString filename, FILE * in) |
486 | 0 | { |
487 | 0 | RET_ON_ERR_SET(static_cast<ModeNotifierImpl *>(config->filter_mode_notifier) |
488 | 0 | ->get_filter_modes(), FilterModeList *, fm); |
489 | | |
490 | 0 | for ( FilterModeList::iterator it = fm->begin(); it != fm->end(); it++ ) |
491 | 0 | { |
492 | 0 | if ( it->lockFileToMode(filename,in) ) { |
493 | 0 | RET_ON_ERR(config->replace("mode", it->modeName().str())); |
494 | 0 | break; |
495 | 0 | } |
496 | 0 | } |
497 | 0 | return no_err; |
498 | 0 | } |
499 | | |
500 | | void activate_filter_modes(Config *config); |
501 | | |
502 | | PosibErr<FilterModeList *> ModeNotifierImpl::get_filter_modes() |
503 | 1.97k | { |
504 | 1.97k | if (!filter_modes_) { |
505 | | //FIXME is filter-path proper for filter mode files ??? |
506 | | // if filter-options-path better ??? |
507 | | // do we need a filter-mode-path ??? |
508 | | // should change to use genetic data-path once implemented |
509 | | // and then search filter-path - KevinA |
510 | 1.72k | String filter_path; |
511 | 1.72k | StringList filter_path_lst; |
512 | 1.72k | config->retrieve_list("filter-path", &filter_path_lst); |
513 | 1.72k | combine_list(filter_path, filter_path_lst); |
514 | 1.72k | RET_ON_ERR(setup(filter_modes_, &filter_modes_cache, config, filter_path)); |
515 | 1.72k | } |
516 | 1.97k | return filter_modes_.get(); |
517 | 1.97k | } |
518 | | |
519 | | |
520 | | PosibErr<void> ModeNotifierImpl::item_updated(const KeyInfo * ki, ParmStr value) |
521 | 15.3k | { |
522 | 15.3k | if ( strcmp(ki->name, "mode") == 0 ) { |
523 | 1.97k | RET_ON_ERR_SET(get_filter_modes(), FilterModeList *, filter_modes); |
524 | 1.97k | for ( Vector<FilterMode>::iterator it = filter_modes->begin() ; |
525 | 9.82k | it != filter_modes->end() ; it++ ) { |
526 | 7.84k | if ( it->modeName() == value ) |
527 | 0 | return it->expand(config); |
528 | 7.84k | } |
529 | 1.97k | return make_err(unknown_mode, value); |
530 | 1.97k | } |
531 | 13.3k | return no_err; |
532 | 15.3k | } |
533 | | |
534 | | PosibErr<void> ModeNotifierImpl::list_updated(const KeyInfo * ki) |
535 | 75.7k | { |
536 | 75.7k | if (strcmp(ki->name, "filter-path") == 0) { |
537 | 2.02k | filter_modes_.reset(0); |
538 | 2.02k | } |
539 | 75.7k | return no_err; |
540 | 75.7k | } |
541 | | |
542 | | PosibErr<FilterModeList *> FilterModeList::get_new(const String & key, |
543 | | const Config *) |
544 | 1.10k | { |
545 | | |
546 | 1.10k | StackPtr<FilterModeList> filter_modes(new FilterModeList); |
547 | 1.10k | filter_modes->key = key; |
548 | 1.10k | StringList mode_path; |
549 | 1.10k | separate_list(key, mode_path); |
550 | | |
551 | 1.10k | PathBrowser els(mode_path, ".amf"); |
552 | | |
553 | 1.10k | String possMode; |
554 | 1.10k | String possModeFile; |
555 | | |
556 | 1.10k | const char * file; |
557 | 6.46k | while ((file = els.next()) != NULL) |
558 | 5.35k | { |
559 | 5.35k | possModeFile = file; |
560 | 5.35k | possMode.assign(possModeFile.str(), possModeFile.size() - 4); |
561 | | |
562 | 5.35k | unsigned pathPos = 0; |
563 | 5.35k | unsigned pathPosEnd = 0; |
564 | | |
565 | 32.1k | while ( ( (pathPosEnd = possMode.find('/',pathPos)) < possMode.size() ) |
566 | 32.1k | && ( pathPosEnd >= 0 ) ) { |
567 | 26.7k | pathPos = pathPosEnd + 1; |
568 | 26.7k | } |
569 | 5.35k | possMode.erase(0,pathPos); |
570 | 5.35k | to_lower(possMode.mstr()); |
571 | | |
572 | 5.35k | Vector<FilterMode>::iterator fmIt = filter_modes->begin(); |
573 | | |
574 | 5.35k | for ( fmIt = filter_modes->begin() ; |
575 | 34.7k | fmIt != filter_modes->end() ; fmIt++ ) { |
576 | 29.4k | if ( (*fmIt).modeName() == possMode ) { |
577 | 0 | break; |
578 | 0 | } |
579 | 29.4k | } |
580 | 5.35k | if ( fmIt != filter_modes->end() ) { |
581 | 0 | continue; |
582 | 0 | } |
583 | | |
584 | 5.35k | FStream toParse; |
585 | | |
586 | 5.35k | RET_ON_ERR(toParse.open(possModeFile.str(),"rb")); |
587 | | |
588 | 5.35k | String buf; |
589 | 5.35k | DataPair dp; |
590 | | |
591 | 5.35k | bool get_sucess = getdata_pair(toParse, dp, buf); |
592 | | |
593 | 5.35k | to_lower(dp.key); |
594 | 5.35k | to_lower(dp.value); |
595 | 5.35k | if ( !get_sucess |
596 | 5.35k | || ( dp.key != "mode" ) |
597 | 5.35k | || ( dp.value != possMode.str() ) ) |
598 | 0 | return make_err(expect_mode_key,"mode").with_file(possModeFile, dp.line_num); |
599 | | |
600 | 5.35k | get_sucess = getdata_pair(toParse, dp, buf); |
601 | 5.35k | to_lower(dp.key); |
602 | 5.35k | if ( !get_sucess |
603 | 5.35k | || ( dp.key != "aspell" ) |
604 | 5.35k | || ( dp.value == NULL ) |
605 | 5.35k | || ( *(dp.value) == '\0' ) ) |
606 | 0 | return make_err(mode_version_requirement).with_file(possModeFile, dp.line_num); |
607 | | |
608 | | #ifdef FILTER_VERSION_CONTROL |
609 | | PosibErr<void> peb = check_version(dp.value.str); |
610 | | if (peb.has_err()) return peb.with_file(possModeFile, dp.line_num); |
611 | | #endif |
612 | | |
613 | 5.35k | FilterMode collect(possMode); |
614 | | |
615 | 10.7k | while ( getdata_pair(toParse,dp,buf) ) { |
616 | 10.7k | to_lower(dp.key); |
617 | 10.7k | if ( ( dp.key == "desc" ) |
618 | 10.7k | || ( dp.key == "description" ) ) |
619 | 5.35k | { |
620 | 5.35k | unescape(dp.value); |
621 | 5.35k | collect.setDescription(dp.value); |
622 | 5.35k | break; |
623 | 5.35k | } |
624 | 5.35k | if ( dp.key == "magic" ) { |
625 | | |
626 | 5.35k | char * regbegin = dp.value; |
627 | | |
628 | 5.35k | while ( regbegin |
629 | 5.35k | && ( *regbegin != '/' ) ) { |
630 | 0 | regbegin++; |
631 | 0 | } |
632 | 5.35k | if ( ( regbegin == NULL ) |
633 | 5.35k | || ( *regbegin == '\0' ) |
634 | 5.35k | || ( *(++regbegin) == '\0' ) ) |
635 | 0 | return make_err(missing_magic_expression).with_file(possModeFile, dp.line_num); |
636 | | |
637 | 5.35k | char * regend = regbegin; |
638 | 5.35k | bool prevslash = false; |
639 | | |
640 | 165k | while ( regend |
641 | 165k | && ( *regend != '\0' ) |
642 | 165k | && ( prevslash |
643 | 165k | || ( * regend != '/' ) ) ) { |
644 | 160k | if ( *regend == '\\' ) { |
645 | 11.5k | prevslash = !prevslash; |
646 | 11.5k | } |
647 | 148k | else { |
648 | 148k | prevslash = false; |
649 | 148k | } |
650 | 160k | regend ++ ; |
651 | 160k | } |
652 | 5.35k | if ( regend == regbegin ) |
653 | 0 | return make_err(missing_magic_expression).with_file(possModeFile, dp.line_num); |
654 | | |
655 | 5.35k | char swap = *regend; |
656 | | |
657 | 5.35k | *regend = '\0'; |
658 | | |
659 | 5.35k | String magic(regbegin); |
660 | | |
661 | 5.35k | *regend = swap; |
662 | | |
663 | 5.35k | unsigned int extCount = 0; |
664 | | |
665 | 21.4k | while ( *regend != '\0' ) { |
666 | 16.0k | regend ++; |
667 | 16.0k | extCount ++; |
668 | 16.0k | regbegin = regend; |
669 | 57.5k | while ( ( *regend != '/' ) |
670 | 57.5k | && ( *regend != '\0' ) ) { |
671 | 41.4k | regend++; |
672 | 41.4k | } |
673 | 16.0k | if ( regend == regbegin ) |
674 | 0 | { |
675 | 0 | char charCount[64]; |
676 | 0 | sprintf(&charCount[0],"%li",(long)(regbegin - (char *)dp.value)); |
677 | 0 | return make_err(empty_file_ext,charCount).with_file(possModeFile,dp.line_num); |
678 | 0 | } |
679 | | |
680 | 16.0k | bool remove = false; |
681 | 16.0k | bool add = true; |
682 | | |
683 | 16.0k | if ( *regbegin == '+' ) { |
684 | 0 | regbegin++; |
685 | 0 | } |
686 | 16.0k | else if ( *regbegin == '-' ) { |
687 | 0 | add = false; |
688 | 0 | remove = true; |
689 | 0 | regbegin++; |
690 | 0 | } |
691 | 16.0k | if ( regend == regbegin ) |
692 | 0 | { |
693 | 0 | char charCount[64]; |
694 | 0 | sprintf(&charCount[0],"%li",(long)(regbegin - (char *)dp.value)); |
695 | 0 | return make_err(empty_file_ext,charCount).with_file(possModeFile,dp.line_num); |
696 | 0 | } |
697 | 16.0k | swap = *regend; |
698 | 16.0k | *regend = '\0'; |
699 | | |
700 | 16.0k | String ext(regbegin); |
701 | | |
702 | 16.0k | *regend = swap; |
703 | | |
704 | | // partially unescape magic |
705 | | |
706 | 16.0k | char * dest = magic.mstr(); |
707 | 16.0k | const char * src = magic.mstr(); |
708 | 357k | while (*src) { |
709 | 341k | if ((*src == '\\' && src[1] == '/') || src[1] == '#') |
710 | 2.23k | ++src; |
711 | 341k | *dest++ = *src++; |
712 | 341k | } |
713 | 16.0k | magic.resize(dest - magic.mstr()); |
714 | | |
715 | 16.0k | PosibErr<bool> pe; |
716 | | |
717 | 16.0k | if ( remove ) |
718 | 0 | pe = collect.remModeExtension(ext,magic); |
719 | 16.0k | else |
720 | 16.0k | pe = collect.addModeExtension(ext,magic); |
721 | | |
722 | 16.0k | if ( pe.has_err() ) |
723 | 0 | return pe.with_file(possModeFile, dp.line_num); |
724 | 16.0k | } |
725 | | |
726 | 5.35k | if (extCount > 0 ) continue; |
727 | | |
728 | 0 | char charCount[64]; |
729 | 0 | sprintf(&charCount[0],"%lu",(unsigned long)strlen((char *)dp.value)); |
730 | 0 | return make_err(empty_file_ext,charCount).with_file(possModeFile,dp.line_num); |
731 | 5.35k | } |
732 | | |
733 | 0 | return make_err(expect_mode_key,"ext[tension]/magic/desc[ription]/rel[ation]") |
734 | 0 | .with_file(possModeFile,dp.line_num); |
735 | | |
736 | 5.35k | }//while getdata_pair |
737 | | |
738 | 5.35k | RET_ON_ERR(collect.build(toParse,dp.line_num,possModeFile.str())); |
739 | | |
740 | 5.35k | filter_modes->push_back(collect); |
741 | 5.35k | } |
742 | 1.10k | return filter_modes.release(); |
743 | 1.10k | } |
744 | | |
745 | | void activate_filter_modes(Config *config) |
746 | 1.58k | { |
747 | 1.58k | config->add_notifier(new ModeNotifierImpl(config)); |
748 | 1.58k | } |
749 | | |
750 | | class FilterModesEnumeration : public StringPairEnumeration |
751 | | { |
752 | | public: |
753 | | typedef Vector<FilterMode>::const_iterator Itr; |
754 | | private: |
755 | | Itr it; |
756 | | Itr end; |
757 | | public: |
758 | 0 | FilterModesEnumeration(Itr i, Itr e) : it(i), end(e) {} |
759 | 0 | bool at_end() const {return it == end;} |
760 | | StringPair next() |
761 | 0 | { |
762 | 0 | if (it == end) return StringPair(); |
763 | 0 | StringPair res = StringPair(it->modeName().str(), it->getDescription().str()); |
764 | 0 | ++it; |
765 | 0 | return res; |
766 | 0 | } |
767 | 0 | StringPairEnumeration * clone() const {return new FilterModesEnumeration(*this);} |
768 | | void assign(const StringPairEnumeration * other0) |
769 | 0 | { |
770 | 0 | const FilterModesEnumeration * other = (const FilterModesEnumeration *)other0; |
771 | 0 | *this = *other; |
772 | 0 | } |
773 | | }; |
774 | | |
775 | | PosibErr<StringPairEnumeration *> available_filter_modes(Config * config) |
776 | 0 | { |
777 | 0 | RET_ON_ERR_SET(static_cast<ModeNotifierImpl *>(config->filter_mode_notifier) |
778 | 0 | ->get_filter_modes(), FilterModeList *, fm); |
779 | 0 | return new FilterModesEnumeration(fm->begin(), fm->end()); |
780 | 0 | } |
781 | | |
782 | | } |
783 | | |