blob: d7005221e4615db96116ee457811ebac055ed267 [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);
91 current->setHasBeenSet();
92 if (b && immutable)
93 current->setImmutable();
94 return b;
95 }
96 current = current->_next;
97 }
98 return _next ? _next->set(name, len, val, immutable) : false;
99}
100
101bool Configuration::set(const char* config, bool immutable) {
102 bool hyphen = false;
103 if (config[0] == '-') {
104 hyphen = true;
105 config++;
106 if (config[0] == '-') config++; // allow gnu-style --<option>
107 }
108 const char* equal = strchr(config, '=');
109 if (equal) {
110 return set(config, equal-config, equal+1, immutable);
111 } else if (hyphen) {
112 VoidParameter* current = head;
113 while (current) {
114 if (strcasecmp(current->getName(), config) == 0) {
115 bool b = current->setParam();
116 current->setHasBeenSet();
117 if (b && immutable)
118 current->setImmutable();
119 return b;
120 }
121 current = current->_next;
122 }
123 }
124 return _next ? _next->set(config, immutable) : false;
125}
126
127VoidParameter* Configuration::get(const char* param)
128{
129 VoidParameter* current = head;
130 while (current) {
131 if (strcasecmp(current->getName(), param) == 0)
132 return current;
133 current = current->_next;
134 }
135 return _next ? _next->get(param) : 0;
136}
137
138void Configuration::list(int width, int nameWidth) {
139 VoidParameter* current = head;
140
141 fprintf(stderr, "%s Parameters:\n", name.buf);
142 while (current) {
143 char* def_str = current->getDefaultStr();
144 const char* desc = current->getDescription();
145 fprintf(stderr," %-*s -", nameWidth, current->getName());
146 int column = strlen(current->getName());
147 if (column < nameWidth) column = nameWidth;
148 column += 4;
149 while (true) {
150 const char* s = strchr(desc, ' ');
151 int wordLen;
152 if (s) wordLen = s-desc;
153 else wordLen = strlen(desc);
154
155 if (column + wordLen + 1 > width) {
156 fprintf(stderr,"\n%*s",nameWidth+4,"");
157 column = nameWidth+4;
158 }
159 fprintf(stderr," %.*s",wordLen,desc);
160 column += wordLen + 1;
161 desc += wordLen + 1;
162 if (!s) break;
163 }
164
165 if (def_str) {
166 if (column + (int)strlen(def_str) + 11 > width)
167 fprintf(stderr,"\n%*s",nameWidth+4,"");
168 fprintf(stderr," (default=%s)\n",def_str);
Adam Tkacd36b6262009-09-04 10:57:20 +0000169 strFree(def_str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170 } else {
171 fprintf(stderr,"\n");
172 }
173 current = current->_next;
174 }
175
176 if (_next)
177 _next->list(width, nameWidth);
178}
179
180
181// -=- VoidParameter
182
Adam Tkacc58b3d12010-04-23 13:55:10 +0000183VoidParameter::VoidParameter(const char* name_, const char* desc_,
184 ConfigurationObject co)
185 : immutable(false), _hasBeenSet(false), name(name_), description(desc_)
186{
187 Configuration *conf = NULL;
188
189 switch (co) {
190 case ConfGlobal: conf = Configuration::global();
191 break;
192 case ConfServer: conf = Configuration::server();
193 break;
194 case ConfViewer: conf = Configuration::viewer();
195 break;
196 }
197
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000198 _next = conf->head;
199 conf->head = this;
200}
201
202VoidParameter::~VoidParameter() {
203}
204
205const char*
206VoidParameter::getName() const {
207 return name;
208}
209
210const char*
211VoidParameter::getDescription() const {
212 return description;
213}
214
215bool VoidParameter::setParam() {
216 return false;
217}
218
219bool VoidParameter::isBool() const {
220 return false;
221}
222
223void
224VoidParameter::setImmutable() {
225 vlog.debug("set immutable %s", getName());
226 immutable = true;
227}
228
229void
230VoidParameter::setHasBeenSet() {
231 _hasBeenSet = true;
232}
233
234bool
235VoidParameter::hasBeenSet() {
236 return _hasBeenSet;
237}
238
239// -=- AliasParameter
240
241AliasParameter::AliasParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000242 VoidParameter* param_, ConfigurationObject co)
243 : VoidParameter(name_, desc_, co), param(param_) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000244}
245
246bool
247AliasParameter::setParam(const char* v) {
248 return param->setParam(v);
249}
250
251bool AliasParameter::setParam() {
252 return param->setParam();
253}
254
255char*
256AliasParameter::getDefaultStr() const {
257 return 0;
258}
259
260char* AliasParameter::getValueStr() const {
261 return param->getValueStr();
262}
263
264bool AliasParameter::isBool() const {
265 return param->isBool();
266}
267
268void
269AliasParameter::setImmutable() {
270 vlog.debug("set immutable %s (Alias)", getName());
271 param->setImmutable();
272}
273
274
275// -=- BoolParameter
276
Adam Tkacc58b3d12010-04-23 13:55:10 +0000277BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
278 ConfigurationObject co)
279: VoidParameter(name_, desc_, co), value(v), def_value(v) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000280}
281
282bool
283BoolParameter::setParam(const char* v) {
284 if (immutable) return true;
285
286 if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
287 || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
288 value = 1;
289 else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
290 || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
291 value = 0;
292 else {
293 vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
294 return false;
295 }
296
297 vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
298 return true;
299}
300
301bool BoolParameter::setParam() {
302 setParam(true);
303 return true;
304}
305
306void BoolParameter::setParam(bool b) {
307 if (immutable) return;
308 value = b;
309 vlog.debug("set %s(Bool) to %d", getName(), value);
310}
311
312char*
313BoolParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000314 return strDup(def_value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000315}
316
317char* BoolParameter::getValueStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000318 return strDup(value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000319}
320
321bool BoolParameter::isBool() const {
322 return true;
323}
324
325BoolParameter::operator bool() const {
326 return value;
327}
328
329// -=- IntParameter
330
331IntParameter::IntParameter(const char* name_, const char* desc_, int v,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000332 int minValue_, int maxValue_, ConfigurationObject co)
333 : VoidParameter(name_, desc_, co), value(v), def_value(v),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000334 minValue(minValue_), maxValue(maxValue_)
335{
336}
337
338bool
339IntParameter::setParam(const char* v) {
340 if (immutable) return true;
341 vlog.debug("set %s(Int) to %s", getName(), v);
342 int i = atoi(v);
343 if (i < minValue || i > maxValue)
344 return false;
345 value = i;
346 return true;
347}
348
349bool
350IntParameter::setParam(int v) {
351 if (immutable) return true;
352 vlog.debug("set %s(Int) to %d", getName(), v);
353 if (v < minValue || v > maxValue)
354 return false;
355 value = v;
356 return true;
357}
358
359char*
360IntParameter::getDefaultStr() const {
361 char* result = new char[16];
362 sprintf(result, "%d", def_value);
363 return result;
364}
365
366char* IntParameter::getValueStr() const {
367 char* result = new char[16];
368 sprintf(result, "%d", value);
369 return result;
370}
371
372IntParameter::operator int() const {
373 return value;
374}
375
376// -=- StringParameter
377
378StringParameter::StringParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000379 const char* v, ConfigurationObject co)
380 : VoidParameter(name_, desc_, co), value(strDup(v)), def_value(v)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000381{
382 if (!v) {
383 fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
384 throw rfb::Exception("Default value <null> not allowed");
385 }
386}
387
388StringParameter::~StringParameter() {
Adam Tkacd36b6262009-09-04 10:57:20 +0000389 strFree(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000390}
391
Adam Tkac3c7f8e12010-11-11 14:29:35 +0000392void StringParameter::setDefaultStr(const char* v) {
393 def_value = v;
394 strFree(value);
395 value = strDup(v);
396}
397
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000398bool StringParameter::setParam(const char* v) {
399 LOCK_CONFIG;
400 if (immutable) return true;
401 if (!v)
402 throw rfb::Exception("setParam(<null>) not allowed");
403 vlog.debug("set %s(String) to %s", getName(), v);
404 CharArray oldValue(value);
Adam Tkacd36b6262009-09-04 10:57:20 +0000405 value = strDup(v);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000406 return value != 0;
407}
408
409char* StringParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000410 return strDup(def_value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000411}
412
413char* StringParameter::getValueStr() const {
414 LOCK_CONFIG;
Adam Tkacd36b6262009-09-04 10:57:20 +0000415 return strDup(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000416}
417
Pierre Ossman660f1082011-03-02 12:44:12 +0000418StringParameter::operator const char *() const {
419 return value;
420}
421
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000422// -=- BinaryParameter
423
Adam Tkacc58b3d12010-04-23 13:55:10 +0000424BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
425 const void* v, int l, ConfigurationObject co)
426: VoidParameter(name_, desc_, co), value(0), length(0), def_value((char*)v), def_length(l) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000427 if (l) {
428 value = new char[l];
429 length = l;
430 memcpy(value, v, l);
431 }
432}
433BinaryParameter::~BinaryParameter() {
434 if (value)
435 delete [] value;
436}
437
438bool BinaryParameter::setParam(const char* v) {
439 LOCK_CONFIG;
440 if (immutable) return true;
441 vlog.debug("set %s(Binary) to %s", getName(), v);
442 return rdr::HexInStream::hexStrToBin(v, &value, &length);
443}
444
445void BinaryParameter::setParam(const void* v, int len) {
446 LOCK_CONFIG;
447 if (immutable) return;
448 vlog.debug("set %s(Binary)", getName());
449 delete [] value; value = 0;
450 if (len) {
451 value = new char[len];
452 length = len;
453 memcpy(value, v, len);
454 }
455}
456
457char* BinaryParameter::getDefaultStr() const {
458 return rdr::HexOutStream::binToHexStr(def_value, def_length);
459}
460
461char* BinaryParameter::getValueStr() const {
462 LOCK_CONFIG;
463 return rdr::HexOutStream::binToHexStr(value, length);
464}
465
466void BinaryParameter::getData(void** data_, int* length_) const {
467 LOCK_CONFIG;
468 if (length_) *length_ = length;
469 if (data_) {
470 *data_ = new char[length];
471 memcpy(*data_, value, length);
472 }
473}