1/* $Id: CoinParam.cpp 1448 2011-06-19 15:34:41Z stefan $ */
2// Copyright (C) 2006, International Business Machines
3// Corporation and others. All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#include <string>
7#include <cassert>
8#include <iostream>
9
10#include "CoinPragma.hpp"
11#include "CoinParam.hpp"
12
13/*
14 Constructors and destructors
15
16 There's a generic constructor and one for integer, double, keyword, string,
17 and action parameters.
18*/
19
20/*
21 Default constructor.
22*/
23CoinParam::CoinParam ()
24 : type_(coinParamInvalid),
25 name_(),
26 lengthName_(0),
27 lengthMatch_(0),
28 lowerDblValue_(0.0),
29 upperDblValue_(0.0),
30 dblValue_(0.0),
31 lowerIntValue_(0),
32 upperIntValue_(0),
33 intValue_(0),
34 strValue_(),
35 definedKwds_(),
36 currentKwd_(-1),
37 pushFunc_(0),
38 pullFunc_(0),
39 shortHelp_(),
40 longHelp_(),
41 display_(false)
42{
43 /* Nothing to be done here */
44}
45
46
47/*
48 Constructor for double parameter
49*/
50CoinParam::CoinParam (std::string name, std::string help,
51 double lower, double upper, double dflt, bool display)
52 : type_(coinParamDbl),
53 name_(name),
54 lengthName_(0),
55 lengthMatch_(0),
56 lowerDblValue_(lower),
57 upperDblValue_(upper),
58 dblValue_(dflt),
59 lowerIntValue_(0),
60 upperIntValue_(0),
61 intValue_(0),
62 strValue_(),
63 definedKwds_(),
64 currentKwd_(-1),
65 pushFunc_(0),
66 pullFunc_(0),
67 shortHelp_(help),
68 longHelp_(),
69 display_(display)
70{
71 processName() ;
72}
73
74/*
75 Constructor for integer parameter
76*/
77CoinParam::CoinParam (std::string name, std::string help,
78 int lower, int upper, int dflt, bool display)
79 : type_(coinParamInt),
80 name_(name),
81 lengthName_(0),
82 lengthMatch_(0),
83 lowerDblValue_(0.0),
84 upperDblValue_(0.0),
85 dblValue_(0.0),
86 lowerIntValue_(lower),
87 upperIntValue_(upper),
88 intValue_(dflt),
89 strValue_(),
90 definedKwds_(),
91 currentKwd_(-1),
92 pushFunc_(0),
93 pullFunc_(0),
94 shortHelp_(help),
95 longHelp_(),
96 display_(display)
97{
98 processName() ;
99}
100
101/*
102 Constructor for keyword parameter.
103*/
104CoinParam::CoinParam (std::string name, std::string help,
105 std::string firstValue, int dflt, bool display)
106 : type_(coinParamKwd),
107 name_(name),
108 lengthName_(0),
109 lengthMatch_(0),
110 lowerDblValue_(0.0),
111 upperDblValue_(0.0),
112 dblValue_(0.0),
113 lowerIntValue_(0),
114 upperIntValue_(0),
115 intValue_(0),
116 strValue_(),
117 definedKwds_(),
118 currentKwd_(dflt),
119 pushFunc_(0),
120 pullFunc_(0),
121 shortHelp_(help),
122 longHelp_(),
123 display_(display)
124{
125 processName() ;
126 definedKwds_.push_back(firstValue) ;
127}
128
129/*
130 Constructor for string parameter.
131*/
132CoinParam::CoinParam (std::string name, std::string help,
133 std::string dflt, bool display)
134 : type_(coinParamStr),
135 name_(name),
136 lengthName_(0),
137 lengthMatch_(0),
138 lowerDblValue_(0.0),
139 upperDblValue_(0.0),
140 dblValue_(0.0),
141 lowerIntValue_(0),
142 upperIntValue_(0),
143 intValue_(0),
144 strValue_(dflt),
145 definedKwds_(),
146 currentKwd_(0),
147 pushFunc_(0),
148 pullFunc_(0),
149 shortHelp_(help),
150 longHelp_(),
151 display_(display)
152{
153 processName() ;
154}
155
156/*
157 Constructor for action parameter.
158*/
159CoinParam::CoinParam (std::string name, std::string help, bool display)
160 : type_(coinParamAct),
161 name_(name),
162 lengthName_(0),
163 lengthMatch_(0),
164 lowerDblValue_(0.0),
165 upperDblValue_(0.0),
166 dblValue_(0.0),
167 lowerIntValue_(0),
168 upperIntValue_(0),
169 intValue_(0),
170 strValue_(),
171 definedKwds_(),
172 currentKwd_(0),
173 pushFunc_(0),
174 pullFunc_(0),
175 shortHelp_(help),
176 longHelp_(),
177 display_(display)
178{
179 processName() ;
180}
181
182/*
183 Copy constructor.
184*/
185CoinParam::CoinParam (const CoinParam &orig)
186 : type_(orig.type_),
187 lengthName_(orig.lengthName_),
188 lengthMatch_(orig.lengthMatch_),
189 lowerDblValue_(orig.lowerDblValue_),
190 upperDblValue_(orig.upperDblValue_),
191 dblValue_(orig.dblValue_),
192 lowerIntValue_(orig.lowerIntValue_),
193 upperIntValue_(orig.upperIntValue_),
194 intValue_(orig.intValue_),
195 currentKwd_(orig.currentKwd_),
196 pushFunc_(orig.pushFunc_),
197 pullFunc_(orig.pullFunc_),
198 display_(orig.display_)
199{
200 name_ = orig.name_ ;
201 strValue_ = orig.strValue_ ;
202 definedKwds_ = orig.definedKwds_ ;
203 shortHelp_ = orig.shortHelp_ ;
204 longHelp_ = orig.longHelp_ ;
205}
206
207/*
208 Clone
209*/
210
211CoinParam *CoinParam::clone ()
212{
213 return (new CoinParam(*this)) ;
214}
215
216CoinParam &CoinParam::operator= (const CoinParam &rhs)
217{
218 if (this != &rhs)
219 { type_ = rhs.type_ ;
220 name_ = rhs.name_ ;
221 lengthName_ = rhs.lengthName_ ;
222 lengthMatch_ = rhs.lengthMatch_ ;
223 lowerDblValue_ = rhs.lowerDblValue_ ;
224 upperDblValue_ = rhs.upperDblValue_ ;
225 dblValue_ = rhs.dblValue_ ;
226 lowerIntValue_ = rhs.lowerIntValue_ ;
227 upperIntValue_ = rhs.upperIntValue_ ;
228 intValue_ = rhs.intValue_ ;
229 strValue_ = rhs.strValue_ ;
230 definedKwds_ = rhs.definedKwds_ ;
231 currentKwd_ = rhs.currentKwd_ ;
232 pushFunc_ = rhs.pushFunc_ ;
233 pullFunc_ = rhs.pullFunc_ ;
234 shortHelp_ = rhs.shortHelp_ ;
235 longHelp_ = rhs.longHelp_ ;
236 display_ = rhs.display_ ; }
237
238 return *this ; }
239
240/*
241 Destructor
242*/
243CoinParam::~CoinParam ()
244{ /* Nothing more to do */ }
245
246
247/*
248 Methods to manipulate a CoinParam object.
249*/
250
251/*
252 Process the parameter name.
253
254 Process the name for efficient matching: determine if an `!' is present. If
255 so, locate and record the position and remove the `!'.
256*/
257
258void CoinParam::processName()
259
260{ std::string::size_type shriekPos = name_.find('!') ;
261 lengthName_ = name_.length() ;
262 if (shriekPos == std::string::npos)
263 { lengthMatch_ = lengthName_ ; }
264 else
265 { lengthMatch_ = shriekPos ;
266 name_ = name_.substr(0,shriekPos)+name_.substr(shriekPos+1) ;
267 lengthName_-- ; }
268
269 return ; }
270
271/*
272 Check an input string to see if it matches the parameter name. The whole
273 input string must match, and the length of the match must exceed the
274 minimum match length. A match is impossible if the string is longer than
275 the name.
276
277 Returns: 0 for no match, 1 for a successful match, 2 if the match is short
278*/
279int CoinParam::matches (std::string input) const
280{
281 size_t inputLen = input.length() ;
282 if (inputLen <= lengthName_)
283 { size_t i ;
284 for (i = 0 ; i < inputLen ; i++)
285 { if (tolower(name_[i]) != tolower(input[i]))
286 break ; }
287 if (i < inputLen)
288 { return (0) ; }
289 else
290 if (i >= lengthMatch_)
291 { return (1) ; }
292 else
293 { return (2) ; } }
294
295 return (0) ;
296}
297
298
299/*
300 Return the parameter name, formatted to indicate how it'll be matched.
301 E.g., some!Name will come back as some(Name).
302*/
303std::string CoinParam::matchName () const
304{
305 if (lengthMatch_ == lengthName_)
306 { return name_ ; }
307 else
308 { return name_.substr(0,lengthMatch_)+"("+name_.substr(lengthMatch_)+")" ; }
309}
310
311
312/*
313 Print the long help message and a message about appropriate values.
314*/
315void CoinParam::printLongHelp() const
316{
317 if (longHelp_ != "")
318 { CoinParamUtils::printIt(longHelp_.c_str()) ; }
319 else
320 if (shortHelp_ != "")
321 { CoinParamUtils::printIt(shortHelp_.c_str()) ; }
322 else
323 { CoinParamUtils::printIt("No help provided.") ; }
324
325 switch (type_)
326 { case coinParamDbl:
327 { std::cout << "<Range of values is " << lowerDblValue_ << " to "
328 << upperDblValue_ << ";\n\tcurrent " << dblValue_ << ">"
329 << std::endl ;
330 assert (upperDblValue_>lowerDblValue_) ;
331 break ; }
332 case coinParamInt:
333 { std::cout << "<Range of values is " << lowerIntValue_ << " to "
334 << upperIntValue_ << ";\n\tcurrent " << intValue_ << ">"
335 << std::endl ;
336 assert (upperIntValue_>lowerIntValue_) ;
337 break ; }
338 case coinParamKwd:
339 { printKwds() ;
340 break ; }
341 case coinParamStr:
342 { std::cout << "<Current value is " ;
343 if (strValue_ == "")
344 { std::cout << "(unset)>" ; }
345 else
346 { std::cout << "`" << strValue_ << "'>" ; }
347 std::cout << std::endl ;
348 break ; }
349 case coinParamAct:
350 { break ; }
351 default:
352 { std::cout << "!! invalid parameter type !!" << std::endl ;
353 assert (false) ; } }
354}
355
356
357/*
358 Methods to manipulate the value of a parameter.
359*/
360
361/*
362 Methods to manipulate the values associated with a keyword parameter.
363*/
364
365/*
366 Add a keyword to the list for a keyword parameter.
367*/
368void CoinParam::appendKwd (std::string kwd)
369{
370 assert (type_ == coinParamKwd) ;
371
372 definedKwds_.push_back(kwd) ;
373}
374
375/*
376 Scan the keywords of a keyword parameter and return the integer index of
377 the keyword matching the input, or -1 for no match.
378*/
379int CoinParam::kwdIndex (std::string input) const
380{
381 assert (type_ == coinParamKwd) ;
382
383 int whichItem = -1 ;
384 size_t numberItems = definedKwds_.size() ;
385 if (numberItems > 0)
386 { size_t inputLen = input.length() ;
387 size_t it ;
388/*
389 Open a loop to check each keyword against the input string. We don't record
390 the match length for keywords, so we need to check each one for an `!' and
391 do the necessary preprocessing (record position and elide `!') before
392 checking for a match of the required length.
393*/
394 for (it = 0 ; it < numberItems ; it++)
395 { std::string kwd = definedKwds_[it] ;
396 std::string::size_type shriekPos = kwd.find('!') ;
397 size_t kwdLen = kwd.length() ;
398 size_t matchLen = kwdLen ;
399 if (shriekPos != std::string::npos)
400 { matchLen = shriekPos ;
401 kwd = kwd.substr(0,shriekPos)+kwd.substr(shriekPos+1) ;
402 kwdLen = kwd.length() ; }
403/*
404 Match is possible only if input is shorter than the keyword. The entire input
405 must match and the match must exceed the minimum length.
406*/
407 if (inputLen <= kwdLen)
408 { unsigned int i ;
409 for (i = 0 ; i < inputLen ; i++)
410 { if (tolower(kwd[i]) != tolower(input[i]))
411 break ; }
412 if (i >= inputLen && i >= matchLen)
413 { whichItem = static_cast<int>(it) ;
414 break ; } } } }
415
416 return (whichItem) ;
417}
418
419/*
420 Set current value for a keyword parameter using a string.
421*/
422void CoinParam::setKwdVal (const std::string value)
423{
424 assert (type_ == coinParamKwd) ;
425
426 int action = kwdIndex(value) ;
427 if (action >= 0)
428 { currentKwd_ = action ; }
429}
430
431/*
432 Set current value for keyword parameter using an integer. Echo the new value
433 to cout if requested.
434*/
435void CoinParam::setKwdVal (int value, bool printIt)
436{
437 assert (type_ == coinParamKwd) ;
438 assert (value >= 0 && unsigned(value) < definedKwds_.size()) ;
439
440 if (printIt && value != currentKwd_)
441 { std::cout << "Option for " << name_ << " changed from "
442 << definedKwds_[currentKwd_] << " to "
443 << definedKwds_[value] << std::endl ; }
444
445 currentKwd_ = value ;
446}
447
448/*
449 Return the string corresponding to the current value.
450*/
451std::string CoinParam::kwdVal() const
452{
453 assert (type_ == coinParamKwd) ;
454
455 return (definedKwds_[currentKwd_]) ;
456}
457
458/*
459 Print the keywords for a keyword parameter, formatted to indicate how they'll
460 be matched. (E.g., some!Name prints as some(Name).). Follow with current
461 value.
462*/
463void CoinParam::printKwds () const
464{
465 assert (type_ == coinParamKwd) ;
466
467 std::cout << "Possible options for " << name_ << " are:" ;
468 unsigned int it ;
469 int maxAcross = 5 ;
470 for (it = 0 ; it < definedKwds_.size() ; it++)
471 { std::string kwd = definedKwds_[it] ;
472 std::string::size_type shriekPos = kwd.find('!') ;
473 if (shriekPos != std::string::npos)
474 { kwd = kwd.substr(0,shriekPos)+"("+kwd.substr(shriekPos+1)+")" ; }
475 if (it%maxAcross == 0)
476 { std::cout << std::endl ; }
477 std::cout << " " << kwd ; }
478 std::cout << std::endl ;
479
480 assert (currentKwd_ >= 0 && unsigned(currentKwd_) < definedKwds_.size()) ;
481
482 std::string current = definedKwds_[currentKwd_] ;
483 std::string::size_type shriekPos = current.find('!') ;
484 if (shriekPos != std::string::npos)
485 { current = current.substr(0,shriekPos)+
486 "("+current.substr(shriekPos+1)+")" ; }
487 std::cout << " <current: " << current << ">" << std::endl ;
488}
489
490
491/*
492 Methods to manipulate the value of a string parameter.
493*/
494
495void CoinParam::setStrVal (std::string value)
496{
497 assert (type_ == coinParamStr) ;
498
499 strValue_ = value ;
500}
501
502std::string CoinParam::strVal () const
503{
504 assert (type_ == coinParamStr) ;
505
506 return (strValue_) ;
507}
508
509
510/*
511 Methods to manipulate the value of a double parameter.
512*/
513
514void CoinParam::setDblVal (double value)
515{
516 assert (type_ == coinParamDbl) ;
517
518 dblValue_ = value ;
519}
520
521double CoinParam::dblVal () const
522{
523 assert (type_ == coinParamDbl) ;
524
525 return (dblValue_) ;
526}
527
528
529/*
530 Methods to manipulate the value of an integer parameter.
531*/
532
533void CoinParam::setIntVal (int value)
534{
535 assert (type_ == coinParamInt) ;
536
537 intValue_ = value ;
538}
539
540int CoinParam::intVal () const
541{
542 assert (type_ == coinParamInt) ;
543
544 return (intValue_) ;
545}
546
547/*
548 A print function (friend of the class)
549*/
550
551std::ostream &operator<< (std::ostream &s, const CoinParam &param)
552{
553 switch (param.type())
554 { case CoinParam::coinParamDbl:
555 { return (s << param.dblVal()) ; }
556 case CoinParam::coinParamInt:
557 { return (s << param.intVal()) ; }
558 case CoinParam::coinParamKwd:
559 { return (s << param.kwdVal()) ; }
560 case CoinParam::coinParamStr:
561 { return (s << param.strVal()) ; }
562 case CoinParam::coinParamAct:
563 { return (s << "<evokes action>") ; }
564 default:
565 { return (s << "!! invalid parameter type !!") ; } }
566}
567