3 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4 * @date Tue Oct 16 18:59:04 2012
9 * @ingroup pwglf_forward_trains_util
18 # include <TObjArray.h>
19 # include <TObjString.h>
32 * An option. The value is stored as a string
34 * @ingroup pwglf_forward_trains_util
36 struct Option /* : public TNamed */
41 * @param name Name of option
42 * @param arg Dummy argument (possibly null)
43 * @param description Description
44 * @param value Default value
46 Option(const TString& name,
48 const TString& description,
50 : fName(name), fDescription(description),
51 fValue(value), fArg(arg), fIsSet(false)
56 * @param other Object to copy from
58 Option(const Option& other)
60 fDescription(other.fDescription),
68 * @param other Object to assign from
70 * @return Reference to this object
72 Option& operator=(const Option& other)
74 if (&other == this) return *this;
77 fDescription = other.fDescription;
78 fValue = other.fValue;
80 fIsSet = other.fIsSet;
87 * @param val New value
89 void Set(const TString& val)
97 // Allow flags to get =true, =1, =false, =0 values
99 (val.EqualTo("false", TString::kIgnoreCase) ||
100 (val.IsDigit() && !val.Atoi()))) {
115 Error("Option::Set", "Option %s needs an argument", fName.Data());
127 if (!HasArg()) fValue = "false";
130 * @return constant reference to value
132 const TString& Get() const { return fValue; }
134 * @return true if this option was set externally
136 Bool_t IsSet() const { return fIsSet; }
138 * @return true if this option needs an argument
140 Bool_t HasArg() const { return !fArg.IsNull(); }
142 * @return value as a boolean value
144 Bool_t AsBool() const { return fIsSet; }
146 * @return value as an integer value
148 Int_t AsInt() const { return fValue.Atoi(); }
150 * @return value as a long integer value
152 Long64_t AsLong() const { return fValue.Atoll(); }
154 * @return value as a double precision value
156 Double_t AsDouble() const { return fValue.Atof(); }
158 * @return value as a C string
160 const char* AsString() const { return fValue.Data(); }
162 * @return Width of the name
164 Int_t NameWidth() const { return fName.IsNull() ? 0 : fName.Length(); }
166 * @return the width of the dummy argument
168 Int_t ArgWidth() const { return fArg.IsNull() ? 0 : fArg.Length(); }
172 * @param o Output stream
173 * @param w With of option plus argument
175 void Help(std::ostream& o, Int_t w=-1) const
182 if (w <= 0) w = NameWidth() + ArgWidth() + 1;
183 std::ios::fmtflags oldf = o.setf(std::ios::left);
184 o << std::setw(w) << tmp << " " << fDescription << " [";
185 if (!HasArg()) o << (IsSet() ? "true" : "false");
187 o << "]" << std::endl;
193 * @param o Output stream
194 * @param w With of name
196 void Show(std::ostream& o, Int_t w=-1) const
198 if (w <= 0) w = NameWidth();
199 std::ios::fmtflags oldf = o.setf(std::ios::left);
200 o << std::setw(w) << fName << ": ";
201 if (!HasArg()) o << (IsSet() ? "true" : "false");
207 * Store option and possible value
209 * @param o Output stream
210 * @param quote If true, quote output
212 void Store(std::ostream& o, bool quote=true) const
215 if (!HasArg()) return;
216 o << "=" << (quote ? "\"" : "") << fValue << (quote ? "\"" : "");
218 TString fName; // Name
219 TString fDescription; // Description
220 TString fValue; // Value
221 TString fArg; // Argument dummy
222 Bool_t fIsSet; // True if this option was set
224 // ClassDef(Option,1) // Option
232 // Linked list element
238 Link() : fPrev(0), fNext(0), fThis(0) {}
239 Link(Link* next, Option* opt)
240 : fPrev(next ? next->fPrev : 0), // Set previous
241 fNext(next), // Set next link
242 fThis(opt) // Set data
244 if (fPrev) fPrev->fNext = this; // Set forward link
245 if (fNext) fNext->fPrev = this; // Set previous link
248 if (fPrev) fPrev->fNext = fNext;
249 if (fNext) fNext->fPrev = fPrev;
258 Link& operator=(const Link& o)
260 if (&o == this) return *this;
270 OptionList() : fList(0) { }
274 * @param other Object to copy from
276 OptionList(const OptionList& other)
280 // TIter next(&other.fList);
282 // while ((o = static_cast<Option*>(next())))
283 // fList.Add(new Option(*o));
289 ~OptionList() { Delete(); }
298 Link* tmp = cur->fNext;
301 // Remove(cur->fThis->fName);
307 * Assignment operator
309 * @param other Object to assign from
311 * @return reference to this
313 OptionList& operator=(const OptionList& other)
315 if (&other == this) return *this;
322 * Copy list from other object
324 * @param other Object to copy from
326 void Copy(const OptionList& other)
329 const Link* ocur = other.fList;
334 cur->fThis = new Option(*(ocur->fThis));
337 if (fList == 0) fList = cur;
338 if (prev) prev->fNext = cur;
343 void DebugLink(const Link* link) const
345 std::cout << "Link=" << link;
347 std::cout << " prev=" << link->fPrev
348 << " next=" << link->fNext
349 << " obj=" << link->fThis;
351 std::cout << " name=" << link->fThis->fName;
353 std::cout <<std::endl;
356 * Find an optio by name
358 * @param name Name of option to find
360 * @return Pointer to option or null
362 Option* Find(const TString& name) const
364 const Link* cur = fList;
366 while (cur && cur->fThis) {
367 if (name.EqualTo(cur->fThis->fName)) return cur->fThis;
373 * Add an option with argument
375 * @param name Name of option
376 * @param arg Dummy argument
377 * @param desc Description
378 * @param val Default value
380 * @return Newly added option
382 Option* Add(const TString& name,
385 const TString& val="")
387 Option* o = Find(name);
389 Warning("OptionList::Add", "Option %s already registered", name.Data());
392 o = new Option(name, arg, desc, val);
405 if (cur->fThis->fName.CompareTo(name) < 0) {
410 n = new Link(cur, o);
411 if (cur == fList) fList = n;
425 * Add an option with no argument
427 * @param name Name of option
428 * @param desc Description
430 * @return Newly created option
432 Option* Add(const TString& name,
435 return Add(name, "", desc, "");
438 * Add an option with no argument
440 * @param name Name of option
441 * @param desc Description
442 * @param def Default value (true, or false)
444 * @return Newly created option
446 Option* Add(const TString& name,
450 Option* o = Add(name, "", desc, "");
451 if (o) o->Set(def ? "true" : "false");
455 * Add an option with argument
457 * @param name Name of option
458 * @param arg Dummy argument
459 * @param desc Description
460 * @param val Default value
461 * @param asHex If true, interpret as hex number
463 * @return Newly added option
465 Option* Add(const TString& name,
473 return Add(name, arg, desc, Form("0x%x", uval));
475 return Add(name, arg, desc, Form("%d", val));
478 * Add an option with argument
480 * @param name Name of option
481 * @param arg Dummy argument
482 * @param desc Description
483 * @param val Default value
484 * @param asHex If true, interpret as hex
486 * @return Newly added option
488 Option* Add(const TString& name,
495 ULong64_t uval = val;
496 return Add(name, arg, desc, Form("0x%llx", uval));
498 return Add(name, arg, desc, Form("%lld", val));
501 * Add an option with argument
503 * @param name Name of option
504 * @param arg Dummy argument
505 * @param desc Description
506 * @param val Default value
508 * @return Newly added option
510 Option* Add(const TString& name,
515 return Add(name, arg, desc, Form("%lg", val));
521 * @param name Name of option to remove
523 void Remove(const TString& name)
527 if (!cur->fThis->fName.EqualTo(name)) {
531 if (fList == cur) fList = cur->fNext;
537 * Check if a given option was set externally
539 * @param name Name of option
541 * @return true if option exists and was set externally
543 Bool_t Has(const TString& name) const
545 Option* o = Find(name);
546 return (o && o->IsSet());
549 * Get the value of an option
551 * @param name Name of option
553 * @return Value of option, or empty string
555 const TString& Get(const TString& name) const
557 static TString null("");
558 Option* o = Find(name);
563 * Get a value using a format statement. Remember argument(s) must
564 * be passed by address (as pointers)
566 * @param name Name of option @param format Format statement.
567 * Remeber, double and long needs the "l" modifier
569 * @return true on success
571 Bool_t GetF(const TString& name, const Char_t* format, ...) const
573 Option* o = Find(name);
574 if (!o) return false;
577 va_start(ap, format);
578 int ret = vsscanf(o->fValue.Data(), format, ap);
584 * Get value of an option as a boolean
586 * @param name Name of
588 * @return Value or false if not found
590 Bool_t AsBool(const TString& name) const
592 Option* o = Find(name);
593 if (!o) return false;
597 * Return value of an option as an integer
599 * @param name Name of option
600 * @param def Default value if options isn't found
602 * @return Value or default value
604 Int_t AsInt(const TString& name, Int_t def=0) const
606 Option* o = Find(name);
611 * Return value of an option as an integer
613 * @param name Name of option
614 * @param def Default value if options isn't found
616 * @return Value or default value
618 Long64_t AsLong(const TString& name, Long64_t def=0) const
620 Option* o = Find(name);
625 * Return value of an option as a double precision real number
627 * @param name Name of option
628 * @param def Default value if options isn't found
630 * @return Value or default value
632 Double_t AsDouble(const TString& name, Double_t def=0) const
634 Option* o = Find(name);
636 return o->AsDouble();
639 * Set value using a format statement
641 * @param name Name of option.
642 * @param format Format statement
644 void SetF(const TString& name, const Char_t* format, ...)
646 Option* o = Find(name);
649 static char buf[1024];
652 va_start(ap, format);
653 vsnprintf(buf, 1023, format, ap);
662 * @param name Name of option
663 * @param value Value of option
665 void Set(const TString& name, const TString& value)
667 Option* o = Find(name);
674 * @param name Name of flag
676 void Set(const TString& name)
678 Option* o = Find(name);
683 * Set long integer value
685 * @param name Name of option
687 * @param asHex If true, interpret as hex
689 void Set(const TString& name, Int_t val, Bool_t asHex=false)
691 if (asHex) Set(name, Form("0x%x", val));
692 else Set(name, Form("%d", val));
695 * Set long integer value
697 * @param name Name of option
699 * @param asHex If true, interpret as hex value
701 void Set(const TString& name, Long64_t val, Bool_t asHex=false)
703 ULong64_t uval = val;
704 if (asHex) Set(name, Form("0x%llx", uval));
705 else Set(name, Form("%lld", val));
708 * Set double precision floating point value
710 * @param name Name of option
713 void Set(const TString& name, Double_t val)
715 Set(name, Form("%lg", val));
718 * Parse the options given in tmp
720 * @param tmp String to pass
721 * @param delims Delimiters
723 * @return true on success
725 Bool_t Parse(const TString& tmp, const TString& delims)
727 TObjArray* opts = tmp.Tokenize(delims);
728 // Info("OptionList::Parse", "Parsing options %s", tmp.Data());
729 Bool_t ret = Parse(opts);
734 * Parse options given in a collection
736 * @param opts List of arguments
737 * @param ignoreUnknown If true, ignore unknown options
739 * @return true on success
741 Bool_t Parse(const TCollection* opts, Bool_t ignoreUnknown=false)
743 // Info("OptionList::Parse", "List of options");
747 while ((o = static_cast<TObjString*>(next()))) {
748 TString& s = o->String();
751 Int_t eq = s.Index("=");
754 val = s(eq+1, s.Length()-eq-1);
757 // Info("OptionList::Parse", "Looking for key=%s", key.Data());
758 Option* opt = Find(key);
761 Warning("OptionList::Parse", "Unknown option: \"%s\"", s.Data());
764 if (opt->HasArg() && val.IsNull()) {
765 Warning("OptionList::Parse",
766 "Option %s needs an argument, using default %s",
767 key.Data(), opt->fValue.Data());
776 * Find the widest name and dummy argument
778 * @param nWidth On return, the largest width of option names
779 * @param aWidth On return, the largest width of option dummy args
781 void Widest(Int_t& nWidth, Int_t& aWidth) const
785 const Link* cur = fList;
787 Option* opt = cur->fThis;
788 nWidth = TMath::Max(nWidth, opt->NameWidth());
789 aWidth = TMath::Max(aWidth, opt->ArgWidth());
793 // while ((opt = static_cast<Option*>(next()))) {
797 * Display option help
799 * @param o Output stream
800 * @param prefix Prefix for each option.
802 void Help(std::ostream& o, const char* prefix=" ") const
804 Int_t nWidth, aWidth;
805 Widest(nWidth, aWidth);
806 if (aWidth > 0) nWidth += aWidth+1;
808 const Link* cur = fList;
810 Option* opt = cur->fThis;
812 opt->Help(o, nWidth);
817 * Show the values of options
819 * @param o Output stream
820 * @param prefix Prefix for each option
822 void Show(std::ostream& o, const char* prefix=" ") const
824 Int_t nWidth, aWidth;
825 Widest(nWidth, aWidth);
828 const Link* cur = fList;
830 Option* opt = cur->fThis;
832 opt->Show(o, nWidth);
837 * Show the values of options
839 * @param o Output stream
840 * @param prefix Prefix for each option
841 * @param delim Delimters
842 * @param quote Quote output
843 * @param onlySet if true, only output set options
845 void Store(std::ostream& o, const char* prefix="",
846 const char* delim=",", bool quote=true,
847 bool onlySet=false) const
849 Int_t nWidth, aWidth;
850 Widest(nWidth, aWidth);
852 const Link* cur = fList;
854 Option* opt = cur->fThis;
855 if ((!opt->HasArg() || onlySet) && !opt->IsSet()) {
860 opt->Store(o, quote);
868 static void Test(const char* opts="")
871 l.Add("int", "NUMBER", "Integer", "42");
872 l.Add("float", "NUMBER", "Floating point", "3.14");
873 l.Add("bool", "Flag");
874 l.Add("hex", "NUMBER", "Hexadecimal", "0xdead");
875 l.Add("string", "STRING", "A string", "Hello, world");
876 l.Show(std::cout, "\t");
878 std::cout << "Find" << std::endl;
879 Option* b = l.Find("bool");
883 std::cout << "SetF" << std::endl;
884 l.SetF("float", "%f", 2.17);
885 l.Show(std::cout, "\t");
887 std::cout << "GetF" << std::endl;
889 l.GetF("float", "%f", &f);
890 std::cout << "\tf=" << f << std::endl;
891 std::cout << "Remove" << std::endl;
893 l.Show(std::cout, "\t");
895 std::cout << "Set" << std::endl;
897 l.Set("hex", 0xbeef, true);
898 l.Set("bool", "false");
899 l.Show(std::cout, "\t");
901 std::cout << "Copy" << std::endl;
903 c.Show(std::cout, "\t");
905 std::cout << "Parse" << std::endl;
907 c.Show(std::cout, "\t");
908 std::cout << "End of test" << std::endl;