Coverage Report

Created: 2025-08-28 06:20

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