1 /*  _________________________________________________________________________
2  *
3  *  UTILIB: A utility library for developing portable C++ codes.
4  *  Copyright (c) 2008 Sandia Corporation.
5  *  This software is distributed under the BSD License.
6  *  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7  *  the U.S. Government retains certain rights in this software.
8  *  For more information, see the README file in the top UTILIB directory.
9  *  _________________________________________________________________________
10  */
11 
12 #include <utilib/OptionParser.h>
13 #include <utilib/TypeManager.h>
14 #include <utilib/sort.h>
15 #include <utilib/TinyXML_helper.h>
16 #include <utilib/Property.h>
17 
18 #include <sstream>
19 #include <set>
20 
21 using std::map;
22 using std::string;
23 
24 namespace utilib
25 {
26 
merge_options(const OptionParser & options)27 void OptionParser::merge_options(const OptionParser& options)
28 {
29 std::set<data_t>::const_iterator curr = options.parameter_data.begin();
30 std::set<data_t>::const_iterator end  = options.parameter_data.end();
31 while (curr != end) {
32   add_parameter(*curr);
33   curr++;
34 }
35 }
36 
37 
categorize(const std::string & _name,const std::string & category)38 void OptionParser::categorize(const std::string& _name, const std::string& category)
39 {
40    map<string, std::set<data_t> >::iterator curr = categories.find(category);
41    if (curr == categories.end())
42    {
43       categories[category] = std::set<data_t>();
44       curr = categories.find(category);
45    }
46    std::string name = standardize(_name);
47    bool posix = name.size() == 1;
48    data_t tmp = get_param_any(name.c_str(),posix);
49    tmp().categories.insert(category);
50    curr->second.insert(tmp);
51 }
52 
53 
alias(const string & _name,const string & _alias)54 void OptionParser::alias(const string& _name, const string& _alias)
55    {
56    std::string name = standardize(_name);
57    std::string alias = standardize(_alias);
58    bool posix = name.size() == 1;
59    data_t tmp = get_param_any(name.c_str(),posix);
60 
61    if (alias.size() == 1)
62       posix_parameters[alias[0]] = tmp;
63    else
64       parameters[alias] = tmp;
65    tmp().aliases.insert(alias);
66 }
67 
68 
initialized(const std::string & _name)69 bool OptionParser::initialized(const std::string& _name)
70 {
71    std::string name = standardize(_name);
72    bool posix = name.size() == 1;
73    data_t tmp = get_param_any(name.c_str(),posix);
74    return tmp().initialized;
75 }
76 
77 
disable(std::string _name)78 void OptionParser::disable(std::string _name)
79 {
80    std::string name = standardize(_name);
81    bool posix = name.size() == 1;
82    data_t tmp = get_param_any(name.c_str(),posix,false);
83    tmp().disabled = true;
84 }
85 
86 
enable(std::string _name)87 void OptionParser::enable(std::string _name)
88 {
89    std::string name = standardize(_name);
90    bool posix = name.size() == 1;
91    data_t tmp = get_param_any(name.c_str(),posix,false);
92    tmp().disabled = false;
93 }
94 
95 
remove(std::string _name)96 void OptionParser::remove(std::string _name)
97 {
98    std::string name = standardize(_name);
99    bool posix = name.size() == 1;
100    data_t tmp = get_param_any(name.c_str(),posix);
101    Parameter& param = tmp();
102 
103    if (param.name.size() == 1)
104       posix_parameters.erase(param.short_name);
105    else
106       parameters.erase(param.name);
107    parameter_data.erase(tmp);
108    //
109    // Remove category data
110    //
111    std::set<std::string>::iterator curr = param.categories.begin();
112    std::set<std::string>::iterator end  = param.categories.end();
113    while (curr != end) {
114      categories[name].erase(tmp);
115      curr++;
116    }
117 }
118 
119 
remove(const Parameter & param)120 void OptionParser::remove(const Parameter& param)
121 {
122    if (param.short_name != 0)
123    {
124       map<char, data_t>::iterator s_it = posix_parameters.find(param.short_name);
125       if (s_it != posix_parameters.end()) posix_parameters.erase(s_it);
126       else EXCEPTION_MNGR(std::runtime_error, "Expected posix parameter " << param.short_name);
127    }
128    if (param.aliases.size() > 0)
129    {
130       std::set<std::string>::const_iterator curr = param.aliases.begin();
131       std::set<std::string>::const_iterator end  = param.aliases.end();
132       while (curr != end)
133       {
134          map<std::string, data_t>::iterator s_it = parameters.find(*curr);
135          if (s_it != parameters.end()) parameters.erase(s_it);
136          else EXCEPTION_MNGR(std::runtime_error, "Expected alias parameter " << *curr);
137          curr++;
138       }
139    }
140 //
141 // Erase parameter with long_name
142 //
143    {
144       map<std::string, data_t>::iterator s_it = parameters.find(param.name);
145       if (s_it != parameters.end()) parameters.erase(s_it);
146       else EXCEPTION_MNGR(std::runtime_error, "Expected parameter " << param.name);
147    }
148 //
149 // Erase parameter data
150 //
151 #if 0
152    WEH - TODO
153    {
154       std::set<data_t>::iterator s_it = parameter_data.find(param.name);
155       if (s_it != parameter_data.end()) parameter_data.erase(s_it);
156       else EXCEPTION_MNGR(std::runtime_error, "Expected parameter " << param.name);
157    }
158 #endif
159 }
160 
161 
162 #ifdef UTILIB_HAVE_TINYXML
process_xml(TiXmlElement * node,bool describe)163 void OptionParser::process_xml( TiXmlElement* node, bool describe )
164 {
165    if ( describe )
166    {
167       TiXmlElement *opt = new TiXmlElement("Option");
168       opt->SetAttribute("name", "string");
169       node->LinkEndChild(opt);
170       return;
171    }
172 
173    TiXmlElement* n = node->FirstChildElement();
174    for( ; n != NULL; n = n->NextSiblingElement() )
175    {
176       if ( n->ValueStr().compare("Option") != 0 )
177          EXCEPTION_MNGR(std::runtime_error, "OptionParser:process_xml - invalid element "
178                         << n->ValueStr() << " in " << get_element_info(n));
179       //std::cerr << "Elment info: " << n->ValueStr() << " in " << get_element_info(n) << std::endl;
180       string name = "";
181       get_string_attribute(n, "name", name);
182       const char* elt_data = n->GetText();
183       if (elt_data != 0)
184          set_parameter(name, elt_data);
185       else
186          set_parameter(name, "");
187    }
188 }
189 #endif
190 
191 
write(std::ostream & os,const std::set<std::string> & categories_requested,bool categorized) const192 void OptionParser::write(std::ostream& os, const std::set<std::string>& categories_requested, bool categorized) const
193 {
194    //
195    // Print usage
196    //
197    std::string indent = "                              ";
198    {
199       std::list<std::string>::const_iterator curr = usage.begin();
200       std::list<std::string>::const_iterator end  = usage.end();
201       while (curr != end)
202       {
203          std::string _usage = "Usage: ";
204          _usage += *curr;
205          wordwrap_printline(os, _usage, indent);
206          curr++;
207       }
208       wordwrap_printline(os, description, "");
209       os << std::endl;
210    }
211    if (categorized && (categories.size() > 0))
212    {
213       //
214       // Print options, grouped by categories
215       //
216       std::vector<std::string> cat;
217       cat.reserve(categories.size());
218       {
219          //
220          // Get the names of the categories
221          //
222          std::map<std::string, std::set<data_t> >::const_iterator curr = categories.begin();
223          std::map<std::string, std::set<data_t> >::const_iterator end  = categories.end();
224          while (curr != end)
225          {
226             if ((categories_requested.size() == 0) || (categories_requested.find(curr->first) != categories_requested.end())) {
227             if (curr->second.size() > 0)
228                cat.push_back(curr->first);
229             }
230             curr++;
231          }
232       }
233       sort(cat);
234       {
235          std::vector<std::string>::iterator curr = cat.begin();
236          std::vector<std::string>::iterator end  = cat.end();
237          while (curr != end)
238          {
239             os << " " << *curr << ":" << std::endl;
240             std::map<std::string, std::set<data_t> >::const_iterator tmp = categories.find(*curr);
241             write_parameter_set(os, tmp->second, indent);
242             os << std::endl;
243             curr++;
244          }
245       }
246       if (categories_requested.size() == 0) {
247          //
248          // If no categories are requested, then print an 'uncategorized options' category
249          //
250          std::set<data_t> uncat;
251          std::set<data_t>::const_iterator pcurr = parameter_data.begin();
252          std::set<data_t>::const_iterator pend  = parameter_data.end();
253          while (pcurr != pend) {
254         const Parameter& param = (*pcurr)();
255         if (param.categories.size() == 0)
256             uncat.insert(*pcurr);
257         pcurr++;
258         }
259             os << " uncategorized options:" << std::endl;
260             write_parameter_set(os, uncat, indent);
261             os << std::endl;
262       }
263 
264    }
265    else
266    {
267       // WEH - is this always an error?
268       if (categories_requested.size() > 0)
269             EXCEPTION_MNGR(std::runtime_error, "Although categories were specified for the output, the OptionParser object does not contain categorized options!");
270       //
271       // Print all options, without categories
272       //
273       os << "options:" << std::endl << std::endl;
274       write_parameter_set(os, parameter_data, indent);
275       os << std::endl;
276    }
277    if (arg_definitions.size() > 0)
278    {
279       os << "arguments:" << std::endl << std::endl;
280       {
281          std::list<std::pair<std::string, std::string> >::const_iterator curr = arg_definitions.begin();
282          std::list<std::pair<std::string, std::string> >::const_iterator end  = arg_definitions.end();
283          while (curr != end)
284          {
285             std::string tmp;
286             tmp = "  ";
287             tmp += curr->first;
288             tmp += ":  ";
289             tmp += curr->second;
290             wordwrap_printline(os, tmp, "      ");
291             os << std::endl;
292             curr++;
293          }
294       }
295    }
296 
297    if (epilog.size() > 0)
298    {
299       wordwrap_printline(os, epilog, "");
300    }
301 }
302 
303 
write_parameter_set(std::ostream & os,const std::set<data_t> & parameters,const string & indent) const304 void OptionParser::write_parameter_set(std::ostream& os, const std::set<data_t>& parameters, const string& indent) const
305    {
306       std::set<data_t>::const_iterator curr = parameters.begin();
307       std::set<data_t>::const_iterator end  = parameters.end();
308       while (curr != end)
309       {
310          const Parameter& param = (*curr)();
311          std::ostringstream tmp;
312          char sname = param.short_name;
313          if (sname == (char)0)
314             tmp << "    ";
315          else
316             tmp << "  -" << sname;
317          if (param.name != "")
318          {
319             if (sname == (char)0)
320                tmp << "  --" << param.name;
321             else
322                tmp << ", --" << param.name;
323          }
324          string str = tmp.str();
325          int tmplen = static_cast<int>(str.size());
326          if (tmplen < 30)
327          {
328             std::string line;
329             line = str;
330             for (int i = tmplen; i < 30; i++)
331                line += " ";
332             line += param.description;
333             wordwrap_printline(os, line, indent);
334          }
335          else
336          {
337             os << str << std::endl << indent;
338             wordwrap_printline(os, param.description, indent);
339          }
340          if (param.aliases.size() > 0) {
341             std::string line(30,' ');
342             line += "aliases:";
343             std::set<std::string>::const_iterator acurr = param.aliases.begin();
344             std::set<std::string>::const_iterator aend  = param.aliases.end();
345             while (acurr != aend) {
346             if (acurr->size() == 1)
347                 line += " -";
348             else
349                 line += " --";
350             line += *acurr;
351             acurr++;
352             }
353             wordwrap_printline(os, line, indent);
354          }
355          curr++;
356       }
357    }
358 
359 
360 //
write_xml(std::ostream &) const361 void OptionParser::write_xml(std::ostream& ) const
362 {
363 #ifdef UTILIB_HAVE_TINYXML
364 
365   /// TODO - how is this different from the write_values_xml() output?
366 
367 #else
368 
369   EXCEPTION_MNGR(std::runtime_error, "Cannot print XML information unless UTILIB is configured with TinyXML");
370 
371 #endif
372 }
373 
374 
375 //============================================================================
376 //
377 //
write_values(std::ostream & os,const std::string & opt_label) const378 void OptionParser::write_values(std::ostream& os, const std::string& opt_label) const
379 {
380    if (opt_label != "")
381       os << "# ---- Options for " << opt_label << " ----" << std::endl;
382 //
383 // Get the length of the longest parameter name
384 //
385    size_type len = 0;
386    std::set<data_t>::const_iterator tcurr = parameter_data.begin();
387    std::set<data_t>::const_iterator tlast = parameter_data.end();
388    while (tcurr != tlast)
389    {
390       const Parameter& param = (*tcurr)();
391       if (len < param.name.size())
392          len = param.name.size();
393       tcurr++;
394    }
395    if (len < 10) len = 10;
396    char tformat[32];
397 #ifdef _MSC_VER
398    sprintf_s(tformat, 32, "%%-%lds", (long int)len);
399 #else
400    sprintf(tformat, "%%-%lds", (long int)len);
401 #endif
402 //
403 //
404 //
405    std::set<data_t>::const_iterator curr = parameter_data.begin();
406    std::set<data_t>::const_iterator last = parameter_data.end();
407 
408    char tmp[128];
409    while (curr != last)
410    {
411       const Parameter& param = (*curr)();
412       if (!(param.disabled))
413       {
414          if (param.name.size() > 0)
415          {
416 #ifdef _MSC_VER
417             sprintf_s(tmp, 128, tformat, param.name.data());
418 #else
419             sprintf(tmp, tformat, param.name.data());
420 #endif
421          }
422          else
423          {
424             std::string tstr;
425             tstr += param.short_name;
426             tstr += "_option";
427 #ifdef _MSC_VER
428             sprintf_s(tmp, 128, tformat, tstr.c_str());
429 #else
430             sprintf(tmp, tformat, tstr.c_str());
431 #endif
432          }
433          os << tmp << " ";
434          std::ostringstream ostr;
435          ostr << param.info;
436          const std::string& output = ostr.str();
437          if (output.size() == 0)
438             os << "\"\"";
439          else if ( output.find(" ") != string::npos &&
440                    ! ( (output[0] == '"'  &&  *output.rbegin() == '"') ||
441                        (output[0] == '['  &&  *output.rbegin() == ']')
442 		       )
443 		   )
444             // Instead of explicitly testing for std::string and
445             // CharString, we will simply look for data with a space
446             // that is not already within quotes or look like a vector.
447             os << "\"" << output << "\"";
448          else
449             os << output;
450          if (!param.initialized)
451             os << "\t# default" << std::endl;
452          else
453             os << std::endl;
454       }
455       curr++;
456    }
457 }
458 
459 
460 #ifdef UTILIB_HAVE_TINYXML
write_values_xml(std::ostream & os) const461 void OptionParser::write_values_xml(std::ostream& os) const
462 {
463 
464   TiXmlElement* root = new TiXmlElement("Options");
465   std::set<data_t>::const_iterator curr = parameter_data.begin();
466   std::set<data_t>::const_iterator end  = parameter_data.end();
467   while (curr != end) {
468       const Parameter& param = (*curr)();
469       if (!(param.disabled)) {
470       TiXmlElement* option = new TiXmlElement("Option");
471       if (param.name != "")
472          option->SetAttribute("name",param.name);
473       else {
474          std::string tmp;
475          tmp += param.short_name;
476          option->SetAttribute("name",tmp);
477          }
478       int default_val = !(param.initialized);
479       option->SetAttribute("default",default_val);
480       //option->SetAttribute("type",param.info.type().name());
481       std::ostringstream ostr;
482       ostr << param.info;
483       option->LinkEndChild(new TiXmlText(ostr.str()));
484       root->LinkEndChild(option);
485       }
486     curr++;
487   }
488 
489   os << *root;
490   delete root;
491 }
492 #else
write_values_xml(std::ostream &) const493 void OptionParser::write_values_xml(std::ostream& ) const
494 {
495   EXCEPTION_MNGR(std::runtime_error, "Cannot print XML information unless UTILIB is configured with TinyXML");
496 }
497 #endif
498 
499 
500 
501 //
502 // 1. Flag errors if an option appears after the first non-option?
503 // 2. Flag error when invalid value is given
504 //
parse_args(int argc,char * _argv[])505 OptionParser::args_t& OptionParser::parse_args(int argc, char* _argv[])
506 {
507    std::vector<std::string> argv(_argv, _argv + argc);
508    int argc_limit = argc - (int)min_num_required_args;
509    //
510    // Go through the argument list
511    //
512    int i = 1;
513    while ((i < argc_limit) && (argv[i][0] == '-'))
514    {
515       //
516       // Split the current string at the '=' character
517       //
518       char* tmp = const_cast<char*>(strchr(argv[i].c_str(), '='));
519       bool using_equal = false;
520       if (tmp)
521       {
522          using_equal = true;
523          tmp++;
524          *(tmp - 1) = '\000';
525       }
526       bool posix = argv[i][1] != '-';
527       Parameter& param = get_param(argv[i].c_str(),posix);
528       if (param.is_bool)
529       {
530          if (strlen(tmp) >0)
531             param.set_value_with_string(tmp);
532          else
533             param.set_value_with_string("");
534       }
535       else
536       {
537          if (!using_equal && required_equals)
538             EXCEPTION_MNGR(std::runtime_error, "Nonboolean parameter '" << argv[i] << "' specified without required argument.  Option parsing configured to require --option=value syntax.");
539          if (strlen(tmp) > 0)
540             param.set_value_with_string(tmp);
541          else
542          {
543             i++;
544             if (i == argc_limit)
545                EXCEPTION_MNGR(std::runtime_error, "Expected argument for parameter '" << argv[i-1] << "' but ran out of available arguments");
546             if ((argv[i][0] == '-') && (argv[i].size() > 1) && (isalpha(argv[i][1])))
547                EXCEPTION_MNGR(std::runtime_error, "Expected argument for parameter '" << argv[i-1] << "' but the next argument is an option.");
548             param.set_value_with_string(argv[i]);
549          }
550       }
551       i++;
552    }
553    //
554    // Check to ensure that first 'required arg' does not look like a parameter
555    //
556    if ((i < argc) && (argv[i][0] == '-'))
557    {
558       std::string tmp = argv[i];
559       if ((tmp == "--help") || (tmp == "--version"))
560       {
561          bool posix = argv[i][1] != '-';
562          Parameter& param = get_param(argv[i].c_str(), posix);
563          param.set_value_with_string("");
564       }
565       else if ((argv[i].size() > 1) && (isalpha(argv[i][1])))
566          EXCEPTION_MNGR(runtime_error,
567                         "OptionParser::parse_args "
568                         "- first required argument looks "
569                         "like a parameter flag: " << argv[i]);
570    }
571 #if 0
572    // WEH - This error checking seems useful, but it can get in the way.
573    //       There are weird contexts where we should expect to find an option
574    //       after a non-option.  For example, the command-line for an AMPL
575    //       solver has the syntax: <solver> <nl-file> -AMPL
576    int j = i + 1;
577    while (j < argc)
578    {
579       if (argv[j][0] == '-')
580          EXCEPTION_MNGR(runtime_error,
581                         "OptionParser::parse_args "
582                         "- argument '" << argv[j] << "' looks "
583                         "like a parameter flag after all parameters have been parsed.  Argument '" << argv[i] << "' is the first argument.");
584       j++;
585    }
586 #endif
587 
588    //
589    // Collect the remaining arguments
590    //
591    processed_args.push_back(argv[0]);
592    while (i < argc)
593    {
594       processed_args.push_back(argv[i++]);
595    }
596 
597    //
598    // Return the list of arguments
599    //
600    return processed_args;
601 }
602 
603 
set_parameter(std::string _name,const std::string & value)604 void OptionParser::set_parameter(std::string _name, const std::string& value)
605 {
606    std::string name = standardize(_name);
607    bool posix= name.size() == 1;
608    Parameter& param = get_param(name.c_str(), posix);
609    param.set_value_with_string(value);
610 }
611 
set_parameter(std::string _name,Any value)612 void OptionParser::set_parameter(std::string _name, Any value)
613 {
614    std::string name = standardize(_name);
615    bool posix= name.size() == 1;
616    Parameter& param = get_param(name.c_str(), posix);
617    if ( param.info.is_type<Property>() )
618       param.info.expose<Property>() = value;
619    else if ( param.info.is_type<Privileged_Property>() )
620       param.info.expose<Privileged_Property>() = value;
621    else
622       TypeManager()->lexical_cast(value, param.info);
623 }
624 
has_parameter(std::string _name)625 int OptionParser::has_parameter(std::string _name)
626 {
627    if ( _name.empty() )
628       return 0;
629    const char* c = _name.c_str();
630    if ( c[0] == '-') c++;
631    if ( c[0] == '-') c++;
632    std::string name = standardize(c);
633 
634    // as with get_param_any(), we will assume all single-character parameters are POSIX.
635    if ( name.size() == 1 )
636    {
637       std::map<char, data_t>::iterator curr = posix_parameters.find(name[0]);
638       if ( curr == posix_parameters.end() )
639          return 0;
640       else
641          return curr->second().disabled ? -1 : 1;
642    }
643    else
644    {
645       std::map<std::string, data_t>::iterator curr = parameters.find(name);
646       if ( curr == parameters.end() )
647          return 0;
648       else
649          return curr->second().disabled ? -1 : 1;
650    }
651 }
652 
653 
get_param(const char * name,bool posix)654 Parameter& OptionParser::get_param(const char* name, bool posix)
655 {
656 data_t tmp = get_param_any(name,posix);
657 return tmp();
658 }
659 
660 
get_param_any(const char * name,bool posix,bool test_if_enabled)661 OptionParser::data_t OptionParser::get_param_any(const char* name, bool posix, bool test_if_enabled)
662 {
663    if ((name == 0) || (name[0] == '\000'))
664       EXCEPTION_MNGR(std::runtime_error, "OptionParser - "
665                      "cannot access a parameter with an empty name.");
666    if (name[0] == '-') name++;
667    if (name[0] == '-') name++;
668 
669    std::string param = name;
670    if (posix) {
671       if (param.size() > 1)
672          EXCEPTION_MNGR(std::runtime_error, "Multiple posix options cannot be specified at once.");
673       std::map<char, data_t>::iterator curr = posix_parameters.find(param[0]);
674       if (curr == posix_parameters.end())
675          EXCEPTION_MNGR(std::runtime_error, "Unknown posix parameter '" << param << "'");
676       if (curr->second().disabled && test_if_enabled)
677          EXCEPTION_MNGR(std::runtime_error, "Parameter '" << param << "' is disabled.");
678       return curr->second;
679    }
680    else
681    {
682       std::map<std::string, data_t>::iterator curr = parameters.find(param);
683       if (curr == parameters.end())
684          EXCEPTION_MNGR(std::runtime_error, "Unknown parameter '" << param << "'");
685       if (curr->second().disabled && test_if_enabled)
686          EXCEPTION_MNGR(std::runtime_error, "Parameter '" << param << "' is disabled.");
687       return curr->second;
688    }
689 
690 }
691 
692 
add_parameter(data_t any_param)693 void OptionParser::add_parameter(data_t any_param)
694       {
695       Parameter& param = any_param();
696       //
697       // Setup parameters, posix_parameters and parameter_data
698       //
699       if (param.name != "")
700          parameters[param.name] = any_param;
701       if (param.short_name != 0)
702       {
703          posix_parameters[param.short_name] = any_param;
704          if (param.name == "")
705          {
706             std::string tmp;
707             tmp += std::string("_") + param.short_name;
708             parameters[tmp] = any_param;
709          }
710       }
711       parameter_data.insert(any_param);
712       //
713       // Insert aliases
714       //
715       {
716       std::set<std::string>::iterator curr = param.aliases.begin();
717       std::set<std::string>::iterator end  = param.aliases.end();
718       while (curr != end) {
719         if (curr->size() == 1)
720            posix_parameters[(*curr)[0]] = any_param;
721         else
722            parameters[*curr] = any_param;
723       curr++;
724       }
725       }
726       //
727       // Setup categories
728       //
729       {
730       std::set<std::string>::iterator curr = param.categories.begin();
731       std::set<std::string>::iterator end  = param.categories.end();
732       while (curr != end) {
733          if (param.name == "") {
734             std::string tmp;
735             tmp += param.short_name;
736             categorize(tmp, *curr);
737             }
738          else
739             categorize(param.name, *curr);
740       curr++;
741       }
742    }
743 }
744 
standardize(const std::string & _name)745 std::string OptionParser::standardize(const std::string& _name)
746 {
747 std::string name = _name;
748 std::string::iterator curr = name.begin();
749 std::string::iterator end  = name.end();
750 while (curr != end) {
751   if (*curr == '_')
752      *curr = '-';
753   curr++;
754   }
755 return name;
756 }
757 
758 //template <>
759 //bool CachedAllocator<SmartPtrInfo<Parameter> >::cache_enabled = false;
760 
761 }
762