blob: 8137501f8811f82fbf1f440f234baca050003128 [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>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025#ifdef WIN32
26#define strcasecmp _stricmp
27#define strncasecmp _strnicmp
28#endif
29
30#include <rfb/util.h>
31#include <rfb/Configuration.h>
32#include <rfb/LogWriter.h>
33#include <rfb/Exception.h>
34#include <rfb/Threading.h>
35
36#ifdef __RFB_THREADING_IMPL
37// On platforms that support Threading, we use Locks to make getData safe
38#define LOCK_CONFIG Lock l(*configLock())
39rfb::Mutex* configLock_ = 0;
40static rfb::Mutex* configLock() {
41 if (!configLock_)
42 configLock_ = new rfb::Mutex;
43 return configLock_;
44}
45#else
46#define LOCK_CONFIG
47#endif
48
49#include <rdr/HexOutStream.h>
50#include <rdr/HexInStream.h>
51
52using namespace rfb;
53
54static LogWriter vlog("Config");
55
56
Adam Tkacc58b3d12010-04-23 13:55:10 +000057// -=- The Global/server/viewer Configuration objects
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000058Configuration* Configuration::global_ = 0;
Adam Tkacc58b3d12010-04-23 13:55:10 +000059Configuration* Configuration::server_ = 0;
60Configuration* Configuration::viewer_ = 0;
61
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000062Configuration* Configuration::global() {
63 if (!global_)
64 global_ = new Configuration("Global");
65 return global_;
66}
67
Adam Tkacc58b3d12010-04-23 13:55:10 +000068Configuration* Configuration::server() {
69 if (!server_)
70 server_ = new Configuration("Server");
71 return server_;
72}
73
74Configuration* Configuration::viewer() {
75 if (!viewer_)
76 viewer_ = new Configuration("Viewer");
77 return viewer_;
78}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000079
80// -=- Configuration implementation
81
82Configuration::Configuration(const char* name_, Configuration* attachToGroup)
Adam Tkacd36b6262009-09-04 10:57:20 +000083: name(strDup(name_)), head(0), _next(0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000084 if (attachToGroup) {
85 _next = attachToGroup->_next;
86 attachToGroup->_next = this;
87 }
88}
89
90Configuration& Configuration::operator=(const Configuration& src) {
91 VoidParameter* current = head;
92 while (current) {
93 VoidParameter* srcParam = ((Configuration&)src).get(current->getName());
94 if (srcParam) {
95 current->immutable = false;
96 CharArray value(srcParam->getValueStr());
97 vlog.debug("operator=(%s, %s)", current->getName(), value.buf);
98 current->setParam(value.buf);
99 }
100 current = current->_next;
101 }
102 if (_next)
103 *_next=src;
104 return *this;
105}
106
107bool Configuration::set(const char* n, const char* v, bool immutable) {
108 return set(n, strlen(n), v, immutable);
109}
110
111bool Configuration::set(const char* name, int len,
112 const char* val, bool immutable)
113{
114 VoidParameter* current = head;
115 while (current) {
116 if ((int)strlen(current->getName()) == len &&
117 strncasecmp(current->getName(), name, len) == 0)
118 {
119 bool b = current->setParam(val);
120 current->setHasBeenSet();
121 if (b && immutable)
122 current->setImmutable();
123 return b;
124 }
125 current = current->_next;
126 }
127 return _next ? _next->set(name, len, val, immutable) : false;
128}
129
130bool Configuration::set(const char* config, bool immutable) {
131 bool hyphen = false;
132 if (config[0] == '-') {
133 hyphen = true;
134 config++;
135 if (config[0] == '-') config++; // allow gnu-style --<option>
136 }
137 const char* equal = strchr(config, '=');
138 if (equal) {
139 return set(config, equal-config, equal+1, immutable);
140 } else if (hyphen) {
141 VoidParameter* current = head;
142 while (current) {
143 if (strcasecmp(current->getName(), config) == 0) {
144 bool b = current->setParam();
145 current->setHasBeenSet();
146 if (b && immutable)
147 current->setImmutable();
148 return b;
149 }
150 current = current->_next;
151 }
152 }
153 return _next ? _next->set(config, immutable) : false;
154}
155
156VoidParameter* Configuration::get(const char* param)
157{
158 VoidParameter* current = head;
159 while (current) {
160 if (strcasecmp(current->getName(), param) == 0)
161 return current;
162 current = current->_next;
163 }
164 return _next ? _next->get(param) : 0;
165}
166
167void Configuration::list(int width, int nameWidth) {
168 VoidParameter* current = head;
169
170 fprintf(stderr, "%s Parameters:\n", name.buf);
171 while (current) {
172 char* def_str = current->getDefaultStr();
173 const char* desc = current->getDescription();
174 fprintf(stderr," %-*s -", nameWidth, current->getName());
175 int column = strlen(current->getName());
176 if (column < nameWidth) column = nameWidth;
177 column += 4;
178 while (true) {
179 const char* s = strchr(desc, ' ');
180 int wordLen;
181 if (s) wordLen = s-desc;
182 else wordLen = strlen(desc);
183
184 if (column + wordLen + 1 > width) {
185 fprintf(stderr,"\n%*s",nameWidth+4,"");
186 column = nameWidth+4;
187 }
188 fprintf(stderr," %.*s",wordLen,desc);
189 column += wordLen + 1;
190 desc += wordLen + 1;
191 if (!s) break;
192 }
193
194 if (def_str) {
195 if (column + (int)strlen(def_str) + 11 > width)
196 fprintf(stderr,"\n%*s",nameWidth+4,"");
197 fprintf(stderr," (default=%s)\n",def_str);
Adam Tkacd36b6262009-09-04 10:57:20 +0000198 strFree(def_str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000199 } else {
200 fprintf(stderr,"\n");
201 }
202 current = current->_next;
203 }
204
205 if (_next)
206 _next->list(width, nameWidth);
207}
208
209
210// -=- VoidParameter
211
Adam Tkacc58b3d12010-04-23 13:55:10 +0000212VoidParameter::VoidParameter(const char* name_, const char* desc_,
213 ConfigurationObject co)
214 : immutable(false), _hasBeenSet(false), name(name_), description(desc_)
215{
216 Configuration *conf = NULL;
217
218 switch (co) {
219 case ConfGlobal: conf = Configuration::global();
220 break;
221 case ConfServer: conf = Configuration::server();
222 break;
223 case ConfViewer: conf = Configuration::viewer();
224 break;
225 }
226
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000227 _next = conf->head;
228 conf->head = this;
229}
230
231VoidParameter::~VoidParameter() {
232}
233
234const char*
235VoidParameter::getName() const {
236 return name;
237}
238
239const char*
240VoidParameter::getDescription() const {
241 return description;
242}
243
244bool VoidParameter::setParam() {
245 return false;
246}
247
248bool VoidParameter::isBool() const {
249 return false;
250}
251
252void
253VoidParameter::setImmutable() {
254 vlog.debug("set immutable %s", getName());
255 immutable = true;
256}
257
258void
259VoidParameter::setHasBeenSet() {
260 _hasBeenSet = true;
261}
262
263bool
264VoidParameter::hasBeenSet() {
265 return _hasBeenSet;
266}
267
268// -=- AliasParameter
269
270AliasParameter::AliasParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000271 VoidParameter* param_, ConfigurationObject co)
272 : VoidParameter(name_, desc_, co), param(param_) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000273}
274
275bool
276AliasParameter::setParam(const char* v) {
277 return param->setParam(v);
278}
279
280bool AliasParameter::setParam() {
281 return param->setParam();
282}
283
284char*
285AliasParameter::getDefaultStr() const {
286 return 0;
287}
288
289char* AliasParameter::getValueStr() const {
290 return param->getValueStr();
291}
292
293bool AliasParameter::isBool() const {
294 return param->isBool();
295}
296
297void
298AliasParameter::setImmutable() {
299 vlog.debug("set immutable %s (Alias)", getName());
300 param->setImmutable();
301}
302
303
304// -=- BoolParameter
305
Adam Tkacc58b3d12010-04-23 13:55:10 +0000306BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
307 ConfigurationObject co)
308: VoidParameter(name_, desc_, co), value(v), def_value(v) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000309}
310
311bool
312BoolParameter::setParam(const char* v) {
313 if (immutable) return true;
314
315 if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
316 || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
317 value = 1;
318 else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
319 || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
320 value = 0;
321 else {
322 vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
323 return false;
324 }
325
326 vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
327 return true;
328}
329
330bool BoolParameter::setParam() {
331 setParam(true);
332 return true;
333}
334
335void BoolParameter::setParam(bool b) {
336 if (immutable) return;
337 value = b;
338 vlog.debug("set %s(Bool) to %d", getName(), value);
339}
340
341char*
342BoolParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000343 return strDup(def_value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000344}
345
346char* BoolParameter::getValueStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000347 return strDup(value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000348}
349
350bool BoolParameter::isBool() const {
351 return true;
352}
353
354BoolParameter::operator bool() const {
355 return value;
356}
357
358// -=- IntParameter
359
360IntParameter::IntParameter(const char* name_, const char* desc_, int v,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000361 int minValue_, int maxValue_, ConfigurationObject co)
362 : VoidParameter(name_, desc_, co), value(v), def_value(v),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000363 minValue(minValue_), maxValue(maxValue_)
364{
365}
366
367bool
368IntParameter::setParam(const char* v) {
369 if (immutable) return true;
370 vlog.debug("set %s(Int) to %s", getName(), v);
371 int i = atoi(v);
372 if (i < minValue || i > maxValue)
373 return false;
374 value = i;
375 return true;
376}
377
378bool
379IntParameter::setParam(int v) {
380 if (immutable) return true;
381 vlog.debug("set %s(Int) to %d", getName(), v);
382 if (v < minValue || v > maxValue)
383 return false;
384 value = v;
385 return true;
386}
387
388char*
389IntParameter::getDefaultStr() const {
390 char* result = new char[16];
391 sprintf(result, "%d", def_value);
392 return result;
393}
394
395char* IntParameter::getValueStr() const {
396 char* result = new char[16];
397 sprintf(result, "%d", value);
398 return result;
399}
400
401IntParameter::operator int() const {
402 return value;
403}
404
405// -=- StringParameter
406
407StringParameter::StringParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000408 const char* v, ConfigurationObject co)
409 : VoidParameter(name_, desc_, co), value(strDup(v)), def_value(v)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000410{
411 if (!v) {
412 fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
413 throw rfb::Exception("Default value <null> not allowed");
414 }
415}
416
417StringParameter::~StringParameter() {
Adam Tkacd36b6262009-09-04 10:57:20 +0000418 strFree(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000419}
420
Adam Tkac3c7f8e12010-11-11 14:29:35 +0000421void StringParameter::setDefaultStr(const char* v) {
422 def_value = v;
423 strFree(value);
424 value = strDup(v);
425}
426
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000427bool StringParameter::setParam(const char* v) {
428 LOCK_CONFIG;
429 if (immutable) return true;
430 if (!v)
431 throw rfb::Exception("setParam(<null>) not allowed");
432 vlog.debug("set %s(String) to %s", getName(), v);
433 CharArray oldValue(value);
Adam Tkacd36b6262009-09-04 10:57:20 +0000434 value = strDup(v);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000435 return value != 0;
436}
437
438char* StringParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000439 return strDup(def_value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000440}
441
442char* StringParameter::getValueStr() const {
443 LOCK_CONFIG;
Adam Tkacd36b6262009-09-04 10:57:20 +0000444 return strDup(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000445}
446
Pierre Ossman660f1082011-03-02 12:44:12 +0000447StringParameter::operator const char *() const {
448 return value;
449}
450
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000451// -=- BinaryParameter
452
Adam Tkacc58b3d12010-04-23 13:55:10 +0000453BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
454 const void* v, int l, ConfigurationObject co)
455: VoidParameter(name_, desc_, co), value(0), length(0), def_value((char*)v), def_length(l) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000456 if (l) {
457 value = new char[l];
458 length = l;
459 memcpy(value, v, l);
460 }
461}
462BinaryParameter::~BinaryParameter() {
463 if (value)
464 delete [] value;
465}
466
467bool BinaryParameter::setParam(const char* v) {
468 LOCK_CONFIG;
469 if (immutable) return true;
470 vlog.debug("set %s(Binary) to %s", getName(), v);
471 return rdr::HexInStream::hexStrToBin(v, &value, &length);
472}
473
474void BinaryParameter::setParam(const void* v, int len) {
475 LOCK_CONFIG;
476 if (immutable) return;
477 vlog.debug("set %s(Binary)", getName());
478 delete [] value; value = 0;
479 if (len) {
480 value = new char[len];
481 length = len;
482 memcpy(value, v, len);
483 }
484}
485
486char* BinaryParameter::getDefaultStr() const {
487 return rdr::HexOutStream::binToHexStr(def_value, def_length);
488}
489
490char* BinaryParameter::getValueStr() const {
491 LOCK_CONFIG;
492 return rdr::HexOutStream::binToHexStr(value, length);
493}
494
495void BinaryParameter::getData(void** data_, int* length_) const {
496 LOCK_CONFIG;
497 if (length_) *length_ = length;
498 if (data_) {
499 *data_ = new char[length];
500 memcpy(*data_, value, length);
501 }
502}