Coverage Report

Created: 2025-12-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aspell/common/info.cpp
Line
Count
Source
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
71.0k
    operator DIR * () {return d_;}
50
440
    Dir(DIR * d) : d_(d) {}
51
440
    ~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
3.54k
    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
7.08k
    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
210
    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
17
  {
159
17
    while (head_ != 0) {
160
0
      ModuleInfoNode * to_del = head_;
161
0
      head_ = head_->next;
162
0
      delete to_del;
163
0
    }
164
17
  }
165
166
  PosibErr<void> ModuleInfoList::fill(MDInfoListAll & list_all,
167
              Config * config)
168
210
  {
169
210
    const ModuleInfoDefItem * i   = module_info_list_def_list;
170
210
    const ModuleInfoDefItem * end = module_info_list_def_list
171
210
      + sizeof(module_info_list_def_list)/sizeof(ModuleInfoDefItem);
172
420
    for (; i != end; ++i)
173
210
    {
174
210
      StringIStream in(i->data);
175
210
      proc_info(list_all, config, i->name, strlen(i->name), in);
176
210
    }
177
178
210
    StringListEnumeration els = list_all.for_dirs.elements_obj();
179
210
    const char * dir;
180
430
    while ( (dir = els.next()) != 0) {
181
220
      Dir d(opendir(dir));
182
220
      if (d==0) continue;
183
    
184
210
      struct dirent * entry;
185
35.2k
      while ( (entry = readdir(d)) != 0) {
186
35.0k
  const char * name = entry->d_name;
187
35.0k
  const char * dot_loc = strrchr(name, '.');
188
35.0k
  unsigned int name_size = dot_loc == 0 ? strlen(name) :  dot_loc - name;
189
      
190
  // check if it ends in suffix
191
35.0k
  if (strcmp(name + name_size, ".asmi") != 0)
192
35.0k
    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
210
    }
203
210
    return no_err;
204
210
  }
205
206
  PosibErr<void> ModuleInfoList::proc_info(MDInfoListAll &,
207
             Config * config,
208
             const char * name,
209
             unsigned int name_size,
210
             IStream & in)
211
210
  {
212
210
    ModuleInfoNode * * prev = &head_;
213
210
    ModuleInfoNode * to_add = new ModuleInfoNode();
214
210
    to_add->c_struct.name = 0;
215
210
    to_add->c_struct.order_num = -1;
216
210
    to_add->c_struct.lib_dir = 0;
217
210
    to_add->c_struct.dict_dirs = 0;
218
219
210
    to_add->name.assign(name, name_size);
220
210
    to_add->c_struct.name = to_add->name.c_str();
221
    
222
210
    PosibErr<void> err;
223
224
210
    String buf; DataPair d;
225
630
    while (getdata_pair(in, d, buf)) {
226
420
      if (d.key == "order-num") {
227
210
  to_add->c_struct.order_num = strtod_c(d.value.str, NULL);
228
210
  if (!(0 < to_add->c_struct.order_num && 
229
210
        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
210
      } 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
210
      } 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
210
      } else if (d.key == "dict-exts") {
242
210
  to_add->c_struct.dict_dirs = &(to_add->dict_exts);
243
210
  itemize(d.value, to_add->dict_exts);
244
210
      } else {
245
0
  err.prim_err(unknown_key, d.key);
246
0
  goto RETURN_ERROR;
247
0
      }
248
420
    }
249
  
250
210
    while (*prev != 0 && 
251
0
     (*prev)->c_struct.order_num < to_add->c_struct.order_num)
252
0
      prev = &(*prev)->next;
253
210
    to_add->next = *prev;
254
210
    *prev = to_add;
255
210
    return err;
256
257
0
  RETURN_ERROR:
258
0
    delete to_add;
259
0
    return err;
260
210
  }
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
41.1k
    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
17
  {
297
17
    while (head_ != 0) {
298
0
      DictInfoNode * to_del = head_;
299
0
      head_ = head_->next;
300
0
      delete to_del;
301
0
    }
302
17
  }
303
304
  const DictExt * find_dict_ext(const DictExtList & l, ParmStr name)
305
62.1k
  {
306
62.1k
    DictExtList::const_iterator   i = l.begin();
307
62.1k
    DictExtList::const_iterator end = l.end();
308
200k
    for (; i != end; ++i) 
309
179k
    {
310
179k
      if (i->ext_size <= name.size() 
311
177k
          && strncmp(name + (name.size() - i->ext_size),
312
177k
                     i->ext, i->ext_size) == 0)
313
41.1k
        break;
314
179k
    }
315
    
316
62.1k
    if (i == end) // does not end in one of the extensions in list
317
21.0k
      return 0;
318
41.1k
    else
319
41.1k
      return &*i;
320
62.1k
  }
321
322
323
  PosibErr<void> DictInfoList::fill(MDInfoListAll & list_all,
324
            Config * config)
325
210
  {
326
210
    StringList aliases;
327
210
    config->retrieve_list("dict-alias", &aliases);
328
210
    StringListEnumeration els = aliases.elements_obj();
329
210
    const char * str;
330
27.2k
    while ( (str = els.next()) != 0) {
331
27.0k
      const char * end = strchr(str, ' ');
332
27.0k
      assert(end != 0); // FIXME: Return error
333
27.0k
      String name(str, end - str);
334
27.0k
      RET_ON_ERR(proc_file(list_all, config,
335
27.0k
                           0, name.str(), name.size(), 
336
27.0k
                           find_dict_ext(list_all.dict_exts, ".alias")->module));
337
27.0k
    }
338
339
210
    els = list_all.dict_dirs.elements_obj();
340
210
    const char * dir;
341
430
    while ( (dir = els.next()) != 0) {
342
220
      Dir d(opendir(dir));
343
220
      if (d==0) continue;
344
    
345
210
      struct dirent * entry;
346
35.2k
      while ( (entry = readdir(d)) != 0) {
347
35.0k
  const char * name = entry->d_name;
348
35.0k
  unsigned int name_size = strlen(name);
349
350
35.0k
  const DictExt * i = find_dict_ext(list_all.dict_exts, 
351
35.0k
                                          ParmString(name, name_size));
352
35.0k
  if (i == 0) // does not end in one of the extensions in list
353
21.0k
    continue;
354
355
14.0k
  name_size -= i->ext_size;
356
      
357
14.0k
  RET_ON_ERR(proc_file(list_all, config, 
358
14.0k
           dir, name, name_size, i->module));
359
14.0k
      }
360
210
    }
361
210
    return no_err;
362
210
  }
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
41.1k
  {
371
41.1k
    DictInfoNode * * prev = &head_;
372
41.1k
    StackPtr<DictInfoNode> to_add(new DictInfoNode());
373
41.1k
    const char * p0;
374
41.1k
    const char * p1;
375
41.1k
    const char * p2;
376
41.1k
    p0 = strnchr(name, '-', name_size);
377
41.1k
    if (!module)
378
0
      p2 = strnrchr(name, '-', name_size);
379
41.1k
    else
380
41.1k
      p2 = name + name_size;
381
41.1k
    if (p0 == 0)
382
28.3k
      p0 = p2;
383
41.1k
    p1 = p2;
384
41.1k
    if (p0 + 2 < p1 && asc_isdigit(p1[-1]) && asc_isdigit(p1[-2]) && p1[-3] == '-')
385
172
      p1 -= 2;
386
387
41.1k
    to_add->name.assign(name, p2-name);
388
41.1k
    to_add->c_struct.name = to_add->name.c_str();
389
  
390
41.1k
    to_add->code.assign(name, p0-name);
391
41.1k
    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
41.1k
    if (to_add->code.size() >= 2 
397
40.1k
  && asc_isalpha(to_add->code[0]) && asc_isalpha(to_add->code[1])) 
398
34.6k
    {
399
34.6k
      unsigned s = strcspn(to_add->code.str(), "_");
400
34.6k
      if (s > 3) return no_err;
401
25.8k
      unsigned i = 0;
402
82.0k
      for (; i != s; ++i)
403
56.2k
        to_add->name[i] = to_add->code[i] = asc_tolower(to_add->code[i]);
404
25.8k
      i++;
405
51.5k
      for (; i < to_add->code.size(); ++i)
406
25.7k
        to_add->name[i] = to_add->code[i] = asc_toupper(to_add->code[i]);
407
25.8k
    } else {
408
6.52k
      return no_err;
409
6.52k
    }
410
    
411
    // Need to do it here as module is about to get a value
412
    // if it is null
413
25.8k
    to_add->direct = module == 0 ? false : true;
414
415
25.8k
    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
25.8k
    to_add->c_struct.module = module;
423
  
424
25.8k
    if (p0 + 1 < p1)
425
6.31k
      to_add->variety.assign(p0+1, p1 - p0 - 1);
426
25.8k
    to_add->c_struct.variety = to_add->variety.c_str();
427
  
428
25.8k
    if (p1 != p2) 
429
148
      to_add->size_str.assign(p1, 2);
430
25.6k
    else
431
25.6k
      to_add->size_str = "60";
432
25.8k
    to_add->c_struct.size_str = to_add->size_str.c_str();
433
25.8k
    to_add->c_struct.size = atoi(to_add->c_struct.size_str);
434
435
25.8k
    if (dir) {
436
6.93k
      to_add->info_file  = dir;
437
6.93k
      to_add->info_file += '/';
438
6.93k
    }
439
25.8k
    to_add->info_file += name;
440
  
441
939k
    while (*prev != 0 && *(DictInfoNode *)*prev < *to_add)
442
913k
      prev = &(*prev)->next;
443
25.8k
    to_add->next = *prev;
444
25.8k
    *prev = to_add.release();
445
446
25.8k
    return no_err;
447
25.8k
  }
448
449
  bool operator< (const DictInfoNode & r, const DictInfoNode & l)
450
939k
  {
451
939k
    const DictInfo & rhs = r.c_struct;
452
939k
    const DictInfo & lhs = l.c_struct;
453
939k
    int res = strcmp(rhs.code, lhs.code);
454
939k
    if (res < 0) return true;
455
94.7k
    if (res > 0) return false;
456
87.9k
    res = strcmp(rhs.variety,lhs.variety);
457
87.9k
    if (res < 0) return true;
458
18.5k
    if (res > 0) return false;
459
14.0k
    if (rhs.size < lhs.size) return true;
460
13.9k
    if (rhs.size > lhs.size) return false;
461
13.8k
    res = strcmp(rhs.module->name,lhs.module->name);
462
13.8k
    if (res < 0) return true;
463
13.8k
    return false;
464
13.8k
  }
465
466
  PosibErr<void> get_dict_file_name(const DictInfo * mi, 
467
            String & main_wl, String & flags)
468
1.15k
  {
469
1.15k
    const DictInfoNode * node = reinterpret_cast<const DictInfoNode *>(mi);
470
1.15k
    if (node->direct) {
471
1.15k
      main_wl = node->info_file;
472
1.15k
      flags   = "";
473
1.15k
      return no_err;
474
1.15k
    } 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
1.15k
  }
486
487
  /////////////////////////////////////////////////////////////////
488
  //
489
  // Lists of Info Lists Impl
490
  //
491
492
  void get_data_dirs (Config * config,
493
          StringList & lst)
494
1.20k
  {
495
1.20k
    lst.clear();
496
1.20k
    lst.add(config->retrieve("data-dir"));
497
1.20k
    lst.add(config->retrieve("dict-dir"));
498
1.20k
  }
499
500
  DictExt::DictExt(ModuleInfo * m, const char * e)
501
630
  {
502
630
    module = m;
503
630
    ext_size = strlen(e);
504
630
    assert(ext_size <= max_ext_size);
505
630
    memcpy(ext, e, ext_size + 1);
506
630
  }
507
508
  void MDInfoListAll::clear()
509
17
  {
510
17
    module_info_list.clear();
511
17
    dict_dirs.clear();
512
17
    dict_exts.clear();
513
17
    dict_info_list.clear();
514
17
  }
515
516
  PosibErr<void> MDInfoListAll::fill(Config * c, 
517
                                     StringList & dirs)
518
227
  {
519
227
    PosibErr<void> err;
520
521
227
    err = fill_dict_aliases(c);
522
227
    if (err.has_err()) goto RETURN_ERROR;
523
524
210
    for_dirs = dirs;
525
210
    err = module_info_list.fill(*this, c);
526
210
    if (err.has_err()) goto RETURN_ERROR;
527
528
210
    fill_helper_lists(dirs);
529
210
    err = dict_info_list.fill(*this, c);
530
210
    if (err.has_err()) goto RETURN_ERROR;
531
532
210
    return err;
533
534
17
  RETURN_ERROR:
535
17
    clear();
536
17
    return err;
537
210
  }
538
539
  void MDInfoListAll::fill_helper_lists(const StringList & def_dirs)
540
210
  {
541
210
    dict_dirs = def_dirs;
542
210
    dict_exts.append(DictExt(0, ".awli"));
543
544
420
    for (ModuleInfoNode * n = module_info_list.head_; n != 0; n = n->next) 
545
210
    {
546
210
      {
547
210
  StringListEnumeration e = n->dict_dirs.elements_obj();
548
210
  const char * item;
549
210
  while ( (item = e.next()) != 0 )
550
0
    dict_dirs.add(item);
551
210
      }{
552
210
  StringListEnumeration e = n->dict_exts.elements_obj();
553
210
  const char * item;
554
630
  while ( (item = e.next()) != 0 )
555
420
    dict_exts.append(DictExt(&n->c_struct, item));
556
210
      }
557
210
    }
558
210
  }
559
560
  PosibErr<void> MDInfoListAll::fill_dict_aliases(Config * c)
561
227
  {
562
227
    StringList aliases;
563
227
    c->retrieve_list("dict-alias", &aliases);
564
227
    StringListEnumeration els = aliases.elements_obj();
565
227
    const char * str;
566
28.4k
    while ( (str = els.next()) != 0) {
567
28.2k
      const char * end = strchr(str, ' ');
568
28.2k
      if (!end) return make_err(bad_value, "dict-alias", str, 
569
17
                                _("in the form \"<name> <value>\""));
570
28.2k
      String name(str, end - str);
571
58.8k
      while (asc_isspace(*end)) ++end;
572
28.2k
      dict_aliases.insert(name.str(), end);
573
28.2k
    }
574
210
    return no_err;
575
227
  }
576
577
578
  MDInfoListofLists::MDInfoListofLists()
579
2
    : 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
1.20k
  {
601
27.4k
    for (int i = 0; i != size; ++i) {
602
27.1k
      if (data[i].key == key)
603
979
  return i + offset;
604
27.1k
    }
605
227
    return -1;
606
1.20k
  }
607
608
  PosibErr<const MDInfoListAll *>
609
  MDInfoListofLists::get_lists(Config * c)
610
3.54k
  {
611
3.54k
    LOCK(&lock);
612
3.54k
    Config * config = (Config *)c; // FIXME: WHY?
613
3.54k
    int & pos = config->md_info_list_index;
614
3.54k
    StringList dirs;
615
3.54k
    StringList key;
616
3.54k
    if (!valid_pos(pos)) {
617
1.20k
      get_data_dirs(config, dirs);
618
1.20k
      key = dirs;
619
1.20k
      key.add("////////");
620
1.20k
      config->retrieve_list("dict-alias", &key);
621
1.20k
      pos = find(key);
622
1.20k
    }
623
3.54k
    if (!valid_pos(pos)) {
624
227
      MDInfoListAll * new_data = new MDInfoListAll[size + 1];
625
25.8k
      for (int i = 0; i != size; ++i) {
626
25.6k
  new_data[i] = data[i];
627
25.6k
      }
628
227
      ++size;
629
227
      delete[] data;
630
227
      data = new_data;
631
227
      pos = size - 1 + offset;
632
227
    }
633
3.54k
    MDInfoListAll & list_all = data[pos - offset];
634
3.54k
    if (list_all.has_data())
635
3.31k
      return &list_all;
636
637
227
    list_all.key = key;
638
227
    RET_ON_ERR(list_all.fill(config, dirs));
639
640
210
    return &list_all;
641
227
  }
642
643
  /////////////////////////////////////////////////////////////////
644
  //
645
  // utility functions
646
  //
647
648
  static const char * strnchr(const char * i, char c, unsigned int size)
649
41.1k
  {
650
41.1k
    const char * stop = i + size;
651
236k
    while (i != stop) {
652
208k
      if (*i == c)
653
12.8k
  return i;
654
195k
      ++i;
655
195k
    }
656
28.3k
    return 0;
657
41.1k
  }
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
1.19k
  {
682
1.19k
    RET_ON_ERR_SET(md_info_list_of_lists.get_lists(c), const MDInfoListAll *, la);
683
1.18k
    return &la->module_info_list;
684
1.19k
  }
685
686
  ModuleInfoEnumeration * ModuleInfoList::elements() const
687
1.18k
  {
688
1.18k
    return new ModuleInfoEnumeration((ModuleInfoNode *)head_);
689
1.18k
  }
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
2.36k
  {
718
2.36k
    if (node_ == 0) return 0;
719
1.18k
    const ModuleInfo * data = &(node_->c_struct);
720
1.18k
    node_ = (ModuleInfoNode *)(node_->next);
721
1.18k
    return data;
722
2.36k
  }
723
724
  //
725
  // DictInfo
726
  //
727
728
  PosibErr<const DictInfoList *> get_dict_info_list(Config * c)
729
1.18k
  {
730
1.18k
    RET_ON_ERR_SET(md_info_list_of_lists.get_lists(c), const MDInfoListAll *, la);
731
1.18k
    return &la->dict_info_list;
732
1.18k
  }
733
734
  PosibErr<const StringMap *> get_dict_aliases(Config * c)
735
1.16k
  {
736
1.16k
    RET_ON_ERR_SET(md_info_list_of_lists.get_lists(c), const MDInfoListAll *, la);
737
1.16k
    return &la->dict_aliases;
738
1.16k
  }
739
740
  DictInfoEnumeration * DictInfoList::elements() const
741
1.18k
  {
742
1.18k
    return new DictInfoEnumeration(static_cast<DictInfoNode *>(head_));
743
1.18k
  }
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
59.0k
  {
772
59.0k
    if (node_ == 0) return 0;
773
57.8k
    const DictInfo * data = &(node_->c_struct);
774
57.8k
    node_ = (DictInfoNode *)(node_->next);
775
57.8k
    return data;
776
59.0k
  }
777
778
}