/src/aspell/common/info.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // This file is part of The New Aspell |
2 | | // Copyright (C) 2001 by Kevin Atkinson under the GNU LGPL license |
3 | | // version 2.0 or 2.1. You should have received a copy of the LGPL |
4 | | // license along with this library if you did not you can find |
5 | | // it at http://www.gnu.org/. |
6 | | |
7 | | #include <stdlib.h> |
8 | | #include <assert.h> |
9 | | #include <string.h> |
10 | | #include <ctype.h> |
11 | | #include <dirent.h> |
12 | | |
13 | | // POSIX includes |
14 | | #ifdef __bsdi__ |
15 | | /* BSDi defines u_intXX_t types in machine/types.h */ |
16 | | #include <machine/types.h> |
17 | | #endif |
18 | | #ifdef WIN32 |
19 | | # include <windows.h> |
20 | | # include <winbase.h> |
21 | | #endif |
22 | | |
23 | | #include "iostream.hpp" |
24 | | |
25 | | #include "asc_ctype.hpp" |
26 | | #include "config.hpp" |
27 | | #include "errors.hpp" |
28 | | #include "fstream.hpp" |
29 | | #include "getdata.hpp" |
30 | | #include "info.hpp" |
31 | | #include "itemize.hpp" |
32 | | #include "string.hpp" |
33 | | #include "string_list.hpp" |
34 | | #include "vector.hpp" |
35 | | #include "stack_ptr.hpp" |
36 | | #include "strtonum.hpp" |
37 | | #include "lock.hpp" |
38 | | #include "string_map.hpp" |
39 | | |
40 | | #include "gettext.h" |
41 | | |
42 | | namespace acommon { |
43 | | |
44 | | class Dir { |
45 | | DIR * d_; |
46 | | Dir(const Dir &); |
47 | | Dir & operator=(const Dir &); |
48 | | public: |
49 | 51.7k | operator DIR * () {return d_;} |
50 | 306 | Dir(DIR * d) : d_(d) {} |
51 | 306 | ~Dir() {if (d_) closedir(d_);} |
52 | | }; |
53 | | |
54 | | ///////////////////////////////////////////////////////////////// |
55 | | // |
56 | | // Lists of Info Lists |
57 | | // |
58 | | |
59 | | static void get_data_dirs (Config *, |
60 | | StringList &); |
61 | | |
62 | | struct DictExt |
63 | | { |
64 | | static const size_t max_ext_size = 15; |
65 | | const ModuleInfo * module; |
66 | | size_t ext_size; |
67 | | char ext[max_ext_size + 1]; |
68 | | DictExt(ModuleInfo * m, const char * e); |
69 | | }; |
70 | | |
71 | | typedef Vector<DictExt> DictExtList; |
72 | | |
73 | | struct MDInfoListAll |
74 | | // this is in an invalid state if some of the lists |
75 | | // has data but others don't |
76 | | { |
77 | | StringList key; |
78 | | StringList for_dirs; |
79 | | ModuleInfoList module_info_list; |
80 | | StringList dict_dirs; |
81 | | DictExtList dict_exts; |
82 | | DictInfoList dict_info_list; |
83 | | StringMap dict_aliases; |
84 | | void clear(); |
85 | | PosibErr<void> fill(Config *, StringList &); |
86 | 2.25k | bool has_data() const {return module_info_list.head_ != 0;} |
87 | | void fill_helper_lists(const StringList &); |
88 | | PosibErr<void> fill_dict_aliases(Config *); |
89 | | }; |
90 | | |
91 | | class MDInfoListofLists |
92 | | { |
93 | | Mutex lock; |
94 | | |
95 | | MDInfoListAll * data; |
96 | | |
97 | | int offset; |
98 | | int size; |
99 | | |
100 | 4.50k | int valid_pos(int pos) {return offset <= pos && pos < size + offset;} |
101 | | |
102 | | void clear(Config * c); |
103 | | int find(const StringList &); |
104 | | |
105 | | public: |
106 | | |
107 | | MDInfoListofLists(); |
108 | | ~MDInfoListofLists(); |
109 | | |
110 | | PosibErr<const MDInfoListAll *> get_lists(Config * c); |
111 | | |
112 | 0 | void flush() {} // unimplemented |
113 | | }; |
114 | | |
115 | | static MDInfoListofLists md_info_list_of_lists; |
116 | | |
117 | | ///////////////////////////////////////////////////////////////// |
118 | | // |
119 | | // Utility functions declaration |
120 | | // |
121 | | |
122 | | static const char * strnchr(const char * i, char c, unsigned int size); |
123 | | static const char * strnrchr(const char * stop, char c, unsigned int size); |
124 | | |
125 | | ///////////////////////////////////////////////////////////////// |
126 | | // |
127 | | // Built in modules |
128 | | // |
129 | | |
130 | | struct ModuleInfoDefItem { |
131 | | const char * name; |
132 | | const char * data; |
133 | | }; |
134 | | |
135 | | static const ModuleInfoDefItem module_info_list_def_list[] = { |
136 | | {"default", |
137 | | "order-num 0.50;" |
138 | | "dict-exts .multi,.alias"} |
139 | | }; |
140 | | |
141 | | ///////////////////////////////////////////////////////////////// |
142 | | // |
143 | | // ModuleInfoList Impl |
144 | | // |
145 | | |
146 | | struct ModuleInfoNode |
147 | | { |
148 | | ModuleInfo c_struct; |
149 | | ModuleInfoNode * next; |
150 | 153 | ModuleInfoNode(ModuleInfoNode * n = 0) : next(n) {} |
151 | | String name; |
152 | | String lib_dir; |
153 | | StringList dict_exts; |
154 | | StringList dict_dirs; |
155 | | }; |
156 | | |
157 | | void ModuleInfoList::clear() |
158 | 2 | { |
159 | 2 | while (head_ != 0) { |
160 | 0 | ModuleInfoNode * to_del = head_; |
161 | 0 | head_ = head_->next; |
162 | 0 | delete to_del; |
163 | 0 | } |
164 | 2 | } |
165 | | |
166 | | PosibErr<void> ModuleInfoList::fill(MDInfoListAll & list_all, |
167 | | Config * config) |
168 | 153 | { |
169 | 153 | const ModuleInfoDefItem * i = module_info_list_def_list; |
170 | 153 | const ModuleInfoDefItem * end = module_info_list_def_list |
171 | 153 | + sizeof(module_info_list_def_list)/sizeof(ModuleInfoDefItem); |
172 | 306 | for (; i != end; ++i) |
173 | 153 | { |
174 | 153 | StringIStream in(i->data); |
175 | 153 | proc_info(list_all, config, i->name, strlen(i->name), in); |
176 | 153 | } |
177 | | |
178 | 153 | StringListEnumeration els = list_all.for_dirs.elements_obj(); |
179 | 153 | const char * dir; |
180 | 306 | while ( (dir = els.next()) != 0) { |
181 | 153 | Dir d(opendir(dir)); |
182 | 153 | if (d==0) continue; |
183 | | |
184 | 153 | struct dirent * entry; |
185 | 25.7k | while ( (entry = readdir(d)) != 0) { |
186 | 25.5k | const char * name = entry->d_name; |
187 | 25.5k | const char * dot_loc = strrchr(name, '.'); |
188 | 25.5k | unsigned int name_size = dot_loc == 0 ? strlen(name) : dot_loc - name; |
189 | | |
190 | | // check if it ends in suffix |
191 | 25.5k | if (strcmp(name + name_size, ".asmi") != 0) |
192 | 25.5k | continue; |
193 | | |
194 | 0 | String path; |
195 | 0 | path += dir; |
196 | 0 | path += '/'; |
197 | 0 | path += name; |
198 | 0 | FStream in; |
199 | 0 | RET_ON_ERR(in.open(path, "r")); |
200 | 0 | RET_ON_ERR(proc_info(list_all, config, name, name_size, in)); |
201 | 0 | } |
202 | 153 | } |
203 | 153 | return no_err; |
204 | 153 | } |
205 | | |
206 | | PosibErr<void> ModuleInfoList::proc_info(MDInfoListAll &, |
207 | | Config * config, |
208 | | const char * name, |
209 | | unsigned int name_size, |
210 | | IStream & in) |
211 | 153 | { |
212 | 153 | ModuleInfoNode * * prev = &head_; |
213 | 153 | ModuleInfoNode * to_add = new ModuleInfoNode(); |
214 | 153 | to_add->c_struct.name = 0; |
215 | 153 | to_add->c_struct.order_num = -1; |
216 | 153 | to_add->c_struct.lib_dir = 0; |
217 | 153 | to_add->c_struct.dict_dirs = 0; |
218 | | |
219 | 153 | to_add->name.assign(name, name_size); |
220 | 153 | to_add->c_struct.name = to_add->name.c_str(); |
221 | | |
222 | 153 | PosibErr<void> err; |
223 | | |
224 | 153 | String buf; DataPair d; |
225 | 459 | while (getdata_pair(in, d, buf)) { |
226 | 306 | if (d.key == "order-num") { |
227 | 153 | to_add->c_struct.order_num = strtod_c(d.value.str, NULL); |
228 | 153 | if (!(0 < to_add->c_struct.order_num && |
229 | 153 | to_add->c_struct.order_num < 1)) |
230 | 0 | { |
231 | 0 | err.prim_err(bad_value, d.key, d.value, |
232 | 0 | _("a number between 0 and 1")); |
233 | 0 | goto RETURN_ERROR; |
234 | 0 | } |
235 | 153 | } else if (d.key == "lib-dir") { |
236 | 0 | to_add->lib_dir = d.value.str; |
237 | 0 | to_add->c_struct.lib_dir = to_add->lib_dir.c_str(); |
238 | 153 | } else if (d.key == "dict-dir" || d.key == "dict-dirs") { |
239 | 0 | to_add->c_struct.dict_dirs = &(to_add->dict_dirs); |
240 | 0 | itemize(d.value, to_add->dict_dirs); |
241 | 153 | } else if (d.key == "dict-exts") { |
242 | 153 | to_add->c_struct.dict_dirs = &(to_add->dict_exts); |
243 | 153 | itemize(d.value, to_add->dict_exts); |
244 | 153 | } else { |
245 | 0 | err.prim_err(unknown_key, d.key); |
246 | 0 | goto RETURN_ERROR; |
247 | 0 | } |
248 | 306 | } |
249 | | |
250 | 153 | while (*prev != 0 && |
251 | 153 | (*prev)->c_struct.order_num < to_add->c_struct.order_num) |
252 | 0 | prev = &(*prev)->next; |
253 | 153 | to_add->next = *prev; |
254 | 153 | *prev = to_add; |
255 | 153 | return err; |
256 | | |
257 | 0 | RETURN_ERROR: |
258 | 0 | delete to_add; |
259 | 0 | return err; |
260 | 153 | } |
261 | | |
262 | | ModuleInfoNode * ModuleInfoList::find(const char * to_find, |
263 | | unsigned int to_find_len) |
264 | 0 | { |
265 | 0 | for (ModuleInfoNode * n = head_; |
266 | 0 | n != 0; |
267 | 0 | n = n->next) |
268 | 0 | { |
269 | 0 | if (n->name.size() == to_find_len |
270 | 0 | && strncmp(n->name.c_str(), to_find, to_find_len) == 0) return n; |
271 | 0 | } |
272 | 0 | return 0; |
273 | 0 | } |
274 | | |
275 | | ///////////////////////////////////////////////////////////////// |
276 | | // |
277 | | // DictInfoList Impl |
278 | | // |
279 | | |
280 | | struct DictInfoNode |
281 | | { |
282 | | DictInfo c_struct; |
283 | | DictInfoNode * next; |
284 | 34.7k | DictInfoNode(DictInfoNode * n = 0) : next(n) {} |
285 | | String name; |
286 | | String code; |
287 | | String variety; |
288 | | String size_str; |
289 | | String info_file; |
290 | | bool direct; |
291 | | }; |
292 | | |
293 | | bool operator< (const DictInfoNode & r, const DictInfoNode & l); |
294 | | |
295 | | void DictInfoList::clear() |
296 | 2 | { |
297 | 2 | while (head_ != 0) { |
298 | 0 | DictInfoNode * to_del = head_; |
299 | 0 | head_ = head_->next; |
300 | 0 | delete to_del; |
301 | 0 | } |
302 | 2 | } |
303 | | |
304 | | const DictExt * find_dict_ext(const DictExtList & l, ParmStr name) |
305 | 50.0k | { |
306 | 50.0k | DictExtList::const_iterator i = l.begin(); |
307 | 50.0k | DictExtList::const_iterator end = l.end(); |
308 | 160k | for (; i != end; ++i) |
309 | 145k | { |
310 | 145k | if (i->ext_size <= name.size() |
311 | 145k | && strncmp(name + (name.size() - i->ext_size), |
312 | 143k | i->ext, i->ext_size) == 0) |
313 | 34.7k | break; |
314 | 145k | } |
315 | | |
316 | 50.0k | if (i == end) // does not end in one of the extensions in list |
317 | 15.3k | return 0; |
318 | 34.7k | else |
319 | 34.7k | return &*i; |
320 | 50.0k | } |
321 | | |
322 | | |
323 | | PosibErr<void> DictInfoList::fill(MDInfoListAll & list_all, |
324 | | Config * config) |
325 | 153 | { |
326 | 153 | StringList aliases; |
327 | 153 | config->retrieve_list("dict-alias", &aliases); |
328 | 153 | StringListEnumeration els = aliases.elements_obj(); |
329 | 153 | const char * str; |
330 | 24.6k | while ( (str = els.next()) != 0) { |
331 | 24.5k | const char * end = strchr(str, ' '); |
332 | 24.5k | assert(end != 0); // FIXME: Return error |
333 | 0 | String name(str, end - str); |
334 | 24.5k | RET_ON_ERR(proc_file(list_all, config, |
335 | 24.5k | 0, name.str(), name.size(), |
336 | 24.5k | find_dict_ext(list_all.dict_exts, ".alias")->module)); |
337 | 24.5k | } |
338 | | |
339 | 153 | els = list_all.dict_dirs.elements_obj(); |
340 | 153 | const char * dir; |
341 | 306 | while ( (dir = els.next()) != 0) { |
342 | 153 | Dir d(opendir(dir)); |
343 | 153 | if (d==0) continue; |
344 | | |
345 | 153 | struct dirent * entry; |
346 | 25.7k | while ( (entry = readdir(d)) != 0) { |
347 | 25.5k | const char * name = entry->d_name; |
348 | 25.5k | unsigned int name_size = strlen(name); |
349 | | |
350 | 25.5k | const DictExt * i = find_dict_ext(list_all.dict_exts, |
351 | 25.5k | ParmString(name, name_size)); |
352 | 25.5k | if (i == 0) // does not end in one of the extensions in list |
353 | 15.3k | continue; |
354 | | |
355 | 10.2k | name_size -= i->ext_size; |
356 | | |
357 | 10.2k | RET_ON_ERR(proc_file(list_all, config, |
358 | 10.2k | dir, name, name_size, i->module)); |
359 | 10.2k | } |
360 | 153 | } |
361 | 153 | return no_err; |
362 | 153 | } |
363 | | |
364 | | PosibErr<void> DictInfoList::proc_file(MDInfoListAll & list_all, |
365 | | Config * config, |
366 | | const char * dir, |
367 | | const char * name, |
368 | | unsigned int name_size, |
369 | | const ModuleInfo * module) |
370 | 34.7k | { |
371 | 34.7k | DictInfoNode * * prev = &head_; |
372 | 34.7k | StackPtr<DictInfoNode> to_add(new DictInfoNode()); |
373 | 34.7k | const char * p0; |
374 | 34.7k | const char * p1; |
375 | 34.7k | const char * p2; |
376 | 34.7k | p0 = strnchr(name, '-', name_size); |
377 | 34.7k | if (!module) |
378 | 0 | p2 = strnrchr(name, '-', name_size); |
379 | 34.7k | else |
380 | 34.7k | p2 = name + name_size; |
381 | 34.7k | if (p0 == 0) |
382 | 25.6k | p0 = p2; |
383 | 34.7k | p1 = p2; |
384 | 34.7k | if (p0 + 2 < p1 && asc_isdigit(p1[-1]) && asc_isdigit(p1[-2]) && p1[-3] == '-') |
385 | 21 | p1 -= 2; |
386 | | |
387 | 34.7k | to_add->name.assign(name, p2-name); |
388 | 34.7k | to_add->c_struct.name = to_add->name.c_str(); |
389 | | |
390 | 34.7k | to_add->code.assign(name, p0-name); |
391 | 34.7k | to_add->c_struct.code = to_add->code.c_str(); |
392 | | |
393 | | // check if the code is in a valid form and normalize entry. |
394 | | // If its not in a valid form, then ignore this entry |
395 | | |
396 | 34.7k | if (to_add->code.size() >= 2 |
397 | 34.7k | && asc_isalpha(to_add->code[0]) && asc_isalpha(to_add->code[1])) |
398 | 28.7k | { |
399 | 28.7k | unsigned s = strcspn(to_add->code.str(), "_"); |
400 | 28.7k | if (s > 3) return no_err; |
401 | 22.1k | unsigned i = 0; |
402 | 70.7k | for (; i != s; ++i) |
403 | 48.6k | to_add->name[i] = to_add->code[i] = asc_tolower(to_add->code[i]); |
404 | 22.1k | i++; |
405 | 32.4k | for (; i < to_add->code.size(); ++i) |
406 | 10.3k | to_add->name[i] = to_add->code[i] = asc_toupper(to_add->code[i]); |
407 | 22.1k | } else { |
408 | 6.04k | return no_err; |
409 | 6.04k | } |
410 | | |
411 | | // Need to do it here as module is about to get a value |
412 | | // if it is null |
413 | 22.1k | to_add->direct = module == 0 ? false : true; |
414 | | |
415 | 22.1k | if (!module) { |
416 | 0 | assert(p2 != 0); //FIXME: return error |
417 | 0 | ModuleInfoNode * mod |
418 | 0 | = list_all.module_info_list.find(p2+1, name_size - (p2+1-name)); |
419 | | //FIXME: Check for null and return an error on an unknown module |
420 | 0 | module = &(mod->c_struct); |
421 | 0 | } |
422 | 0 | to_add->c_struct.module = module; |
423 | | |
424 | 22.1k | if (p0 + 1 < p1) |
425 | 4.56k | to_add->variety.assign(p0+1, p1 - p0 - 1); |
426 | 22.1k | to_add->c_struct.variety = to_add->variety.c_str(); |
427 | | |
428 | 22.1k | if (p1 != p2) |
429 | 21 | to_add->size_str.assign(p1, 2); |
430 | 22.0k | else |
431 | 22.0k | to_add->size_str = "60"; |
432 | 22.1k | to_add->c_struct.size_str = to_add->size_str.c_str(); |
433 | 22.1k | to_add->c_struct.size = atoi(to_add->c_struct.size_str); |
434 | | |
435 | 22.1k | if (dir) { |
436 | 5.04k | to_add->info_file = dir; |
437 | 5.04k | to_add->info_file += '/'; |
438 | 5.04k | } |
439 | 22.1k | to_add->info_file += name; |
440 | | |
441 | 891k | while (*prev != 0 && *(DictInfoNode *)*prev < *to_add) |
442 | 869k | prev = &(*prev)->next; |
443 | 22.1k | to_add->next = *prev; |
444 | 22.1k | *prev = to_add.release(); |
445 | | |
446 | 22.1k | return no_err; |
447 | 34.7k | } |
448 | | |
449 | | bool operator< (const DictInfoNode & r, const DictInfoNode & l) |
450 | 890k | { |
451 | 890k | const DictInfo & rhs = r.c_struct; |
452 | 890k | const DictInfo & lhs = l.c_struct; |
453 | 890k | int res = strcmp(rhs.code, lhs.code); |
454 | 890k | if (res < 0) return true; |
455 | 81.2k | if (res > 0) return false; |
456 | 75.7k | res = strcmp(rhs.variety,lhs.variety); |
457 | 75.7k | if (res < 0) return true; |
458 | 15.7k | if (res > 0) return false; |
459 | 12.8k | if (rhs.size < lhs.size) return true; |
460 | 12.8k | if (rhs.size > lhs.size) return false; |
461 | 12.8k | res = strcmp(rhs.module->name,lhs.module->name); |
462 | 12.8k | if (res < 0) return true; |
463 | 12.8k | return false; |
464 | 12.8k | } |
465 | | |
466 | | PosibErr<void> get_dict_file_name(const DictInfo * mi, |
467 | | String & main_wl, String & flags) |
468 | 737 | { |
469 | 737 | const DictInfoNode * node = reinterpret_cast<const DictInfoNode *>(mi); |
470 | 737 | if (node->direct) { |
471 | 737 | main_wl = node->info_file; |
472 | 737 | flags = ""; |
473 | 737 | return no_err; |
474 | 737 | } else { |
475 | 0 | FStream f; |
476 | 0 | RET_ON_ERR(f.open(node->info_file, "r")); |
477 | 0 | String buf; DataPair dp; |
478 | 0 | bool res = getdata_pair(f, dp, buf); |
479 | 0 | main_wl = dp.key; flags = dp.value; |
480 | 0 | f.close(); |
481 | 0 | if (!res) |
482 | 0 | return make_err(bad_file_format, node->info_file, ""); |
483 | 0 | return no_err; |
484 | 0 | } |
485 | 737 | } |
486 | | |
487 | | ///////////////////////////////////////////////////////////////// |
488 | | // |
489 | | // Lists of Info Lists Impl |
490 | | // |
491 | | |
492 | | void get_data_dirs (Config * config, |
493 | | StringList & lst) |
494 | 760 | { |
495 | 760 | lst.clear(); |
496 | 760 | lst.add(config->retrieve("data-dir")); |
497 | 760 | lst.add(config->retrieve("dict-dir")); |
498 | 760 | } |
499 | | |
500 | | DictExt::DictExt(ModuleInfo * m, const char * e) |
501 | 459 | { |
502 | 459 | module = m; |
503 | 459 | ext_size = strlen(e); |
504 | 459 | assert(ext_size <= max_ext_size); |
505 | 0 | memcpy(ext, e, ext_size + 1); |
506 | 459 | } |
507 | | |
508 | | void MDInfoListAll::clear() |
509 | 2 | { |
510 | 2 | module_info_list.clear(); |
511 | 2 | dict_dirs.clear(); |
512 | 2 | dict_exts.clear(); |
513 | 2 | dict_info_list.clear(); |
514 | 2 | } |
515 | | |
516 | | PosibErr<void> MDInfoListAll::fill(Config * c, |
517 | | StringList & dirs) |
518 | 155 | { |
519 | 155 | PosibErr<void> err; |
520 | | |
521 | 155 | err = fill_dict_aliases(c); |
522 | 155 | if (err.has_err()) goto RETURN_ERROR; |
523 | | |
524 | 153 | for_dirs = dirs; |
525 | 153 | err = module_info_list.fill(*this, c); |
526 | 153 | if (err.has_err()) goto RETURN_ERROR; |
527 | | |
528 | 153 | fill_helper_lists(dirs); |
529 | 153 | err = dict_info_list.fill(*this, c); |
530 | 153 | if (err.has_err()) goto RETURN_ERROR; |
531 | | |
532 | 153 | return err; |
533 | | |
534 | 2 | RETURN_ERROR: |
535 | 2 | clear(); |
536 | 2 | return err; |
537 | 153 | } |
538 | | |
539 | | void MDInfoListAll::fill_helper_lists(const StringList & def_dirs) |
540 | 153 | { |
541 | 153 | dict_dirs = def_dirs; |
542 | 153 | dict_exts.append(DictExt(0, ".awli")); |
543 | | |
544 | 306 | for (ModuleInfoNode * n = module_info_list.head_; n != 0; n = n->next) |
545 | 153 | { |
546 | 153 | { |
547 | 153 | StringListEnumeration e = n->dict_dirs.elements_obj(); |
548 | 153 | const char * item; |
549 | 153 | while ( (item = e.next()) != 0 ) |
550 | 0 | dict_dirs.add(item); |
551 | 153 | }{ |
552 | 153 | StringListEnumeration e = n->dict_exts.elements_obj(); |
553 | 153 | const char * item; |
554 | 459 | while ( (item = e.next()) != 0 ) |
555 | 306 | dict_exts.append(DictExt(&n->c_struct, item)); |
556 | 153 | } |
557 | 153 | } |
558 | 153 | } |
559 | | |
560 | | PosibErr<void> MDInfoListAll::fill_dict_aliases(Config * c) |
561 | 155 | { |
562 | 155 | StringList aliases; |
563 | 155 | c->retrieve_list("dict-alias", &aliases); |
564 | 155 | StringListEnumeration els = aliases.elements_obj(); |
565 | 155 | const char * str; |
566 | 24.6k | while ( (str = els.next()) != 0) { |
567 | 24.5k | const char * end = strchr(str, ' '); |
568 | 24.5k | if (!end) return make_err(bad_value, "dict-alias", str, |
569 | 2 | _("in the form \"<name> <value>\"")); |
570 | 24.5k | String name(str, end - str); |
571 | 50.9k | while (asc_isspace(*end)) ++end; |
572 | 24.5k | dict_aliases.insert(name.str(), end); |
573 | 24.5k | } |
574 | 153 | return no_err; |
575 | 155 | } |
576 | | |
577 | | |
578 | | MDInfoListofLists::MDInfoListofLists() |
579 | | : data(0), offset(0), size(0) |
580 | 2 | { |
581 | 2 | } |
582 | | |
583 | 0 | MDInfoListofLists::~MDInfoListofLists() { |
584 | 0 | for (int i = offset; i != offset + size; ++i) |
585 | 0 | data[i].clear(); |
586 | 0 | delete[] data; |
587 | 0 | } |
588 | | |
589 | | void MDInfoListofLists::clear(Config * c) |
590 | 0 | { |
591 | 0 | StringList dirs; |
592 | 0 | get_data_dirs(c, dirs); |
593 | 0 | int pos = find(dirs); |
594 | 0 | if (pos == -1) { |
595 | 0 | data[pos - offset].clear(); |
596 | 0 | } |
597 | 0 | } |
598 | | |
599 | | int MDInfoListofLists::find(const StringList & key) |
600 | 760 | { |
601 | 12.6k | for (int i = 0; i != size; ++i) { |
602 | 12.5k | if (data[i].key == key) |
603 | 605 | return i + offset; |
604 | 12.5k | } |
605 | 155 | return -1; |
606 | 760 | } |
607 | | |
608 | | PosibErr<const MDInfoListAll *> |
609 | | MDInfoListofLists::get_lists(Config * c) |
610 | 2.25k | { |
611 | 2.25k | LOCK(&lock); |
612 | 2.25k | Config * config = (Config *)c; // FIXME: WHY? |
613 | 2.25k | int & pos = config->md_info_list_index; |
614 | 2.25k | StringList dirs; |
615 | 2.25k | StringList key; |
616 | 2.25k | if (!valid_pos(pos)) { |
617 | 760 | get_data_dirs(config, dirs); |
618 | 760 | key = dirs; |
619 | 760 | key.add("////////"); |
620 | 760 | config->retrieve_list("dict-alias", &key); |
621 | 760 | pos = find(key); |
622 | 760 | } |
623 | 2.25k | if (!valid_pos(pos)) { |
624 | 155 | MDInfoListAll * new_data = new MDInfoListAll[size + 1]; |
625 | 12.0k | for (int i = 0; i != size; ++i) { |
626 | 11.9k | new_data[i] = data[i]; |
627 | 11.9k | } |
628 | 155 | ++size; |
629 | 155 | delete[] data; |
630 | 155 | data = new_data; |
631 | 155 | pos = size - 1 + offset; |
632 | 155 | } |
633 | 2.25k | MDInfoListAll & list_all = data[pos - offset]; |
634 | 2.25k | if (list_all.has_data()) |
635 | 2.09k | return &list_all; |
636 | | |
637 | 155 | list_all.key = key; |
638 | 155 | RET_ON_ERR(list_all.fill(config, dirs)); |
639 | | |
640 | 153 | return &list_all; |
641 | 155 | } |
642 | | |
643 | | ///////////////////////////////////////////////////////////////// |
644 | | // |
645 | | // utility functions |
646 | | // |
647 | | |
648 | | static const char * strnchr(const char * i, char c, unsigned int size) |
649 | 34.7k | { |
650 | 34.7k | const char * stop = i + size; |
651 | 177k | while (i != stop) { |
652 | 151k | if (*i == c) |
653 | 9.11k | return i; |
654 | 142k | ++i; |
655 | 142k | } |
656 | 25.6k | return 0; |
657 | 34.7k | } |
658 | | |
659 | | static const char * strnrchr(const char * stop, char c, unsigned int size) |
660 | 0 | { |
661 | 0 | const char * i = stop + size - 1; |
662 | 0 | --stop; |
663 | 0 | while (i != stop) { |
664 | 0 | if (*i == c) |
665 | 0 | return i; |
666 | 0 | --i; |
667 | 0 | } |
668 | 0 | return 0; |
669 | 0 | } |
670 | | |
671 | | ///////////////////////////////////////////////////////////////// |
672 | | // |
673 | | // user visible functions and enumeration impl |
674 | | // |
675 | | |
676 | | // |
677 | | // ModuleInfo |
678 | | // |
679 | | |
680 | | PosibErr<const ModuleInfoList *> get_module_info_list(Config * c) |
681 | 758 | { |
682 | 758 | RET_ON_ERR_SET(md_info_list_of_lists.get_lists(c), const MDInfoListAll *, la); |
683 | 756 | return &la->module_info_list; |
684 | 758 | } |
685 | | |
686 | | ModuleInfoEnumeration * ModuleInfoList::elements() const |
687 | 756 | { |
688 | 756 | return new ModuleInfoEnumeration((ModuleInfoNode *)head_); |
689 | 756 | } |
690 | | |
691 | | unsigned int ModuleInfoList::size() const |
692 | 0 | { |
693 | 0 | return size_; |
694 | 0 | } |
695 | | |
696 | | bool ModuleInfoList::empty() const |
697 | 0 | { |
698 | 0 | return size_ != 0; |
699 | 0 | } |
700 | | |
701 | | ModuleInfoEnumeration * ModuleInfoEnumeration::clone () const |
702 | 0 | { |
703 | 0 | return new ModuleInfoEnumeration(*this); |
704 | 0 | } |
705 | | |
706 | | void ModuleInfoEnumeration::assign(const ModuleInfoEnumeration * other) |
707 | 0 | { |
708 | 0 | *this = *other; |
709 | 0 | } |
710 | | |
711 | | bool ModuleInfoEnumeration::at_end () const |
712 | 0 | { |
713 | 0 | return node_ == 0; |
714 | 0 | } |
715 | | |
716 | | const ModuleInfo * ModuleInfoEnumeration::next () |
717 | 1.51k | { |
718 | 1.51k | if (node_ == 0) return 0; |
719 | 756 | const ModuleInfo * data = &(node_->c_struct); |
720 | 756 | node_ = (ModuleInfoNode *)(node_->next); |
721 | 756 | return data; |
722 | 1.51k | } |
723 | | |
724 | | // |
725 | | // DictInfo |
726 | | // |
727 | | |
728 | | PosibErr<const DictInfoList *> get_dict_info_list(Config * c) |
729 | 756 | { |
730 | 756 | RET_ON_ERR_SET(md_info_list_of_lists.get_lists(c), const MDInfoListAll *, la); |
731 | 756 | return &la->dict_info_list; |
732 | 756 | } |
733 | | |
734 | | PosibErr<const StringMap *> get_dict_aliases(Config * c) |
735 | 739 | { |
736 | 739 | RET_ON_ERR_SET(md_info_list_of_lists.get_lists(c), const MDInfoListAll *, la); |
737 | 739 | return &la->dict_aliases; |
738 | 739 | } |
739 | | |
740 | | DictInfoEnumeration * DictInfoList::elements() const |
741 | 756 | { |
742 | 756 | return new DictInfoEnumeration(static_cast<DictInfoNode *>(head_)); |
743 | 756 | } |
744 | | |
745 | | unsigned int DictInfoList::size() const |
746 | 0 | { |
747 | 0 | return size_; |
748 | 0 | } |
749 | | |
750 | | bool DictInfoList::empty() const |
751 | 0 | { |
752 | 0 | return size_ != 0; |
753 | 0 | } |
754 | | |
755 | | DictInfoEnumeration * DictInfoEnumeration::clone() const |
756 | 0 | { |
757 | 0 | return new DictInfoEnumeration(*this); |
758 | 0 | } |
759 | | |
760 | | void DictInfoEnumeration::assign(const DictInfoEnumeration * other) |
761 | 0 | { |
762 | 0 | *this = *other; |
763 | 0 | } |
764 | | |
765 | | bool DictInfoEnumeration::at_end() const |
766 | 0 | { |
767 | 0 | return node_ == 0; |
768 | 0 | } |
769 | | |
770 | | const DictInfo * DictInfoEnumeration::next () |
771 | 42.7k | { |
772 | 42.7k | if (node_ == 0) return 0; |
773 | 41.9k | const DictInfo * data = &(node_->c_struct); |
774 | 41.9k | node_ = (DictInfoNode *)(node_->next); |
775 | 41.9k | return data; |
776 | 42.7k | } |
777 | | |
778 | | } |