blob: 8e1ea6e93dee53a95cc779ca42c6c87fd3afedfd [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Peter Åstrandd69bcc42011-09-28 12:52:53 +00002 * Copyright 2004-2005 Cendio AB.
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
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
26#include <rfb/util.h>
27#include <rfb/Configuration.h>
28#include <rfb/LogWriter.h>
29#include <rfb/Exception.h>
30#include <rfb/Threading.h>
31
32#ifdef __RFB_THREADING_IMPL
33// On platforms that support Threading, we use Locks to make getData safe
34#define LOCK_CONFIG Lock l(*configLock())
35rfb::Mutex* configLock_ = 0;
36static rfb::Mutex* configLock() {
37 if (!configLock_)
38 configLock_ = new rfb::Mutex;
39 return configLock_;
40}
41#else
42#define LOCK_CONFIG
43#endif
44
45#include <rdr/HexOutStream.h>
46#include <rdr/HexInStream.h>
47
48using namespace rfb;
49
50static LogWriter vlog("Config");
51
52
Adam Tkacc58b3d12010-04-23 13:55:10 +000053// -=- The Global/server/viewer Configuration objects
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000054Configuration* Configuration::global_ = 0;
Adam Tkacc58b3d12010-04-23 13:55:10 +000055Configuration* Configuration::server_ = 0;
56Configuration* Configuration::viewer_ = 0;
57
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000058Configuration* Configuration::global() {
59 if (!global_)
60 global_ = new Configuration("Global");
61 return global_;
62}
63
Adam Tkacc58b3d12010-04-23 13:55:10 +000064Configuration* Configuration::server() {
65 if (!server_)
66 server_ = new Configuration("Server");
67 return server_;
68}
69
70Configuration* Configuration::viewer() {
71 if (!viewer_)
72 viewer_ = new Configuration("Viewer");
73 return viewer_;
74}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000075
76// -=- Configuration implementation
77
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000078bool Configuration::set(const char* n, const char* v, bool immutable) {
79 return set(n, strlen(n), v, immutable);
80}
81
82bool Configuration::set(const char* name, int len,
83 const char* val, bool immutable)
84{
85 VoidParameter* current = head;
86 while (current) {
87 if ((int)strlen(current->getName()) == len &&
88 strncasecmp(current->getName(), name, len) == 0)
89 {
90 bool b = current->setParam(val);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000091 if (b && immutable)
92 current->setImmutable();
93 return b;
94 }
95 current = current->_next;
96 }
97 return _next ? _next->set(name, len, val, immutable) : false;
98}
99
100bool Configuration::set(const char* config, bool immutable) {
101 bool hyphen = false;
102 if (config[0] == '-') {
103 hyphen = true;
104 config++;
105 if (config[0] == '-') config++; // allow gnu-style --<option>
106 }
107 const char* equal = strchr(config, '=');
108 if (equal) {
109 return set(config, equal-config, equal+1, immutable);
110 } else if (hyphen) {
111 VoidParameter* current = head;
112 while (current) {
113 if (strcasecmp(current->getName(), config) == 0) {
114 bool b = current->setParam();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000115 if (b && immutable)
116 current->setImmutable();
117 return b;
118 }
119 current = current->_next;
120 }
121 }
122 return _next ? _next->set(config, immutable) : false;
123}
124
125VoidParameter* Configuration::get(const char* param)
126{
127 VoidParameter* current = head;
128 while (current) {
129 if (strcasecmp(current->getName(), param) == 0)
130 return current;
131 current = current->_next;
132 }
133 return _next ? _next->get(param) : 0;
134}
135
136void Configuration::list(int width, int nameWidth) {
137 VoidParameter* current = head;
138
139 fprintf(stderr, "%s Parameters:\n", name.buf);
140 while (current) {
141 char* def_str = current->getDefaultStr();
142 const char* desc = current->getDescription();
143 fprintf(stderr," %-*s -", nameWidth, current->getName());
144 int column = strlen(current->getName());
145 if (column < nameWidth) column = nameWidth;
146 column += 4;
147 while (true) {
148 const char* s = strchr(desc, ' ');
149 int wordLen;
150 if (s) wordLen = s-desc;
151 else wordLen = strlen(desc);
152
153 if (column + wordLen + 1 > width) {
154 fprintf(stderr,"\n%*s",nameWidth+4,"");
155 column = nameWidth+4;
156 }
157 fprintf(stderr," %.*s",wordLen,desc);
158 column += wordLen + 1;
159 desc += wordLen + 1;
160 if (!s) break;
161 }
162
163 if (def_str) {
164 if (column + (int)strlen(def_str) + 11 > width)
165 fprintf(stderr,"\n%*s",nameWidth+4,"");
166 fprintf(stderr," (default=%s)\n",def_str);
Adam Tkacd36b6262009-09-04 10:57:20 +0000167 strFree(def_str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000168 } else {
169 fprintf(stderr,"\n");
170 }
171 current = current->_next;
172 }
173
174 if (_next)
175 _next->list(width, nameWidth);
176}
177
178
179// -=- VoidParameter
180
Adam Tkacc58b3d12010-04-23 13:55:10 +0000181VoidParameter::VoidParameter(const char* name_, const char* desc_,
182 ConfigurationObject co)
Pierre Ossman135906e2015-04-27 12:48:47 +0200183 : immutable(false), name(name_), description(desc_)
Adam Tkacc58b3d12010-04-23 13:55:10 +0000184{
185 Configuration *conf = NULL;
186
187 switch (co) {
188 case ConfGlobal: conf = Configuration::global();
189 break;
190 case ConfServer: conf = Configuration::server();
191 break;
192 case ConfViewer: conf = Configuration::viewer();
193 break;
194 }
195
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000196 _next = conf->head;
197 conf->head = this;
198}
199
200VoidParameter::~VoidParameter() {
201}
202
203const char*
204VoidParameter::getName() const {
205 return name;
206}
207
208const char*
209VoidParameter::getDescription() const {
210 return description;
211}
212
213bool VoidParameter::setParam() {
214 return false;
215}
216
217bool VoidParameter::isBool() const {
218 return false;
219}
220
221void
222VoidParameter::setImmutable() {
223 vlog.debug("set immutable %s", getName());
224 immutable = true;
225}
226
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000227// -=- AliasParameter
228
229AliasParameter::AliasParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000230 VoidParameter* param_, ConfigurationObject co)
231 : VoidParameter(name_, desc_, co), param(param_) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000232}
233
234bool
235AliasParameter::setParam(const char* v) {
236 return param->setParam(v);
237}
238
239bool AliasParameter::setParam() {
240 return param->setParam();
241}
242
243char*
244AliasParameter::getDefaultStr() const {
245 return 0;
246}
247
248char* AliasParameter::getValueStr() const {
249 return param->getValueStr();
250}
251
252bool AliasParameter::isBool() const {
253 return param->isBool();
254}
255
256void
257AliasParameter::setImmutable() {
258 vlog.debug("set immutable %s (Alias)", getName());
259 param->setImmutable();
260}
261
262
263// -=- BoolParameter
264
Adam Tkacc58b3d12010-04-23 13:55:10 +0000265BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
266 ConfigurationObject co)
267: VoidParameter(name_, desc_, co), value(v), def_value(v) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000268}
269
270bool
271BoolParameter::setParam(const char* v) {
272 if (immutable) return true;
273
274 if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
275 || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
276 value = 1;
277 else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
278 || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
279 value = 0;
280 else {
281 vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
282 return false;
283 }
284
285 vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
286 return true;
287}
288
289bool BoolParameter::setParam() {
290 setParam(true);
291 return true;
292}
293
294void BoolParameter::setParam(bool b) {
295 if (immutable) return;
296 value = b;
297 vlog.debug("set %s(Bool) to %d", getName(), value);
298}
299
300char*
301BoolParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000302 return strDup(def_value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000303}
304
305char* BoolParameter::getValueStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000306 return strDup(value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000307}
308
309bool BoolParameter::isBool() const {
310 return true;
311}
312
313BoolParameter::operator bool() const {
314 return value;
315}
316
317// -=- IntParameter
318
319IntParameter::IntParameter(const char* name_, const char* desc_, int v,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000320 int minValue_, int maxValue_, ConfigurationObject co)
321 : VoidParameter(name_, desc_, co), value(v), def_value(v),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000322 minValue(minValue_), maxValue(maxValue_)
323{
324}
325
326bool
327IntParameter::setParam(const char* v) {
328 if (immutable) return true;
329 vlog.debug("set %s(Int) to %s", getName(), v);
330 int i = atoi(v);
331 if (i < minValue || i > maxValue)
332 return false;
333 value = i;
334 return true;
335}
336
337bool
338IntParameter::setParam(int v) {
339 if (immutable) return true;
340 vlog.debug("set %s(Int) to %d", getName(), v);
341 if (v < minValue || v > maxValue)
342 return false;
343 value = v;
344 return true;
345}
346
347char*
348IntParameter::getDefaultStr() const {
349 char* result = new char[16];
350 sprintf(result, "%d", def_value);
351 return result;
352}
353
354char* IntParameter::getValueStr() const {
355 char* result = new char[16];
356 sprintf(result, "%d", value);
357 return result;
358}
359
360IntParameter::operator int() const {
361 return value;
362}
363
364// -=- StringParameter
365
366StringParameter::StringParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000367 const char* v, ConfigurationObject co)
368 : VoidParameter(name_, desc_, co), value(strDup(v)), def_value(v)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000369{
370 if (!v) {
371 fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
372 throw rfb::Exception("Default value <null> not allowed");
373 }
374}
375
376StringParameter::~StringParameter() {
Adam Tkacd36b6262009-09-04 10:57:20 +0000377 strFree(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000378}
379
Adam Tkac3c7f8e12010-11-11 14:29:35 +0000380void StringParameter::setDefaultStr(const char* v) {
381 def_value = v;
382 strFree(value);
383 value = strDup(v);
384}
385
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000386bool StringParameter::setParam(const char* v) {
387 LOCK_CONFIG;
388 if (immutable) return true;
389 if (!v)
390 throw rfb::Exception("setParam(<null>) not allowed");
391 vlog.debug("set %s(String) to %s", getName(), v);
392 CharArray oldValue(value);
Adam Tkacd36b6262009-09-04 10:57:20 +0000393 value = strDup(v);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000394 return value != 0;
395}
396
397char* StringParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000398 return strDup(def_value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000399}
400
401char* StringParameter::getValueStr() const {
402 LOCK_CONFIG;
Adam Tkacd36b6262009-09-04 10:57:20 +0000403 return strDup(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000404}
405
Pierre Ossman660f1082011-03-02 12:44:12 +0000406StringParameter::operator const char *() const {
407 return value;
408}
409
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000410// -=- BinaryParameter
411
Adam Tkacc58b3d12010-04-23 13:55:10 +0000412BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
413 const void* v, int l, ConfigurationObject co)
414: VoidParameter(name_, desc_, co), value(0), length(0), def_value((char*)v), def_length(l) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000415 if (l) {
416 value = new char[l];
417 length = l;
418 memcpy(value, v, l);
419 }
420}
421BinaryParameter::~BinaryParameter() {
422 if (value)
423 delete [] value;
424}
425
426bool BinaryParameter::setParam(const char* v) {
427 LOCK_CONFIG;
428 if (immutable) return true;
429 vlog.debug("set %s(Binary) to %s", getName(), v);
430 return rdr::HexInStream::hexStrToBin(v, &value, &length);
431}
432
433void BinaryParameter::setParam(const void* v, int len) {
434 LOCK_CONFIG;
435 if (immutable) return;
436 vlog.debug("set %s(Binary)", getName());
437 delete [] value; value = 0;
438 if (len) {
439 value = new char[len];
440 length = len;
441 memcpy(value, v, len);
442 }
443}
444
445char* BinaryParameter::getDefaultStr() const {
446 return rdr::HexOutStream::binToHexStr(def_value, def_length);
447}
448
449char* BinaryParameter::getValueStr() const {
450 LOCK_CONFIG;
451 return rdr::HexOutStream::binToHexStr(value, length);
452}
453
454void BinaryParameter::getData(void** data_, int* length_) const {
455 LOCK_CONFIG;
456 if (length_) *length_ = length;
457 if (data_) {
458 *data_ = new char[length];
459 memcpy(*data_, value, length);
460 }
461}