Fix crash when providing bad command line argument
[clinton/bobotpp.git] / source / BotConfig.C
1 // BotConfig.C -*- C++ -*-
2 // Copyright (C) 2004,2005 Clinton Ebadi
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // any later version.
8
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 #include "BotConfig.H"
19 #include "Bot.H"
20 #include "StringTokenizer.H"
21 #include "Utils.H"
22 #include <iostream>
23 #include <string>
24 #include <list>
25 #include <algorithm>
26
27 BotConfig::BotConfig (std::string cf)
28 : config_filename (cf)
29 { }
30
31 bool
32 BotConfig::read_config ()
33 {
34 std::ifstream config_file (config_filename.c_str ());
35 std::string current_line;
36 unsigned int line_number = 1;
37
38 options_db.clear ();
39
40 if (!config_file)
41 {
42 // FIXME: log lines (needs local bot object, probably a
43 // redesign. UGH).
44
45 // Bot::logLine ("Error: Config File Not Found `" +
46 // config_filename + "'");
47 return false;
48 }
49
50 while (!config_file.eof ())
51 {
52 std::getline (config_file, current_line);
53 if (current_line.length () == 0 || current_line[0] == '#')
54 {
55 line_number++;
56 continue;
57 }
58
59 StringTokenizer st (current_line);
60 std::string command = Utils::to_upper (Utils::trim_str(st.next_token('=')));
61 StringTokenizer params (Utils::trim_str (st.next_token('=')));
62
63 set_option_value (command, params.rest (), true);
64 }
65 return true;
66 }
67
68
69 BotConfig::t_option_values
70 BotConfig::get_option_values (std::string key)
71 {
72 t_options_db::const_iterator cf_iter =
73 options_db.find (key);
74
75 if (cf_iter != options_db.end ())
76 return cf_iter->second;
77 else
78 return t_option_values (); // Empty vector
79 }
80
81 std::string
82 BotConfig::set_config_file (std::string fname)
83 {
84 std::string old_config_filename = config_filename;
85 config_filename = fname;
86 options_db.clear ();
87 read_config ();
88 return old_config_filename;
89 }
90
91 namespace
92 {
93 struct push_back_
94 {
95 BotConfig::t_value_list* lst;
96
97 push_back_ (BotConfig::t_value_list* l)
98 : lst (l)
99 {}
100
101 void operator() (BotConfig::t_value val)
102 {
103 lst->push_back (val);
104 }
105 };
106
107 struct run_fun_
108 {
109 std::string key;
110 BotConfig::t_value_list& vals;
111 bool appended;
112
113 run_fun_ (std::string k, BotConfig::t_value_list& vl, bool a)
114 : key (k), vals (vl), appended (a)
115 { }
116 void operator() (BotConfig::t_watcher w)
117 {
118 w (key, vals, appended);
119 }
120 };
121 }
122
123 void
124 BotConfig::set_option_value (std::string key, t_value_list values,
125 bool append)
126 {
127 key = Utils::to_upper (key); // keys are case insensitive
128 t_options_db::iterator cf_iter = options_db.find (key);
129
130
131 if (cf_iter != options_db.end ())
132 {
133 if (append)
134 {
135 // FIXME: Potentially slow (make this push_front in 3.0)
136 std::for_each (values.begin (), values.end (),
137 push_back_ (&cf_iter->second.first));
138 }
139 else
140 cf_iter->second.first = values;
141
142 // call watchers
143 std::for_each (cf_iter->second.second.begin (),
144 cf_iter->second.second.end (),
145 run_fun_ (key, values, append));
146 }
147 else
148 options_db[key] = t_option_values (values, t_watcher_list ());
149 }
150
151 void
152 BotConfig::set_option_value (std::string key, t_value value, bool append)
153 {
154 t_value_list value_list = t_value_list ();
155 value_list.push_front (value);
156
157 set_option_value (key, value_list, append);
158 }
159
160 bool
161 BotConfig::add_watcher (std::string key, t_watcher new_watcher)
162 {
163 t_options_db::iterator cf_iter = options_db.find (key);
164
165 if (cf_iter != options_db.end ())
166 {
167 cf_iter->second.second.push_front (new_watcher);
168 return true;
169 }
170 else
171 return false;
172 }