1 karl 1.51 //%2006////////////////////////////////////////////////////////////////////////
|
2 karl 1.42 //
|
3 karl 1.46 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.42 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.46 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.47 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.51 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 karl 1.42 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.51 //
|
21 karl 1.42 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
|
31 a.arora 1.45 //
32 // Author: Mike Brasher (mbrasher@bmc.com)
33 //
34 // Modified By: Karl Schopmeyer(k.schopmeyer@opengroup.org)
35 // June 2001 - Extend help and print to include help description
36 // Feb 2002 - ad IsTrue
37 // Amit K Arora, IBM (amita@in.ibm.com) for PEP#101
|
38 david.dillard 1.48 // David Dillard, VERITAS Software Corp.
39 // (david.dillard@veritas.com)
|
40 a.arora 1.45 //
41 //%/////////////////////////////////////////////////////////////////////////////
42
43 #include <cstdlib>
44 #include <cctype>
45 #include <fstream>
46 #include <cstdio>
47 #include "OptionManager.h"
48 #include "FileSystem.h"
49
50 PEGASUS_USING_STD;
51
52 PEGASUS_NAMESPACE_BEGIN
53
54 ////////////////////////////////////////////////////////////////////////////////
55 //
56 // TODO: expand variables in the configuration file. For example:
57 //
58 // provider_dir = "${home}/providers"
59 //
60 ////////////////////////////////////////////////////////////////////////////////
61 a.arora 1.45
62 ////////////////////////////////////////////////////////////////////////////////
63 //
64 // Option
65 //
66 ////////////////////////////////////////////////////////////////////////////////
67
68 const Array<String>& Option::getDomain() const
69 {
70 return _domain;
71 }
72
73 void Option::setDomain(const Array<String>& domain)
74 {
75 _domain = domain;
76 }
77
78 ////////////////////////////////////////////////////////////////////////////////
79 //
80 // OptionManager
81 //
82 a.arora 1.45 ////////////////////////////////////////////////////////////////////////////////
83
84 OptionManager::OptionManager()
85 {
86
87 }
88
89 OptionManager::~OptionManager()
90 {
91 // Delete all options in the list:
92
93 for (Uint32 i = 0; i < _options.size(); i++)
94 delete _options[i];
95 }
96
|
97 david.dillard 1.48 void OptionManager::registerOption(Option* option)
|
98 a.arora 1.45 {
99 if (!option)
100 throw NullPointer();
101
102 if (lookupOption(option->getOptionName()))
103 throw OMDuplicateOption(option->getOptionName());
104
105 _options.append(option);
106 }
107
108
109 void OptionManager::registerOptions(OptionRow* optionRow, Uint32 numOptions)
110 {
111 for (Uint32 i = 0; i < numOptions; i++)
112 {
113 // Get option name:
114
115 if (!optionRow[i].optionName)
116 throw NullPointer();
117
118 String optionName = optionRow[i].optionName;
119 a.arora 1.45
120 // Get default value:
121
122 String defaultValue;
123
124 if (optionRow[i].defaultValue)
125 defaultValue = optionRow[i].defaultValue;
126
127 // Get the required flag:
128
129 Boolean required = optionRow[i].required != 0;
130
131 // Get the type:
132
133 Option::Type type = optionRow[i].type;
134
135 // Get the domain:
136
137 Array<String> domain;
138
139 if (optionRow[i].domain)
140 a.arora 1.45 {
141 Uint32 domainSize = optionRow[i].domainSize;
142
143 for (Uint32 j = 0; j < domainSize; j++)
144 domain.append(optionRow[i].domain[j]);
145 }
146
147 // Get commandLineOptionName:
148
149 String commandLineOptionName;
150
151 if (optionRow[i].commandLineOptionName)
152 commandLineOptionName = optionRow[i].commandLineOptionName;
153
154 // get optionHelp Message String
155
156 String optionHelpMessage;
157
158 if (optionRow[i].optionHelpMessage)
159 optionHelpMessage = optionRow[i].optionHelpMessage;
160
161 a.arora 1.45 // Add the option:
162
163 Option* option = new Option(
164 optionName,
165 defaultValue,
166 required,
167 type,
168 domain,
169 commandLineOptionName,
170 optionHelpMessage);
171
172 registerOption(option);
173 }
174 }
175
176 void OptionManager::mergeCommandLine(int& argc, char**& argv, Boolean abortOnErr)
177 {
178 for (int i = 0; i < argc; )
179 {
180 // Check for -option:
181
182 a.arora 1.45 const char* arg = argv[i];
183
184 if (*arg == '-')
185 {
186 // Look for the option:
187
188 Option* option = _lookupOptionByCommandLineOptionName(arg + 1);
189
190 if (!option)
191 {
192 if (abortOnErr)
193 {
|
194 david.dillard 1.48 throw OMMBadCmdLineOption(arg);
|
195 a.arora 1.45 }
196 else
197 {
198 i++;
199 continue;
200 }
201 }
202
203 // Get the option argument if any:
204
205 const char* optionArgument = "true";
206
207 if (option->getType() != Option::BOOLEAN)
208 {
209 if (i + 1 == argc)
210 throw OMMissingCommandLineOptionArgument(arg);
211
212 optionArgument = argv[i + 1];
213 }
214
215 // Validate the value:
216 a.arora 1.45
217 if (!option->isValid(optionArgument))
218 throw OMInvalidOptionValue(arg, optionArgument);
219
220 // Set the value:
221
222 option->setValue(optionArgument);
223
224 // Remove the option and its argument from the command line:
225
226 if (option->getType() == Option::BOOLEAN)
227 {
228 memmove(&argv[i], &argv[i + 1], (argc-i) * sizeof(char*));
229 argc--;
230 }
231 else
232 {
233 memmove(&argv[i], &argv[i + 2], (argc-i-1) * sizeof(char*));
234 argc -= 2;
235 }
236 }
237 a.arora 1.45 else
238 i++;
239 }
240 }
241
242 void OptionManager::mergeFile(const String& fileName)
243 {
244 // Open the input file:
245 #if defined(PEGASUS_OS_OS400)
246 ifstream is(fileName.getCString(),PEGASUS_STD(_CCSID_T(1208)));
247 #else
248 ifstream is(fileName.getCString());
249 #endif
250
251 if (!is)
252 throw NoSuchFile(fileName);
253
254 // For each line of the file:
255
256 String line;
257
258 a.arora 1.45 for (Uint32 lineNumber = 1; GetLine(is, line); lineNumber++)
259 {
260 // -- Get the identifier and value:
261
262 if (line[0] == '#')
263 continue;
264
265 // Skip leading whitespace:
266
267 const Char16* p = line.getChar16Data();
268
269 while (*p && isspace(*p))
270 p++;
271
272 if (!*p)
273 continue;
274
275 if (*p == '#')
276 continue;
277
278 // Get the identifier:
279 a.arora 1.45
280 String ident;
281
282 if (!(isalpha(*p) || *p == '_'))
283 throw OMConfigFileSyntaxError(fileName, lineNumber);
284
285 ident.append(*p++);
286
287 while (isalnum(*p) || *p == '_')
288 ident.append(*p++);
289
290 // Skip whitespace after identifier:
291
292 while (*p && isspace(*p))
293 p++;
294
295 // Expect an equal sign:
296
297 if (*p != '=')
298 throw OMConfigFileSyntaxError(fileName, lineNumber);
299 p++;
300 a.arora 1.45
301 // Skip whitespace after equal sign:
302
303 while (*p && isspace(*p))
304 p++;
305
306 // Expect open quote:
307
308 if (*p != '"')
309 throw OMConfigFileSyntaxError(fileName, lineNumber);
310 p++;
311
312 // Get the value:
313
314 String value;
315
316 while (*p && *p != '"')
317 {
318 if (*p == '\\')
319 {
320 p++;
321 a.arora 1.45
322 switch (*p)
323 {
|
324 david.dillard 1.48 case 'n':
325 value.append('\n');
|
326 a.arora 1.45 break;
|
327 david.dillard 1.48
|
328 a.arora 1.45 case 'r':
329 value.append('\r');
330 break;
331
332 case 't':
333 value.append('\t');
334 break;
335
336 case 'f':
337 value.append('\f');
338 break;
339
340 case '"':
341 value.append('"');
342 break;
343
344 case '\0':
345 throw OMConfigFileSyntaxError(fileName, lineNumber);
346
347 default:
348 value.append(*p);
349 a.arora 1.45 }
350 p++;
351 }
352 else
353 value.append(*p++);
354 }
355
356
357 // Expect close quote:
358
359 if (*p != '"')
360 throw OMConfigFileSyntaxError(fileName, lineNumber);
361 p++;
362
363 // Skip whitespace through end of line:
364
365 while (*p && isspace(*p))
366 p++;
367
368 if (*p)
369 throw OMConfigFileSyntaxError(fileName, lineNumber);
370 a.arora 1.45
371 // Now that we have the identifier and value, merge it:
372
373 Option* option = (Option*)lookupOption(ident);
374
375 if (!option)
376 throw OMUnrecognizedConfigFileOption(ident);
377
378 if (!option->isValid(value))
379 throw OMInvalidOptionValue(ident, value);
380
381 option->setValue(value);
382 }
383 }
384
385 void OptionManager::checkRequiredOptions() const
386 {
387 for (Uint32 i = 0; i < _options.size(); i++)
388 {
389 const Option* option = _options[i];
390
391 a.arora 1.45 if (option->getRequired() && !option->isResolved())
392 throw OMMissingRequiredOptionValue(option->getOptionName());
393 }
394 }
395
396 const Option* OptionManager::lookupOption(const String& name) const
397 {
398 for (Uint32 i = 0; i < _options.size(); i++)
399 {
400 if (_options[i]->getOptionName() == name)
401 return _options[i];
402 }
403
404 return 0;
405 }
406
407 Boolean OptionManager::lookupValue(const String& name, String& value) const
408 {
409 const Option* option = lookupOption(name);
410
411 if (!option)
412 a.arora 1.45 return false;
413
414 value = option->getValue();
415 return true;
416 }
417
418 Boolean OptionManager::lookupIntegerValue(const String& name, Uint32& value) const
419 {
420 //ATTN: KS P1 7 May 2002 - Add test for Integer type in om table.
421 String valueString;
422 if (lookupValue(name, valueString))
423 {
424 value = atol(valueString.getCString());
425 return true;
426 }
427 else
428 {
429 return false;
430 }
431
432 }
433 a.arora 1.45
|
434 david.dillard 1.48 Boolean OptionManager::valueEquals(const String& name, const String& value)
|
435 a.arora 1.45 const
436 {
437 String optionString;
438
439 return (lookupValue(name, optionString) && optionString == value) ? true : false;
440 }
441
442 Boolean OptionManager::isTrue(const String& name) const
443 {
|
444 david.dillard 1.48 //ATTN: KS 7 May 2002 P3 Add test to confirm boolean type
|
445 a.arora 1.45 return valueEquals(name, "true") ? true: false;
446 }
447 /* ATTN: P3 MB 2001 Buried this one for the moment to think about it.
|
448 david.dillard 1.48 Uint32 OptionManager::isStringInOptionMask(const String& option,
449 const String& entry)
|
450 a.arora 1.45 {
451 String optionString;
452
453 if (lookupValue(name, optionString) && optionString == value)
454 if (optionString.find(entry)
455 return 1;
456 else
457 return PEG_NOT_FOUND;
458 }
459 */
460
461 Option* OptionManager::_lookupOptionByCommandLineOptionName(const String& name)
462 {
463 for (Uint32 i = 0; i < _options.size(); i++)
464 {
465 if (_options[i]->getCommandLineOptionName() == name)
466 return _options[i];
467 }
468
469 return 0;
470 }
471 a.arora 1.45
472 void OptionManager::print() const
473 {
474 for (Uint32 i = 0; i < _options.size(); i++)
475 {
476 Option* option = _options[i];
477 cout << option->getOptionName() << "=\"";
478 cout << option->getValue() << "\" ";
479 cout << option->getOptionHelpMessage() << "\n";
480 }
481 cout << endl;
482 }
483
484 void OptionManager::printOptionsHelp() const
485 {
486 for (Uint32 i = 0; i < _options.size(); i++)
487 {
488 Option* option = _options[i];
489 cout << " -";
490 cout << option->getCommandLineOptionName() << " ";
491 cout << option->getOptionName() << ". ";
492 a.arora 1.45 cout << option->getOptionHelpMessage();
493 cout << ". Default(" << option->getDefaultValue() << ")\n";
494 }
495 cout << endl;
496
497 }
498
499 void OptionManager::printOptionsHelpTxt(const String& header, const String& trailer) const
500 {
501 cout << "\n" << header << "\n";
502 printOptionsHelp();
503 cout << trailer << "\n";
504 }
505
506 ////////////////////////////////////////////////////////////////////////////////
507 //
508 // Option
509 //
510 ////////////////////////////////////////////////////////////////////////////////
511
512 Option::Option(
513 a.arora 1.45 const String& optionName,
514 const String& defaultValue,
515 Boolean required,
516 Type type,
517 const Array<String>& domain,
518 const String& commandLineOptionName,
519 const String& optionHelpMessage)
520 :
521 _optionName(optionName),
522 _defaultValue(defaultValue),
523 _value(defaultValue),
524 _required(required),
525 _type(type),
526 _domain(domain),
527 _commandLineOptionName(commandLineOptionName),
528 _optionHelpMessage(optionHelpMessage),
529 _resolved(false)
530 {
531 if (!isValid(_value))
532 throw OMInvalidOptionValue(_optionName, _value);
533 }
534 a.arora 1.45
|
535 david.dillard 1.48 Option::Option(const Option& x)
|
536 a.arora 1.45 :
537 _optionName(x._optionName),
538 _defaultValue(x._defaultValue),
539 _value(x._value),
540 _required(x._required),
541 _type(x._type),
542 _domain(x._domain),
543 _commandLineOptionName(x._commandLineOptionName),
544 _optionHelpMessage(x._optionHelpMessage)
545
546 {
547 }
548
549 Option::~Option()
550 {
551
552 }
553
554 Option& Option::operator=(const Option& x)
555 {
556 if (this != &x)
557 a.arora 1.45 {
558 _optionName = x._optionName;
559 _defaultValue = x._defaultValue;
560 _value = x._value;
561 _required = x._required;
562 _type = x._type;
563 _domain = x._domain;
564 _commandLineOptionName = x._commandLineOptionName;
565 _optionHelpMessage = x._optionHelpMessage;
566 }
567 return *this;
568 }
569
570 Boolean Option::isValid(const String& value) const
571 {
572 // Check to see that the value is in the domain (if a domain was given)
573
574 Uint32 domainSize = _domain.size();
575
576 if (domainSize)
577 {
578 a.arora 1.45 Boolean found = false;
579
580 for (Uint32 i = 0; i < domainSize; i++)
581 {
582 if (value == _domain[i])
583 found = true;
584 }
585
586 if (!found)
587 return false;
588 }
589
590 // Check the type:
591
592 switch (_type)
593 {
594 case BOOLEAN:
595 {
596 if (value == "true" || value == "false")
597 return true;
|
598 dave.sudlik 1.52 else
599 return false;
|
600 a.arora 1.45 }
601
602 case STRING:
603 return true;
604
605 case INTEGER:
606 case NATURAL_NUMBER:
607 case WHOLE_NUMBER:
608 {
609 CString tmp = value.getCString();
610 char* end = 0;
611 long x = strtol(tmp, &end, 10);
612
613 if (!end || *end != '\0')
614 return false;
615
616 switch (_type)
617 {
|
618 david.dillard 1.48 case INTEGER:
|
619 a.arora 1.45 return true;
620
621 case NATURAL_NUMBER:
622 return x >= 1;
623
624 case WHOLE_NUMBER:
625 return x >= 0;
626
627 default:
628 break;
629 }
630 }
631 }
632
633 // Unreachable!
|
634 dave.sudlik 1.52 return false;
|
635 a.arora 1.45 }
636
637 ////////////////////////////////////////////////////////////////////////////////
638 //
639 // ConfigFileSyntaxError
640 //
641 ////////////////////////////////////////////////////////////////////////////////
642
643 String OMConfigFileSyntaxError::_formatMessage(
644 const String& file, Uint32 line)
645 {
646 char buffer[32];
647 sprintf(buffer, "%d", line);
648 //l10n
649 MessageLoaderParms parms("Common.OptionManager.SYNTAX_ERR_CONFIG_FILE",
650 "Syntax error in configuration file: ");
651 String result = MessageLoader::getMessage(parms);
652 //String result = "Syntax error in configuration file: ";
653 result.append(file);
654 result.append("(");
655 result.append(buffer);
656 a.arora 1.45 result.append(")");
657 return result;
658 }
659
660 PEGASUS_NAMESPACE_END
|