1 thilo.boehm 1.1 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 thilo.boehm 1.1 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //////////////////////////////////////////////////////////////////////////
29 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <cstdlib>
33 #include <cctype>
34 #include <fstream>
35 #include <cstdio>
|
39 thilo.boehm 1.1
40 PEGASUS_USING_STD;
41
42 PEGASUS_NAMESPACE_BEGIN
43
44 ////////////////////////////////////////////////////////////////////////////////
45 //
46 // TODO: expand variables in the configuration file. For example:
47 //
48 // provider_dir = "${home}/providers"
49 //
50 ////////////////////////////////////////////////////////////////////////////////
51
52 ////////////////////////////////////////////////////////////////////////////////
53 //
54 // Option
55 //
56 ////////////////////////////////////////////////////////////////////////////////
57
58 const Array<String>& Option::getDomain() const
59 {
60 thilo.boehm 1.1 return _domain;
61 }
62
63 void Option::setDomain(const Array<String>& domain)
64 {
65 _domain = domain;
66 }
67
68 ////////////////////////////////////////////////////////////////////////////////
69 //
70 // OptionManager
71 //
72 ////////////////////////////////////////////////////////////////////////////////
73
74 OptionManager::OptionManager()
75 :_msgPath("")
76 {
77
78 }
79
80 OptionManager::~OptionManager()
81 thilo.boehm 1.1 {
82 // Delete all options in the list:
83
84 for (Uint32 i = 0; i < _options.size(); i++)
85 delete _options[i];
86 }
87
88 void OptionManager::registerOption(Option* option)
89 {
90 if (!option)
91 throw NullPointer();
92
93 if (lookupOption(option->getOptionName()))
94 throw OMDuplicateOption(option->getOptionName());
95
96 _options.append(option);
97 }
98
99
100 void OptionManager::registerOptions(OptionRow* optionRow, Uint32 numOptions)
101 {
102 thilo.boehm 1.1 for (Uint32 i = 0; i < numOptions; i++)
103 {
104 // Get option name:
105
106 if (!optionRow[i].optionName)
107 throw NullPointer();
108
109 String optionName = optionRow[i].optionName;
110
111 // Get default value:
112
113 String defaultValue;
114
115 if (optionRow[i].defaultValue)
116 defaultValue = optionRow[i].defaultValue;
117
118 // Get the required flag:
119
120 Boolean required = optionRow[i].required != 0;
121
122 // Get the type:
123 thilo.boehm 1.1
124 Option::Type type = optionRow[i].type;
125
126 // Get the domain:
127
128 Array<String> domain;
129
130 if (optionRow[i].domain)
131 {
132 Uint32 domainSize = optionRow[i].domainSize;
133
134 for (Uint32 j = 0; j < domainSize; j++)
135 domain.append(optionRow[i].domain[j]);
136 }
137
138 // Get commandLineOptionName:
139
140 String commandLineOptionName;
141
142 if (optionRow[i].commandLineOptionName)
143 commandLineOptionName = optionRow[i].commandLineOptionName;
144 thilo.boehm 1.1
145 // get optionHelp Message String
146
147 String optionHelpMessage;
148
149 if (optionRow[i].optionHelpMessage)
150 optionHelpMessage = optionRow[i].optionHelpMessage;
151
152 // Add the option:
153
154 Option* option = new Option(
155 optionName,
156 defaultValue,
157 required,
158 type,
159 domain,
160 commandLineOptionName,
161 optionHelpMessage);
162
163 registerOption(option);
164 }
165 thilo.boehm 1.1 }
166
167 void OptionManager::registerOptions(
168 OptionRowWithMsg* optionRow,
169 Uint32 numOptions)
170 {
171 for (Uint32 i = 0; i < numOptions; i++)
172 {
173 // Get option name:
174
175 if (!optionRow[i].optionName)
176 {
177 throw NullPointer();
178 }
179
180 String optionName = optionRow[i].optionName;
181
182 // Get default value:
183
184 String defaultValue;
185
186 thilo.boehm 1.1 if (optionRow[i].defaultValue)
187 {
188 defaultValue = optionRow[i].defaultValue;
189 }
190 // Get the required flag:
191
192 Boolean required = optionRow[i].required != 0;
193
194 // Get the type:
195
196 Option::Type type = optionRow[i].type;
197
198 // Get the domain:
199
200 Array<String> domain;
201
202 if (optionRow[i].domain)
203 {
204 Uint32 domainSize = optionRow[i].domainSize;
205
206 for (Uint32 j = 0; j < domainSize; j++)
207 thilo.boehm 1.1 {
208 domain.append(optionRow[i].domain[j]);
209 }
210 }
211
212 // Get commandLineOptionName:
213
214 String commandLineOptionName;
215
216 if (optionRow[i].commandLineOptionName)
217 {
218 commandLineOptionName = optionRow[i].commandLineOptionName;
219 }
220 // get optionHelp Message String
221
222 String optionHelpMessage;
223
224 if (optionRow[i].optionHelpMessage)
225 {
226 optionHelpMessage = optionRow[i].optionHelpMessage;
227 }
228 thilo.boehm 1.1
229 String messageKey = String();
230 if (optionRow[i].messageKey)
231 {
232 messageKey = optionRow[i].messageKey;
233 }
234
235 // Add the option:
236
237 Option* option = new Option(
238 optionName,
239 defaultValue,
240 required,
241 type,
242 domain,
243 commandLineOptionName,
244 optionHelpMessage,
245 messageKey);
246
247 registerOption(option);
248 }
249 thilo.boehm 1.1 }
250 void OptionManager::mergeCommandLine(
251 int& argc,
252 char**& argv,
253 Boolean abortOnErr)
254 {
255 for (int i = 0; i < argc; )
256 {
257 // Check for -option:
258
259 const char* arg = argv[i];
260
261 if (*arg == '-')
262 {
263 // Look for the option:
264
265 Option* option = _lookupOptionByCommandLineOptionName(arg + 1);
266
267 if (!option)
268 {
269 if (abortOnErr)
270 thilo.boehm 1.1 {
271 throw OMMBadCmdLineOption(arg);
272 }
273 else
274 {
275 i++;
276 continue;
277 }
278 }
279
280 // Get the option argument if any:
281
282 const char* optionArgument = "true";
283
284 if (option->getType() != Option::BOOLEAN)
285 {
286 if (i + 1 == argc)
287 throw OMMissingCommandLineOptionArgument(arg);
288
289 optionArgument = argv[i + 1];
290 }
291 thilo.boehm 1.1
292 // Validate the value:
293
294 if (!option->isValid(optionArgument))
295 throw OMInvalidOptionValue(arg, optionArgument);
296
297 // Set the value:
298
299 option->setValue(optionArgument);
300
301 // Remove the option and its argument from the command line:
302
303 if (option->getType() == Option::BOOLEAN)
304 {
305 memmove(&argv[i], &argv[i + 1], (argc-i) * sizeof(char*));
306 argc--;
307 }
308 else
309 {
310 memmove(&argv[i], &argv[i + 2], (argc-i-1) * sizeof(char*));
311 argc -= 2;
312 thilo.boehm 1.1 }
313 }
314 else
315 i++;
316 }
317 }
318
319 void OptionManager::mergeFile(const String& fileName)
320 {
321 // Open the input file:
322 ifstream is(fileName.getCString());
323
324 if (!is)
325 throw NoSuchFile(fileName);
326
327 // For each line of the file:
328
329 String line;
330
331 for (Uint32 lineNumber = 1; GetLine(is, line); lineNumber++)
332 {
333 thilo.boehm 1.1 // -- Get the identifier and value:
334
335 if (line[0] == '#')
336 continue;
337
338 // Skip leading whitespace:
339
340 const Char16* p = line.getChar16Data();
341
342 while (*p && isspace(*p))
343 p++;
344
345 if (!*p)
346 continue;
347
348 if (*p == '#')
349 continue;
350
351 // Get the identifier:
352
353 String ident;
354 thilo.boehm 1.1
355 if (!(isalpha(*p) || *p == '_'))
356 throw OMConfigFileSyntaxError(fileName, lineNumber);
357
358 ident.append(*p++);
359
360 while (isalnum(*p) || *p == '_')
361 ident.append(*p++);
362
363 // Skip whitespace after identifier:
364
365 while (*p && isspace(*p))
366 p++;
367
368 // Expect an equal sign:
369
370 if (*p != '=')
371 throw OMConfigFileSyntaxError(fileName, lineNumber);
372 p++;
373
374 // Skip whitespace after equal sign:
375 thilo.boehm 1.1
376 while (*p && isspace(*p))
377 p++;
378
379 // Expect open quote:
380
381 if (*p != '"')
382 throw OMConfigFileSyntaxError(fileName, lineNumber);
383 p++;
384
385 // Get the value:
386
387 String value;
388
389 while (*p && *p != '"')
390 {
391 if (*p == '\\')
392 {
393 p++;
394
395 switch (*p)
396 thilo.boehm 1.1 {
397 case 'n':
398 value.append('\n');
399 break;
400
401 case 'r':
402 value.append('\r');
403 break;
404
405 case 't':
406 value.append('\t');
407 break;
408
409 case 'f':
410 value.append('\f');
411 break;
412
413 case '"':
414 value.append('"');
415 break;
416
417 thilo.boehm 1.1 case '\0':
418 throw OMConfigFileSyntaxError(fileName, lineNumber);
419
420 default:
421 value.append(*p);
422 }
423 p++;
424 }
425 else
426 value.append(*p++);
427 }
428
429
430 // Expect close quote:
431
432 if (*p != '"')
433 throw OMConfigFileSyntaxError(fileName, lineNumber);
434 p++;
435
436 // Skip whitespace through end of line:
437
438 thilo.boehm 1.1 while (*p && isspace(*p))
439 p++;
440
441 if (*p)
442 throw OMConfigFileSyntaxError(fileName, lineNumber);
443
444 // Now that we have the identifier and value, merge it:
445
446 Option* option = (Option*)lookupOption(ident);
447
448 if (!option)
449 throw OMUnrecognizedConfigFileOption(ident);
450
451 if (!option->isValid(value))
452 throw OMInvalidOptionValue(ident, value);
453
454 option->setValue(value);
455 }
456 }
457
458 void OptionManager::checkRequiredOptions() const
459 thilo.boehm 1.1 {
460 for (Uint32 i = 0; i < _options.size(); i++)
461 {
462 const Option* option = _options[i];
463
464 if (option->getRequired() && !option->isResolved())
465 throw OMMissingRequiredOptionValue(option->getOptionName());
466 }
467 }
468
469 const Option* OptionManager::lookupOption(const String& name) const
470 {
471 for (Uint32 i = 0; i < _options.size(); i++)
472 {
473 if (_options[i]->getOptionName() == name)
474 return _options[i];
475 }
476
477 return 0;
478 }
479
480 thilo.boehm 1.1 Boolean OptionManager::lookupValue(const String& name, String& value) const
481 {
482 const Option* option = lookupOption(name);
483
484 if (!option)
485 return false;
486
487 value = option->getValue();
488 return true;
489 }
490
491 Boolean OptionManager::lookupIntegerValue(
492 const String& name,
493 Uint32& value) const
494 {
495 //ATTN: KS P1 7 May 2002 - Add test for Integer type in om table.
496 String valueString;
497 if (lookupValue(name, valueString))
498 {
499 value = atol(valueString.getCString());
500 return true;
501 thilo.boehm 1.1 }
502 else
503 {
504 return false;
505 }
506
507 }
508
509 Boolean OptionManager::valueEquals(
510 const String& name,
511 const String& value) const
512 {
513 String optionString;
514
515 return (lookupValue(name, optionString) && optionString == value);
516 }
517
518 Boolean OptionManager::isTrue(const String& name) const
519 {
520 //ATTN: KS 7 May 2002 P3 Add test to confirm boolean type
521 return valueEquals(name, "true") ? true: false;
522 thilo.boehm 1.1 }
523
524 /* ATTN: P3 MB 2001 Buried this one for the moment to think about it.
525 Uint32 OptionManager::isStringInOptionMask(
526 const String& option,
527 const String& entry)
528 {
529 String optionString;
530
531 if (lookupValue(name, optionString) && optionString == value)
532 if (optionString.find(entry)
533 return 1;
534 else
535 return PEG_NOT_FOUND;
536 }
537 */
538
539 Option* OptionManager::_lookupOptionByCommandLineOptionName(const String& name)
540 {
541 for (Uint32 i = 0; i < _options.size(); i++)
542 {
543 thilo.boehm 1.1 if (_options[i]->getCommandLineOptionName() == name)
544 return _options[i];
545 }
546
547 return 0;
548 }
549
550 void OptionManager::print() const
551 {
552 for (Uint32 i = 0; i < _options.size(); i++)
553 {
554 Option* option = _options[i];
555 cout << option->getOptionName() << "=\"";
556 cout << option->getValue() << "\" ";
557 cout << option->getOptionHelpMessage() << "\n";
558 }
559 cout << endl;
560 }
561
562 void OptionManager::setMessagePath(String messagePath)
563 {
564 thilo.boehm 1.1 _msgPath = messagePath;
565 }
566 /* This is utility function to create help string for the option*/
567 String createOptionHelpString(Option* option)
568 {
569 String defMsg = " -";
570 defMsg.append(option->getCommandLineOptionName());
571 defMsg.append(" ");
572 defMsg.append(option->getOptionName());
573 defMsg.append(". ");
574 defMsg.append(option->getOptionHelpMessage());
575 defMsg.append(". Default(");
576 defMsg.append(option->getDefaultValue());
577 defMsg.append(")\n");
578 return defMsg;
579 }
580
581 void OptionManager::printOptionsHelp() const
582 {
583 for (Uint32 i = 0; i < _options.size(); i++)
584 {
585 thilo.boehm 1.1 String str;
586 Option* option = _options[i];
587 String defMsg = createOptionHelpString(option);
588 CString cstr = defMsg.getCString();
589 const String messageKey = option->getMessageKey();
590 CString msgKeyCString = messageKey.getCString();
591 if (String::compare(messageKey, String::EMPTY))
592 {
593 MessageLoaderParms parms(
594 (const char*)msgKeyCString,
595 (const char*)cstr);
596 parms.msg_src_path = _msgPath;
597 str = MessageLoader::getMessage(parms);
598 }
599 else
600 {
601 str = defMsg;
602 }
603 cout << str;
604 }
605 cout << endl;
606 thilo.boehm 1.1 }
607
608 void OptionManager::printOptionsHelpTxt(
609 const String& header,
610 const String& trailer) const
611 {
612 cout << "\n" << header << "\n";
613 printOptionsHelp();
614 cout << trailer << "\n";
615 }
616
617 ////////////////////////////////////////////////////////////////////////////////
618 //
619 // Option
620 //
621 ////////////////////////////////////////////////////////////////////////////////
622
623 Option::Option(
624 const String& optionName,
625 const String& defaultValue,
626 Boolean required,
627 thilo.boehm 1.1 Type type,
628 const Array<String>& domain,
629 const String& commandLineOptionName,
630 const String& optionHelpMessage,
631 const String& messageKey)
632 :
633 _optionName(optionName),
634 _defaultValue(defaultValue),
635 _value(defaultValue),
636 _required(required),
637 _type(type),
638 _domain(domain),
639 _commandLineOptionName(commandLineOptionName),
640 _optionHelpMessage(optionHelpMessage),
641 _messageKey(messageKey),
642 _resolved(false)
643 {
644 if (!isValid(_value))
645 throw OMInvalidOptionValue(_optionName, _value);
646 }
647
648 thilo.boehm 1.1 Option::Option(const Option& x)
649 :
650 _optionName(x._optionName),
651 _defaultValue(x._defaultValue),
652 _value(x._value),
653 _required(x._required),
654 _type(x._type),
655 _domain(x._domain),
656 _commandLineOptionName(x._commandLineOptionName),
657 _optionHelpMessage(x._optionHelpMessage),
658 _messageKey(x._messageKey)
659 {
660 }
661
662 Option::~Option()
663 {
664
665 }
666
667 Option& Option::operator=(const Option& x)
668 {
669 thilo.boehm 1.1 if (this != &x)
670 {
671 _optionName = x._optionName;
672 _defaultValue = x._defaultValue;
673 _value = x._value;
674 _required = x._required;
675 _type = x._type;
676 _domain = x._domain;
677 _commandLineOptionName = x._commandLineOptionName;
678 _optionHelpMessage = x._optionHelpMessage;
679 _messageKey = x._messageKey;
680 }
681 return *this;
682 }
683
684 Boolean Option::isValid(const String& value) const
685 {
686 // Check to see that the value is in the domain (if a domain was given)
687
688 Uint32 domainSize = _domain.size();
689
690 thilo.boehm 1.1 if (domainSize)
691 {
692 Boolean found = false;
693
694 for (Uint32 i = 0; i < domainSize; i++)
695 {
696 if (value == _domain[i])
697 found = true;
698 }
699
700 if (!found)
701 return false;
702 }
703
704 // Check the type:
705
706 switch (_type)
707 {
708 case BOOLEAN:
709 {
710 if (value == "true" || value == "false")
711 thilo.boehm 1.1 return true;
712 else
713 return false;
714 }
715
716 case STRING:
717 return true;
718
719 case INTEGER:
720 case NATURAL_NUMBER:
721 case WHOLE_NUMBER:
722 {
723 CString tmp = value.getCString();
724 char* end = 0;
725 long x = strtol(tmp, &end, 10);
726
727 if (!end || *end != '\0')
728 return false;
729
730 switch (_type)
731 {
732 thilo.boehm 1.1 case INTEGER:
733 return true;
734
735 case NATURAL_NUMBER:
736 return x >= 1;
737
738 case WHOLE_NUMBER:
739 return x >= 0;
740
741 default:
742 break;
743 }
744 }
745 }
746
747 // Unreachable!
748 return false;
749 }
750
751 ////////////////////////////////////////////////////////////////////////////////
752 //
753 thilo.boehm 1.1 // ConfigFileSyntaxError
754 //
755 ////////////////////////////////////////////////////////////////////////////////
756
757 String OMConfigFileSyntaxError::_formatMessage(
758 const String& file, Uint32 line)
759 {
760 char buffer[32];
761 sprintf(buffer, "%u", line);
762 MessageLoaderParms parms(
763 "Common.OptionManager.SYNTAX_ERR_CONFIG_FILE",
764 "Syntax error in configuration file: ");
765 String result = MessageLoader::getMessage(parms);
766 result.append(file);
767 result.append("(");
768 result.append(buffer);
769 result.append(")");
770 return result;
771 }
772
773 PEGASUS_NAMESPACE_END
|