blob: fd4c23aeed11d0d897d9135921e0e4f6b46723fa [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
3 *
4 * This 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 * (at your option) any later version.
8 *
9 * This software 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 software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20// -=- Configuration.cxx
21
22#include <stdlib.h>
23#include <ctype.h>
24#include <string.h>
25#include <assert.h>
26#ifdef WIN32
27#define strcasecmp _stricmp
28#define strncasecmp _strnicmp
29#endif
30
31#include <rfb/util.h>
32#include <rfb/Configuration.h>
33#include <rfb/LogWriter.h>
34#include <rfb/Exception.h>
35#include <rfb/Threading.h>
36
37#ifdef __RFB_THREADING_IMPL
38// On platforms that support Threading, we use Locks to make getData safe
39#define LOCK_CONFIG Lock l(*configLock())
40rfb::Mutex* configLock_ = 0;
41static rfb::Mutex* configLock() {
42 if (!configLock_)
43 configLock_ = new rfb::Mutex;
44 return configLock_;
45}
46#else
47#define LOCK_CONFIG
48#endif
49
50#include <rdr/HexOutStream.h>
51#include <rdr/HexInStream.h>
52
53using namespace rfb;
54
55static LogWriter vlog("Config");
56
57
58// -=- The Global Configuration object
59Configuration* Configuration::global_ = 0;
60Configuration* Configuration::global() {
61 if (!global_)
62 global_ = new Configuration("Global");
63 return global_;
64}
65
66
67// -=- Configuration implementation
68
69Configuration::Configuration(const char* name_, Configuration* attachToGroup)
Adam Tkac97abe8a2009-09-04 10:16:58 +000070: name(safe_strdup(name_)), head(0), _next(0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000071 if (attachToGroup) {
72 _next = attachToGroup->_next;
73 attachToGroup->_next = this;
74 }
75}
76
77Configuration& Configuration::operator=(const Configuration& src) {
78 VoidParameter* current = head;
79 while (current) {
80 VoidParameter* srcParam = ((Configuration&)src).get(current->getName());
81 if (srcParam) {
82 current->immutable = false;
83 CharArray value(srcParam->getValueStr());
84 vlog.debug("operator=(%s, %s)", current->getName(), value.buf);
85 current->setParam(value.buf);
86 }
87 current = current->_next;
88 }
89 if (_next)
90 *_next=src;
91 return *this;
92}
93
94bool Configuration::set(const char* n, const char* v, bool immutable) {
95 return set(n, strlen(n), v, immutable);
96}
97
98bool Configuration::set(const char* name, int len,
99 const char* val, bool immutable)
100{
101 VoidParameter* current = head;
102 while (current) {
103 if ((int)strlen(current->getName()) == len &&
104 strncasecmp(current->getName(), name, len) == 0)
105 {
106 bool b = current->setParam(val);
107 current->setHasBeenSet();
108 if (b && immutable)
109 current->setImmutable();
110 return b;
111 }
112 current = current->_next;
113 }
114 return _next ? _next->set(name, len, val, immutable) : false;
115}
116
117bool Configuration::set(const char* config, bool immutable) {
118 bool hyphen = false;
119 if (config[0] == '-') {
120 hyphen = true;
121 config++;
122 if (config[0] == '-') config++; // allow gnu-style --<option>
123 }
124 const char* equal = strchr(config, '=');
125 if (equal) {
126 return set(config, equal-config, equal+1, immutable);
127 } else if (hyphen) {
128 VoidParameter* current = head;
129 while (current) {
130 if (strcasecmp(current->getName(), config) == 0) {
131 bool b = current->setParam();
132 current->setHasBeenSet();
133 if (b && immutable)
134 current->setImmutable();
135 return b;
136 }
137 current = current->_next;
138 }
139 }
140 return _next ? _next->set(config, immutable) : false;
141}
142
143VoidParameter* Configuration::get(const char* param)
144{
145 VoidParameter* current = head;
146 while (current) {
147 if (strcasecmp(current->getName(), param) == 0)
148 return current;
149 current = current->_next;
150 }
151 return _next ? _next->get(param) : 0;
152}
153
154void Configuration::list(int width, int nameWidth) {
155 VoidParameter* current = head;
156
157 fprintf(stderr, "%s Parameters:\n", name.buf);
158 while (current) {
159 char* def_str = current->getDefaultStr();
160 const char* desc = current->getDescription();
161 fprintf(stderr," %-*s -", nameWidth, current->getName());
162 int column = strlen(current->getName());
163 if (column < nameWidth) column = nameWidth;
164 column += 4;
165 while (true) {
166 const char* s = strchr(desc, ' ');
167 int wordLen;
168 if (s) wordLen = s-desc;
169 else wordLen = strlen(desc);
170
171 if (column + wordLen + 1 > width) {
172 fprintf(stderr,"\n%*s",nameWidth+4,"");
173 column = nameWidth+4;
174 }
175 fprintf(stderr," %.*s",wordLen,desc);
176 column += wordLen + 1;
177 desc += wordLen + 1;
178 if (!s) break;
179 }
180
181 if (def_str) {
182 if (column + (int)strlen(def_str) + 11 > width)
183 fprintf(stderr,"\n%*s",nameWidth+4,"");
184 fprintf(stderr," (default=%s)\n",def_str);
Adam Tkac97abe8a2009-09-04 10:16:58 +0000185 free(def_str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000186 } else {
187 fprintf(stderr,"\n");
188 }
189 current = current->_next;
190 }
191
192 if (_next)
193 _next->list(width, nameWidth);
194}
195
196
197// -=- VoidParameter
198
199VoidParameter::VoidParameter(const char* name_, const char* desc_, Configuration* conf)
200 : immutable(false), _hasBeenSet(false), name(name_), description(desc_) {
201 if (!conf)
202 conf = Configuration::global();
203 _next = conf->head;
204 conf->head = this;
205}
206
207VoidParameter::~VoidParameter() {
208}
209
210const char*
211VoidParameter::getName() const {
212 return name;
213}
214
215const char*
216VoidParameter::getDescription() const {
217 return description;
218}
219
220bool VoidParameter::setParam() {
221 return false;
222}
223
224bool VoidParameter::isBool() const {
225 return false;
226}
227
228void
229VoidParameter::setImmutable() {
230 vlog.debug("set immutable %s", getName());
231 immutable = true;
232}
233
234void
235VoidParameter::setHasBeenSet() {
236 _hasBeenSet = true;
237}
238
239bool
240VoidParameter::hasBeenSet() {
241 return _hasBeenSet;
242}
243
244// -=- AliasParameter
245
246AliasParameter::AliasParameter(const char* name_, const char* desc_,
247 VoidParameter* param_, Configuration* conf)
248 : VoidParameter(name_, desc_, conf), param(param_) {
249}
250
251bool
252AliasParameter::setParam(const char* v) {
253 return param->setParam(v);
254}
255
256bool AliasParameter::setParam() {
257 return param->setParam();
258}
259
260char*
261AliasParameter::getDefaultStr() const {
262 return 0;
263}
264
265char* AliasParameter::getValueStr() const {
266 return param->getValueStr();
267}
268
269bool AliasParameter::isBool() const {
270 return param->isBool();
271}
272
273void
274AliasParameter::setImmutable() {
275 vlog.debug("set immutable %s (Alias)", getName());
276 param->setImmutable();
277}
278
279
280// -=- BoolParameter
281
282BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v, Configuration* conf)
283: VoidParameter(name_, desc_, conf), value(v), def_value(v) {
284}
285
286bool
287BoolParameter::setParam(const char* v) {
288 if (immutable) return true;
289
290 if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
291 || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
292 value = 1;
293 else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
294 || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
295 value = 0;
296 else {
297 vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
298 return false;
299 }
300
301 vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
302 return true;
303}
304
305bool BoolParameter::setParam() {
306 setParam(true);
307 return true;
308}
309
310void BoolParameter::setParam(bool b) {
311 if (immutable) return;
312 value = b;
313 vlog.debug("set %s(Bool) to %d", getName(), value);
314}
315
316char*
317BoolParameter::getDefaultStr() const {
Adam Tkac97abe8a2009-09-04 10:16:58 +0000318 return safe_strdup(def_value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000319}
320
321char* BoolParameter::getValueStr() const {
Adam Tkac97abe8a2009-09-04 10:16:58 +0000322 return safe_strdup(value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000323}
324
325bool BoolParameter::isBool() const {
326 return true;
327}
328
329BoolParameter::operator bool() const {
330 return value;
331}
332
333// -=- IntParameter
334
335IntParameter::IntParameter(const char* name_, const char* desc_, int v,
336 int minValue_, int maxValue_, Configuration* conf)
337 : VoidParameter(name_, desc_, conf), value(v), def_value(v),
338 minValue(minValue_), maxValue(maxValue_)
339{
340}
341
342bool
343IntParameter::setParam(const char* v) {
344 if (immutable) return true;
345 vlog.debug("set %s(Int) to %s", getName(), v);
346 int i = atoi(v);
347 if (i < minValue || i > maxValue)
348 return false;
349 value = i;
350 return true;
351}
352
353bool
354IntParameter::setParam(int v) {
355 if (immutable) return true;
356 vlog.debug("set %s(Int) to %d", getName(), v);
357 if (v < minValue || v > maxValue)
358 return false;
359 value = v;
360 return true;
361}
362
363char*
364IntParameter::getDefaultStr() const {
365 char* result = new char[16];
366 sprintf(result, "%d", def_value);
367 return result;
368}
369
370char* IntParameter::getValueStr() const {
371 char* result = new char[16];
372 sprintf(result, "%d", value);
373 return result;
374}
375
376IntParameter::operator int() const {
377 return value;
378}
379
380// -=- StringParameter
381
382StringParameter::StringParameter(const char* name_, const char* desc_,
383 const char* v, Configuration* conf)
Adam Tkac97abe8a2009-09-04 10:16:58 +0000384 : VoidParameter(name_, desc_, conf), value(safe_strdup(v)), def_value(v)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000385{
386 if (!v) {
387 fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
388 throw rfb::Exception("Default value <null> not allowed");
389 }
390}
391
392StringParameter::~StringParameter() {
Adam Tkac97abe8a2009-09-04 10:16:58 +0000393 free(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000394}
395
396bool StringParameter::setParam(const char* v) {
397 LOCK_CONFIG;
398 if (immutable) return true;
399 if (!v)
400 throw rfb::Exception("setParam(<null>) not allowed");
401 vlog.debug("set %s(String) to %s", getName(), v);
402 CharArray oldValue(value);
Adam Tkac97abe8a2009-09-04 10:16:58 +0000403 value = safe_strdup(v);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000404 return value != 0;
405}
406
407char* StringParameter::getDefaultStr() const {
Adam Tkac97abe8a2009-09-04 10:16:58 +0000408 return safe_strdup(def_value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000409}
410
411char* StringParameter::getValueStr() const {
412 LOCK_CONFIG;
Adam Tkac97abe8a2009-09-04 10:16:58 +0000413 return safe_strdup(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000414}
415
416// -=- BinaryParameter
417
418BinaryParameter::BinaryParameter(const char* name_, const char* desc_, const void* v, int l, Configuration* conf)
419: VoidParameter(name_, desc_, conf), value(0), length(0), def_value((char*)v), def_length(l) {
420 if (l) {
421 value = new char[l];
422 length = l;
423 memcpy(value, v, l);
424 }
425}
426BinaryParameter::~BinaryParameter() {
427 if (value)
428 delete [] value;
429}
430
431bool BinaryParameter::setParam(const char* v) {
432 LOCK_CONFIG;
433 if (immutable) return true;
434 vlog.debug("set %s(Binary) to %s", getName(), v);
435 return rdr::HexInStream::hexStrToBin(v, &value, &length);
436}
437
438void BinaryParameter::setParam(const void* v, int len) {
439 LOCK_CONFIG;
440 if (immutable) return;
441 vlog.debug("set %s(Binary)", getName());
442 delete [] value; value = 0;
443 if (len) {
444 value = new char[len];
445 length = len;
446 memcpy(value, v, len);
447 }
448}
449
450char* BinaryParameter::getDefaultStr() const {
451 return rdr::HexOutStream::binToHexStr(def_value, def_length);
452}
453
454char* BinaryParameter::getValueStr() const {
455 LOCK_CONFIG;
456 return rdr::HexOutStream::binToHexStr(value, length);
457}
458
459void BinaryParameter::getData(void** data_, int* length_) const {
460 LOCK_CONFIG;
461 if (length_) *length_ = length;
462 if (data_) {
463 *data_ = new char[length];
464 memcpy(*data_, value, length);
465 }
466}