new home directory
[feisty_meow.git] / nucleus / library / configuration / system_values.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : system_values                                                     *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *******************************************************************************
7 * Copyright (c) 2004-$now By Author.  This program is free software; you can  *
8 * redistribute it and/or modify it under the terms of the GNU General Public  *
9 * License as published by the Free Software Foundation; either version 2 of   *
10 * the License or (at your option) any later version.  This is online at:      *
11 *     http://www.fsf.org/copyleft/gpl.html                                    *
12 * Please send any updates to: fred@gruntose.com                               *
13 \*****************************************************************************/
14
15 #include "ini_configurator.h"
16 #include "system_values.h"
17
18 #include <structures/int_hash.h>
19 #include <structures/string_table.h>
20 #include <textual/list_parsing.h>
21 #include <textual/parser_bits.h>
22 #include "../algorithms/sorts.h"
23
24 using namespace algorithms;
25 using namespace basis;
26 using namespace structures;
27 using namespace textual;
28
29 namespace configuration {
30
31 const int MAX_VALUE_BITS = 8;  // we provide 2^n slots in hash.
32
33 #undef LOG
34 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
35
36 //////////////
37
38 class value_record
39 {
40 public:
41   astring _name;  // the name of the value.
42   astring _descrip;  // the description of the value.
43   astring _location;  // the file defining the value.
44
45   value_record(const astring &name = astring::empty_string(),
46       const astring &description = astring::empty_string(),
47       const astring &location = astring::empty_string())
48   : _name(name), _descrip(description), _location(location) {}
49 };
50
51 //////////////
52
53 class system_values_lookup_list : public int_hash<value_record>
54 {
55 public:
56   system_values_lookup_list() : int_hash<value_record>(MAX_VALUE_BITS) {}
57
58   // finds the symbolic "name" in the table, which is not as efficient as
59   // lookin up integers.
60   value_record *text_find(const astring &name, int &value) {
61     // scoot across all of the ids.
62     const int_set &cids = ids();
63     for (int i = 0; i < cids.elements(); i++) {
64       int current_id = cids[i];
65       value_record *curr = find(current_id);
66       if (!curr) {
67 //serious error.
68         continue;
69       }
70       if (curr->_name == name) {
71         // this is a match to the name they were seeking.
72         value = current_id;
73         return curr;
74       }
75     }
76     return NULL_POINTER;
77   }
78 };
79
80 //////////////
81
82 system_values::system_values(const astring &section_tag)
83 : _tag(new astring(section_tag)),
84   _list(new system_values_lookup_list),
85   _file(new astring(DEFAULT_MANIFEST))
86 {
87   FUNCDEF("constructor");
88   open_values();
89 }
90   
91 system_values::~system_values()
92 {
93   WHACK(_list);
94   WHACK(_tag);
95   WHACK(_file);
96 }
97
98 const char *system_values::DEFAULT_MANIFEST = "manifest.txt";
99   // this is the default manifest and it is expected to live right in
100   // the folder where the applications are.
101
102 bool system_values::use_other_manifest(const astring &manifest_file)
103 {
104   *_file = manifest_file;
105   return open_values();
106 }
107
108 const char *system_values::OUTCOME_VALUES() { return "DEFINE_OUTCOME"; }
109
110 const char *system_values::FILTER_VALUES() { return "DEFINE_FILTER"; }
111
112 const char *system_values::EVENT_VALUES() { return "DEFINE_EVENT"; }
113
114 bool system_values::open_values()
115 {
116   FUNCDEF("open_values");
117   ini_configurator ini(*_file, ini_configurator::RETURN_ONLY,
118       ini_configurator::APPLICATION_DIRECTORY);
119
120   string_table full_section;
121   bool got_section = ini.get_section(*_tag, full_section);
122   if (!got_section) return false;  // nothing there to look up.
123   for (int i = 0; i < full_section.symbols(); i++) {
124
125     string_array items;
126     list_parsing::parse_csv_line(full_section.name(i), items);
127     if (items.length() < 4) {
128       continue;
129     }
130
131     value_record *entry = new value_record(items[0], items[2], items[3]);
132     int value = items[1].convert(0);
133     _list->add(value, entry);
134   }
135
136   return true;
137 }
138
139 #define SV_EOL parser_bits::platform_eol_to_chars()
140
141 //hmmm: it might be nice to have an alternate version sorted by name...
142
143 astring system_values::text_form() const
144 {
145   int_set cids = _list->ids();
146
147   if (!_tag->equal_to("DEFINE_OUTCOME")) {
148     // sort the list in identifier order.
149     shell_sort(cids.access(), cids.elements());
150   } else {
151     // sort the list in reverse identifier order, since zero is first
152     // for outcomes and then they go negative.
153     shell_sort(cids.access(), cids.elements(), true);
154   }
155
156   astring to_return("values for ");
157   to_return += *_tag;
158   to_return += SV_EOL;
159   for (int i = 0; i < cids.elements(); i++) {
160     int current_id = cids[i];
161     value_record *curr = _list->find(current_id);
162     if (!curr) {
163 //serious error.
164       continue;
165     }
166     to_return += a_sprintf("%d: ", current_id);
167     to_return += curr->_name + " \"" + curr->_descrip + "\" from "
168         + curr->_location;
169     to_return += SV_EOL;
170   }
171   return to_return;
172 }
173
174 bool system_values::lookup(int value, astring &symbolic_name,
175     astring &description, astring &file_location)
176 {
177   value_record *found = _list->find(value);
178   if (!found) return false;
179   symbolic_name = found->_name;
180   description = found->_descrip;
181   file_location = found->_location;
182   return true;
183 }
184
185 bool system_values::lookup(const astring &symbolic_name, int &value,
186     astring &description, astring &file_location)
187 {
188   value_record *found = _list->text_find(symbolic_name, value);
189   if (!found) return false;
190   description = found->_descrip;
191   file_location = found->_location;
192   return true;
193 }
194
195 int system_values::elements() const { return _list->ids().elements(); }
196
197 bool system_values::get(int index, astring &symbolic_name, int &value,
198     astring &description, astring &file_location)
199 {
200   bounds_return(index, 0, _list->ids().elements() - 1, false);  // bad index.
201   value = _list->ids()[index];
202   return lookup(value, symbolic_name, description, file_location);
203 }
204
205 } //namespace.
206
207