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
|
285 thilo.boehm 1.1 }
286 else
287 {
288 i++;
289 continue;
290 }
291 }
292
293 // Get the option argument if any:
294
295 const char* optionArgument = "true";
296
297 if (option->getType() != Option::BOOLEAN)
298 {
299 if (i + 1 == argc)
300 throw OMMissingCommandLineOptionArgument(arg);
301
302 optionArgument = argv[i + 1];
303 }
304
305 // Validate the value:
306 thilo.boehm 1.1
307 if (!option->isValid(optionArgument))
308 throw OMInvalidOptionValue(arg, optionArgument);
309
310 // Set the value:
311
312 option->setValue(optionArgument);
313
314 // Remove the option and its argument from the command line:
315
316 if (option->getType() == Option::BOOLEAN)
317 {
318 memmove(&argv[i], &argv[i + 1], (argc-i) * sizeof(char*));
319 argc--;
320 }
321 else
322 {
323 memmove(&argv[i], &argv[i + 2], (argc-i-1) * sizeof(char*));
324 argc -= 2;
325 }
326 }
327 thilo.boehm 1.1 else
328 i++;
329 }
330 }
331
332 void OptionManager::mergeFile(const String& fileName)
333 {
334 // Open the input file:
335 ifstream is(fileName.getCString());
336
337 if (!is)
338 throw NoSuchFile(fileName);
339
340 // For each line of the file:
341
342 String line;
343
344 for (Uint32 lineNumber = 1; GetLine(is, line); lineNumber++)
345 {
346 // -- Get the identifier and value:
347
348 thilo.boehm 1.1 if (line[0] == '#')
349 continue;
350
351 // Skip leading whitespace:
352
353 const Char16* p = line.getChar16Data();
354
355 while (*p && isspace(*p))
356 p++;
357
358 if (!*p)
359 continue;
360
361 if (*p == '#')
362 continue;
363
364 // Get the identifier:
365
366 String ident;
367
368 if (!(isalpha(*p) || *p == '_'))
369 thilo.boehm 1.1 throw OMConfigFileSyntaxError(fileName, lineNumber);
370
371 ident.append(*p++);
372
373 while (isalnum(*p) || *p == '_')
374 ident.append(*p++);
375
376 // Skip whitespace after identifier:
377
378 while (*p && isspace(*p))
379 p++;
380
381 // Expect an equal sign:
382
383 if (*p != '=')
384 throw OMConfigFileSyntaxError(fileName, lineNumber);
385 p++;
386
387 // Skip whitespace after equal sign:
388
389 while (*p && isspace(*p))
390 thilo.boehm 1.1 p++;
391
392 // Expect open quote:
393
394 if (*p != '"')
395 throw OMConfigFileSyntaxError(fileName, lineNumber);
396 p++;
397
398 // Get the value:
399
400 String value;
401
402 while (*p && *p != '"')
403 {
404 if (*p == '\\')
405 {
406 p++;
407
408 switch (*p)
409 {
410 case 'n':
411 thilo.boehm 1.1 value.append('\n');
412 break;
413
414 case 'r':
415 value.append('\r');
416 break;
417
418 case 't':
419 value.append('\t');
420 break;
421
422 case 'f':
423 value.append('\f');
424 break;
425
426 case '"':
427 value.append('"');
428 break;
429
430 case '\0':
431 throw OMConfigFileSyntaxError(fileName, lineNumber);
432 thilo.boehm 1.1
433 default:
434 value.append(*p);
435 }
436 p++;
437 }
438 else
439 value.append(*p++);
440 }
441
442
443 // Expect close quote:
444
445 if (*p != '"')
446 throw OMConfigFileSyntaxError(fileName, lineNumber);
447 p++;
448
449 // Skip whitespace through end of line:
450
451 while (*p && isspace(*p))
452 p++;
453 thilo.boehm 1.1
454 if (*p)
455 throw OMConfigFileSyntaxError(fileName, lineNumber);
456
457 // Now that we have the identifier and value, merge it:
458
459 Option* option = (Option*)lookupOption(ident);
460
461 if (!option)
462 throw OMUnrecognizedConfigFileOption(ident);
463
464 if (!option->isValid(value))
465 throw OMInvalidOptionValue(ident, value);
466
467 option->setValue(value);
468 }
469 }
470
471 void OptionManager::checkRequiredOptions() const
472 {
473 for (Uint32 i = 0; i < _options.size(); i++)
474 thilo.boehm 1.1 {
475 const Option* option = _options[i];
476
477 if (option->getRequired() && !option->isResolved())
478 throw OMMissingRequiredOptionValue(option->getOptionName());
479 }
480 }
481
482 const Option* OptionManager::lookupOption(const String& name) const
483 {
484 for (Uint32 i = 0; i < _options.size(); i++)
485 {
486 if (_options[i]->getOptionName() == name)
487 return _options[i];
488 }
489
490 return 0;
491 }
492
493 Boolean OptionManager::lookupValue(const String& name, String& value) const
494 {
495 thilo.boehm 1.1 const Option* option = lookupOption(name);
496
497 if (!option)
498 return false;
499
500 value = option->getValue();
501 return true;
502 }
503
504 Boolean OptionManager::lookupIntegerValue(
505 const String& name,
506 Uint32& value) const
507 {
508 //ATTN: KS P1 7 May 2002 - Add test for Integer type in om table.
509 String valueString;
510 if (lookupValue(name, valueString))
511 {
512 value = atol(valueString.getCString());
513 return true;
514 }
515 else
516 thilo.boehm 1.1 {
517 return false;
518 }
519
520 }
521
522 Boolean OptionManager::valueEquals(
523 const String& name,
524 const String& value) const
525 {
526 String optionString;
527
528 return (lookupValue(name, optionString) && optionString == value);
529 }
530
531 Boolean OptionManager::isTrue(const String& name) const
532 {
533 //ATTN: KS 7 May 2002 P3 Add test to confirm boolean type
534 return valueEquals(name, "true") ? true: false;
535 }
536
537 thilo.boehm 1.1 /* ATTN: P3 MB 2001 Buried this one for the moment to think about it.
538 Uint32 OptionManager::isStringInOptionMask(
539 const String& option,
540 const String& entry)
541 {
542 String optionString;
543
544 if (lookupValue(name, optionString) && optionString == value)
545 if (optionString.find(entry)
546 return 1;
547 else
548 return PEG_NOT_FOUND;
549 }
550 */
551
552 Option* OptionManager::_lookupOptionByCommandLineOptionName(const String& name)
553 {
554 for (Uint32 i = 0; i < _options.size(); i++)
555 {
556 if (_options[i]->getCommandLineOptionName() == name)
557 return _options[i];
558 thilo.boehm 1.1 }
559
560 return 0;
561 }
562
563 void OptionManager::print() const
564 {
565 for (Uint32 i = 0; i < _options.size(); i++)
566 {
567 Option* option = _options[i];
568 cout << option->getOptionName() << "=\"";
569 cout << option->getValue() << "\" ";
570 cout << option->getOptionHelpMessage() << "\n";
571 }
572 cout << endl;
573 }
574
575 void OptionManager::setMessagePath(String messagePath)
576 {
577 _msgPath = messagePath;
578 }
579 thilo.boehm 1.1 /* This is utility function to create help string for the option*/
580 String createOptionHelpString(Option* option)
581 {
582 String defMsg = " -";
583 defMsg.append(option->getCommandLineOptionName());
584 defMsg.append(" ");
585 defMsg.append(option->getOptionName());
586 defMsg.append(". ");
587 defMsg.append(option->getOptionHelpMessage());
588 defMsg.append(". Default(");
589 defMsg.append(option->getDefaultValue());
590 defMsg.append(")\n");
591 return defMsg;
592 }
593
594 void OptionManager::printOptionsHelp() const
595 {
596 for (Uint32 i = 0; i < _options.size(); i++)
597 {
598 String str;
599 Option* option = _options[i];
600 thilo.boehm 1.1 String defMsg = createOptionHelpString(option);
601 CString cstr = defMsg.getCString();
602 const String messageKey = option->getMessageKey();
603 CString msgKeyCString = messageKey.getCString();
604 if (String::compare(messageKey, String::EMPTY))
605 {
606 MessageLoaderParms parms(
607 (const char*)msgKeyCString,
608 (const char*)cstr);
609 parms.msg_src_path = _msgPath;
610 str = MessageLoader::getMessage(parms);
611 }
612 else
613 {
614 str = defMsg;
615 }
616 cout << str;
617 }
618 cout << endl;
619 }
620
621 thilo.boehm 1.1 void OptionManager::printOptionsHelpTxt(
622 const String& header,
623 const String& trailer) const
624 {
625 cout << "\n" << header << "\n";
626 printOptionsHelp();
627 cout << trailer << "\n";
628 }
629
630 ////////////////////////////////////////////////////////////////////////////////
631 //
632 // Option
633 //
634 ////////////////////////////////////////////////////////////////////////////////
635
636 Option::Option(
637 const String& optionName,
638 const String& defaultValue,
639 Boolean required,
640 Type type,
641 const Array<String>& domain,
642 thilo.boehm 1.1 const String& commandLineOptionName,
643 const String& optionHelpMessage,
644 const String& messageKey)
645 :
646 _optionName(optionName),
647 _defaultValue(defaultValue),
648 _value(defaultValue),
649 _required(required),
650 _type(type),
651 _domain(domain),
652 _commandLineOptionName(commandLineOptionName),
653 _optionHelpMessage(optionHelpMessage),
654 _messageKey(messageKey),
655 _resolved(false)
656 {
657 if (!isValid(_value))
658 throw OMInvalidOptionValue(_optionName, _value);
659 }
660
661 Option::Option(const Option& x)
662 :
663 thilo.boehm 1.1 _optionName(x._optionName),
664 _defaultValue(x._defaultValue),
665 _value(x._value),
666 _required(x._required),
667 _type(x._type),
668 _domain(x._domain),
669 _commandLineOptionName(x._commandLineOptionName),
670 _optionHelpMessage(x._optionHelpMessage),
671 _messageKey(x._messageKey)
672 {
673 }
674
675 Option::~Option()
676 {
677
678 }
679
680 Option& Option::operator=(const Option& x)
681 {
682 if (this != &x)
683 {
684 thilo.boehm 1.1 _optionName = x._optionName;
685 _defaultValue = x._defaultValue;
686 _value = x._value;
687 _required = x._required;
688 _type = x._type;
689 _domain = x._domain;
690 _commandLineOptionName = x._commandLineOptionName;
691 _optionHelpMessage = x._optionHelpMessage;
692 _messageKey = x._messageKey;
693 }
694 return *this;
695 }
696
697 Boolean Option::isValid(const String& value) const
698 {
699 // Check to see that the value is in the domain (if a domain was given)
700
701 Uint32 domainSize = _domain.size();
702
703 if (domainSize)
704 {
705 thilo.boehm 1.1 Boolean found = false;
706
707 for (Uint32 i = 0; i < domainSize; i++)
708 {
709 if (value == _domain[i])
710 found = true;
711 }
712
713 if (!found)
714 return false;
715 }
716
717 // Check the type:
718
719 switch (_type)
720 {
721 case BOOLEAN:
722 {
723 if (value == "true" || value == "false")
724 return true;
725 else
726 thilo.boehm 1.1 return false;
727 }
728
729 case STRING:
730 return true;
731
732 case INTEGER:
733 case NATURAL_NUMBER:
734 case WHOLE_NUMBER:
735 {
736 CString tmp = value.getCString();
737 char* end = 0;
738 long x = strtol(tmp, &end, 10);
739
740 if (!end || *end != '\0')
741 return false;
742
743 switch (_type)
744 {
745 case INTEGER:
746 return true;
747 thilo.boehm 1.1
748 case NATURAL_NUMBER:
749 return x >= 1;
750
751 case WHOLE_NUMBER:
752 return x >= 0;
753
754 default:
755 break;
756 }
757 }
758 }
759
760 // Unreachable!
761 return false;
762 }
763
764 ////////////////////////////////////////////////////////////////////////////////
765 //
766 // ConfigFileSyntaxError
767 //
768 thilo.boehm 1.1 ////////////////////////////////////////////////////////////////////////////////
769
770 String OMConfigFileSyntaxError::_formatMessage(
771 const String& file, Uint32 line)
772 {
773 char buffer[32];
774 sprintf(buffer, "%u", line);
775 MessageLoaderParms parms(
776 "Common.OptionManager.SYNTAX_ERR_CONFIG_FILE",
777 "Syntax error in configuration file: ");
778 String result = MessageLoader::getMessage(parms);
779 result.append(file);
780 result.append("(");
781 result.append(buffer);
782 result.append(")");
783 return result;
784 }
785
786 PEGASUS_NAMESPACE_END
|