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)
94 // Info("Set", "Setting option %s with arg %s to %s",
95 // fName.Data(), fArg.Data(), fValue.Data());
99 // Info("Set", "Setting option %s with no arg", fName.Data());
100 // Allow flags to get =true, =1, =false, =0 values
102 (val.EqualTo("false", TString::kIgnoreCase) ||
103 (val.IsDigit() && !val.Atoi()))) {
118 Error("Option::Set", "Option %s needs an argument", fName.Data());
130 if (!HasArg()) fValue = "false";
133 * @return constant reference to value
135 const TString& Get() const { return fValue; }
137 * @return true if this option was set externally
139 Bool_t IsSet() const { return fIsSet; }
141 * @return true if this option needs an argument
143 Bool_t HasArg() const { return !fArg.IsNull(); }
145 * @return value as a boolean value
147 Bool_t AsBool() const { return fIsSet; }
149 * @return value as an integer value
151 Int_t AsInt() const { return fValue.Atoi(); }
153 * @return value as a long integer value
155 Long64_t AsLong() const { return fValue.Atoll(); }
157 * @return value as a double precision value
159 Double_t AsDouble() const { return fValue.Atof(); }
161 * @return value as a C string
163 const char* AsString() const { return fValue.Data(); }
165 * @return Width of the name
167 Int_t NameWidth() const { return fName.IsNull() ? 0 : fName.Length(); }
169 * @return the width of the dummy argument
171 Int_t ArgWidth() const { return fArg.IsNull() ? 0 : fArg.Length(); }
175 * @param o Output stream
176 * @param w With of option plus argument
178 void Help(std::ostream& o, Int_t w=-1) const
185 if (w <= 0) w = NameWidth() + ArgWidth() + 1;
186 std::ios::fmtflags oldf = o.setf(std::ios::left);
187 o << std::setw(w) << tmp << " " << fDescription << " [";
188 if (!HasArg()) o << (IsSet() ? "true" : "false");
190 o << "]" << std::endl;
196 * @param o Output stream
197 * @param w With of name
199 void Show(std::ostream& o, Int_t w=-1) const
201 if (w <= 0) w = NameWidth();
202 std::ios::fmtflags oldf = o.setf(std::ios::left);
203 o << std::setw(w) << fName << ": ";
204 if (!HasArg()) o << (IsSet() ? "true" : "false");
210 * Store option and possible value
212 * @param o Output stream
213 * @param quote If true, quote output
215 void Store(std::ostream& o, bool quote=true) const
218 if (!HasArg()) return;
219 o << "=" << (quote ? "\"" : "") << fValue << (quote ? "\"" : "");
221 TString fName; // Name
222 TString fDescription; // Description
223 TString fValue; // Value
224 TString fArg; // Argument dummy
225 Bool_t fIsSet; // True if this option was set
227 // ClassDef(Option,1) // Option
235 // Linked list element
241 Link() : fPrev(0), fNext(0), fThis(0) {}
242 Link(Link* next, Option* opt)
243 : fPrev(next ? next->fPrev : 0), // Set previous
244 fNext(next), // Set next link
245 fThis(opt) // Set data
247 if (fPrev) fPrev->fNext = this; // Set forward link
248 if (fNext) fNext->fPrev = this; // Set previous link
251 if (fPrev) fPrev->fNext = fNext;
252 if (fNext) fNext->fPrev = fPrev;
261 Link& operator=(const Link& o)
263 if (&o == this) return *this;
273 OptionList() : fList(0) { }
277 * @param other Object to copy from
279 OptionList(const OptionList& other)
283 // TIter next(&other.fList);
285 // while ((o = static_cast<Option*>(next())))
286 // fList.Add(new Option(*o));
292 ~OptionList() { Delete(); }
301 Link* tmp = cur->fNext;
304 // Remove(cur->fThis->fName);
310 * Assignment operator
312 * @param other Object to assign from
314 * @return reference to this
316 OptionList& operator=(const OptionList& other)
318 if (&other == this) return *this;
325 * Copy list from other object
327 * @param other Object to copy from
329 void Copy(const OptionList& other)
332 const Link* ocur = other.fList;
337 cur->fThis = new Option(*(ocur->fThis));
340 if (fList == 0) fList = cur;
341 if (prev) prev->fNext = cur;
346 void DebugLink(const Link* link) const
348 std::cout << "Link=" << link;
350 std::cout << " prev=" << link->fPrev
351 << " next=" << link->fNext
352 << " obj=" << link->fThis;
354 std::cout << " name=" << link->fThis->fName;
356 std::cout <<std::endl;
359 * Find an optio by name
361 * @param name Name of option to find
363 * @return Pointer to option or null
365 Option* Find(const TString& name) const
367 const Link* cur = fList;
369 while (cur && cur->fThis) {
370 if (name.EqualTo(cur->fThis->fName)) return cur->fThis;
376 * Add an option with argument
378 * @param name Name of option
379 * @param arg Dummy argument
380 * @param desc Description
381 * @param val Default value
383 * @return Newly added option
385 Option* Add(const TString& name,
388 const TString& val="")
390 Option* o = Find(name);
392 Warning("OptionList::Add", "Option %s already registered", name.Data());
395 // Info("Add", "New option %s with arg %s (%s) and value %s",
396 // name.Data(), arg.Data(), desc.Data(), val.Data());
397 o = new Option(name, arg, desc, val);
410 if (cur->fThis->fName.CompareTo(name) < 0) {
415 n = new Link(cur, o);
416 if (cur == fList) fList = n;
430 * Add an option with no argument
432 * @param name Name of option
433 * @param desc Description
435 * @return Newly created option
437 Option* Add(const TString& name,
440 return Add(name, "", desc, "");
443 * Add an option with no argument
445 * @param name Name of option
446 * @param desc Description
447 * @param def Default value (true, or false)
449 * @return Newly created option
451 Option* Add(const TString& name,
455 Option* o = Add(name, "", desc, "");
456 if (o) o->Set(def ? "true" : "false");
460 * Add an option with argument
462 * @param name Name of option
463 * @param arg Dummy argument
464 * @param desc Description
465 * @param val Default value
466 * @param asHex If true, interpret as hex number
468 * @return Newly added option
470 Option* Add(const TString& name,
478 return Add(name, arg, desc, Form("0x%x", uval));
480 return Add(name, arg, desc, Form("%d", val));
483 * Add an option with argument
485 * @param name Name of option
486 * @param arg Dummy argument
487 * @param desc Description
488 * @param val Default value
489 * @param asHex If true, interpret as hex
491 * @return Newly added option
493 Option* Add(const TString& name,
500 ULong64_t uval = val;
501 return Add(name, arg, desc, Form("0x%llx", uval));
503 return Add(name, arg, desc, Form("%lld", val));
506 * Add an option with argument
508 * @param name Name of option
509 * @param arg Dummy argument
510 * @param desc Description
511 * @param val Default value
513 * @return Newly added option
515 Option* Add(const TString& name,
520 return Add(name, arg, desc, Form("%lg", val));
526 * @param name Name of option to remove
528 void Remove(const TString& name)
532 if (!cur->fThis->fName.EqualTo(name)) {
536 if (fList == cur) fList = cur->fNext;
542 * Check if a given option was set externally
544 * @param name Name of option
546 * @return true if option exists and was set externally
548 Bool_t Has(const TString& name) const
550 Option* o = Find(name);
551 return (o && o->IsSet());
554 * Get the value of an option
556 * @param name Name of option
558 * @return Value of option, or empty string
560 const TString& Get(const TString& name) const
562 static TString null("");
563 Option* o = Find(name);
568 * Get a value using a format statement. Remember argument(s) must
569 * be passed by address (as pointers)
571 * @param name Name of option @param format Format statement.
572 * Remeber, double and long needs the "l" modifier
574 * @return true on success
576 Bool_t GetF(const TString& name, const Char_t* format, ...) const
578 Option* o = Find(name);
579 if (!o) return false;
582 va_start(ap, format);
583 int ret = vsscanf(o->fValue.Data(), format, ap);
589 * Get value of an option as a boolean
591 * @param name Name of
593 * @return Value or false if not found
595 Bool_t AsBool(const TString& name) const
597 Option* o = Find(name);
598 if (!o) return false;
602 * Return value of an option as an integer
604 * @param name Name of option
605 * @param def Default value if options isn't found
607 * @return Value or default value
609 Int_t AsInt(const TString& name, Int_t def=0) const
611 Option* o = Find(name);
616 * Return value of an option as an integer
618 * @param name Name of option
619 * @param def Default value if options isn't found
621 * @return Value or default value
623 Long64_t AsLong(const TString& name, Long64_t def=0) const
625 Option* o = Find(name);
630 * Return value of an option as a double precision real number
632 * @param name Name of option
633 * @param def Default value if options isn't found
635 * @return Value or default value
637 Double_t AsDouble(const TString& name, Double_t def=0) const
639 Option* o = Find(name);
641 return o->AsDouble();
644 * return value of an option as a string
646 * @param name Name of option
647 * @param def Default valie if option isn't found
649 * @return Value or default value
651 const char* AsString(const TString& name, const TString& def="") const
653 Option* o = Find(name);
654 if (!o) return def.Data();
655 return o->AsString();
658 * return value of an option as a string
660 * @param name Name of option
661 * @param def Default valie if option isn't found
663 * @return Value or default value
665 const TString& AsTString(const TString& name, const TString& def="") const
667 Option* o = Find(name);
672 * Set value using a format statement
674 * @param name Name of option.
675 * @param format Format statement
677 void SetF(const TString& name, const Char_t* format, ...)
679 Option* o = Find(name);
682 static char buf[1024];
685 va_start(ap, format);
686 vsnprintf(buf, 1023, format, ap);
695 * @param name Name of option
696 * @param value Value of option
698 void Set(const TString& name, const TString& value)
700 Option* o = Find(name);
707 * @param name Name of flag
709 void Set(const TString& name)
711 Option* o = Find(name);
716 * Set long integer value
718 * @param name Name of option
720 * @param asHex If true, interpret as hex
722 void Set(const TString& name, Int_t val, Bool_t asHex=false)
724 if (asHex) Set(name, Form("0x%x", val));
725 else Set(name, Form("%d", val));
728 * Set long integer value
730 * @param name Name of option
732 * @param asHex If true, interpret as hex value
734 void Set(const TString& name, Long64_t val, Bool_t asHex=false)
736 ULong64_t uval = val;
737 if (asHex) Set(name, Form("0x%llx", uval));
738 else Set(name, Form("%lld", val));
741 * Set double precision floating point value
743 * @param name Name of option
746 void Set(const TString& name, Double_t val)
748 Set(name, Form("%lg", val));
751 * Parse the options given in tmp
753 * @param tmp String to pass
754 * @param delims Delimiters
756 * @return true on success
758 Bool_t Parse(const TString& tmp, const TString& delims)
760 TObjArray* opts = tmp.Tokenize(delims);
761 // Info("OptionList::Parse", "Parsing options %s", tmp.Data());
762 Bool_t ret = Parse(opts);
767 * Parse options given in a collection
769 * @param opts List of arguments
770 * @param ignoreUnknown If true, ignore unknown options
772 * @return true on success
774 Bool_t Parse(const TCollection* opts, Bool_t ignoreUnknown=false)
776 // Info("OptionList::Parse", "List of options");
780 while ((o = static_cast<TObjString*>(next()))) {
781 TString& s = o->String();
784 Int_t eq = s.Index("=");
787 val = s(eq+1, s.Length()-eq-1);
790 // Info("OptionList::Parse", "Looking for key=%s", key.Data());
791 Option* opt = Find(key);
794 Warning("OptionList::Parse", "Unknown option: \"%s\"", s.Data());
797 if (opt->HasArg() && val.IsNull()) {
798 Warning("OptionList::Parse",
799 "Option %s needs an argument, using default %s",
800 key.Data(), opt->fValue.Data());
809 * Find the widest name and dummy argument
811 * @param nWidth On return, the largest width of option names
812 * @param aWidth On return, the largest width of option dummy args
814 void Widest(Int_t& nWidth, Int_t& aWidth) const
818 const Link* cur = fList;
820 Option* opt = cur->fThis;
821 nWidth = TMath::Max(nWidth, opt->NameWidth());
822 aWidth = TMath::Max(aWidth, opt->ArgWidth());
826 // while ((opt = static_cast<Option*>(next()))) {
830 * Display option help
832 * @param o Output stream
833 * @param prefix Prefix for each option.
835 void Help(std::ostream& o, const char* prefix=" ") const
837 Int_t nWidth, aWidth;
838 Widest(nWidth, aWidth);
839 if (aWidth > 0) nWidth += aWidth+1;
841 const Link* cur = fList;
843 Option* opt = cur->fThis;
845 opt->Help(o, nWidth);
850 * Show the values of options
852 * @param o Output stream
853 * @param prefix Prefix for each option
855 void Show(std::ostream& o, const char* prefix=" ") const
857 Int_t nWidth, aWidth;
858 Widest(nWidth, aWidth);
861 const Link* cur = fList;
863 Option* opt = cur->fThis;
865 opt->Show(o, nWidth);
870 * Show the values of options
872 * @param o Output stream
873 * @param prefix Prefix for each option
874 * @param delim Delimters
875 * @param quote Quote output
876 * @param onlySet if true, only output set options
878 void Store(std::ostream& o, const char* prefix="",
879 const char* delim=",", bool quote=true,
880 bool onlySet=false) const
882 Int_t nWidth, aWidth;
883 Widest(nWidth, aWidth);
885 const Link* cur = fList;
887 Option* opt = cur->fThis;
888 if ((!opt->HasArg() || onlySet) && !opt->IsSet()) {
893 opt->Store(o, quote);
901 static void Test(const char* opts="")
904 l.Add("int", "NUMBER", "Integer", "42");
905 l.Add("float", "NUMBER", "Floating point", "3.14");
906 l.Add("bool", "Flag");
907 l.Add("hex", "NUMBER", "Hexadecimal", "0xdead");
908 l.Add("string", "STRING", "A string", "Hello, world");
909 l.Show(std::cout, "\t");
911 std::cout << "Find" << std::endl;
912 Option* b = l.Find("bool");
916 std::cout << "SetF" << std::endl;
917 l.SetF("float", "%f", 2.17);
918 l.Show(std::cout, "\t");
920 std::cout << "GetF" << std::endl;
922 l.GetF("float", "%f", &f);
923 std::cout << "\tf=" << f << std::endl;
924 std::cout << "Remove" << std::endl;
926 l.Show(std::cout, "\t");
928 std::cout << "Set" << std::endl;
930 l.Set("hex", 0xbeef, true);
931 l.Set("bool", "false");
932 l.Show(std::cout, "\t");
934 std::cout << "Copy" << std::endl;
936 c.Show(std::cout, "\t");
938 std::cout << "Parse" << std::endl;
940 c.Show(std::cout, "\t");
941 std::cout << "End of test" << std::endl;