You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

configuration.hpp 45KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. // configuration.hpp
  2. //
  3. // (C) 2006 - 2009 MicroNeil Research Corporation.
  4. //
  5. // This program is part of the MicroNeil Research Open Library Project. For
  6. // more information go to http://www.microneil.com/OpenLibrary/index.html
  7. //
  8. // This program is free software; you can redistribute it and/or modify it
  9. // under the terms of the GNU General Public License as published by the
  10. // Free Software Foundation; either version 2 of the License, or (at your
  11. // option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful, but WITHOUT
  14. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. // more details.
  17. //
  18. // You should have received a copy of the GNU General Public License along with
  19. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. // Place, Suite 330, Boston, MA 02111-1307 USA
  21. //
  22. // What about this =============================================================
  23. // The configuration module provides a platform for reading configuration files
  24. // (or string data) containing well-formed xml and mapping that data to program
  25. // variables.
  26. // The idea is to provide the ability for an object or application to provide
  27. // a modular "configuration" object that models a hierarchical collection of
  28. // "settings" that can be represented easily in code and in xml.
  29. //
  30. // The following is an example model of a configuration in code and that same
  31. // configuration fully populated in xml.
  32. //
  33. // The code might look like this...
  34. //
  35. // int IntValue, DefaultInt = 3;
  36. // double DblValue, DefaultDbl = 3.14159;
  37. // bool BooleanValue, DefaultBool = false;
  38. // string StringValue, DefaultString = "NoStringHere";
  39. //
  40. // SpecialConfigurator : public ConfigurationHandler { // Create a special handler to build a list
  41. // ...
  42. // public:
  43. //
  44. // ConfigurationHandler& Startup(ConfigurationElement& E) { // This function returns a handy handler to
  45. // return MyStartupConfigurationHandler; // (re) initialize this handler ;-)
  46. // }
  47. //
  48. // void Operator()() { // Each time the configurator is called
  49. // ...
  50. // }
  51. //
  52. // int Attribute1; // these items are interpreted and added
  53. // double Attribute2; // to the list. A ConfigurationHandler COULD
  54. // string Attribute3; // do something entirely different though ;-)
  55. // string Contents;
  56. // ...
  57. // } Special;
  58. //
  59. // ConfigurationElement SampleConfig("SampleConfiguration"); // Define a sample config (doc element)
  60. // SampleConfig // Populate the SampleConfig
  61. // .atStartCall(Special.Startup())
  62. // .Element("Integer", IntValue, DefaultInt).End() // Link an element to an int w/ default.
  63. // .Element("Double", DblValue, DefaultDbl).End("Double") // Link an element to a dbl w/ default.
  64. // .Element("String", StringValue, DefaultString).End("String") // Link an element to a string w/ default.
  65. // .Element("ComplexElements") // Create a sub element.
  66. // .Element("Complex1") // Sub element Complex1 has attributes.
  67. // .Attribute("IntAtt", IntValue, DefaultInt) // Complex1 has an integer attribute.
  68. // .Attribute("DblAtt", DblValue, DefaultDbl) // Complex1 has a dbl attribute.
  69. // .Element("IntAtt", IntValue).End() // IntAtt can also be set by a sub element.
  70. // .Element("DblAtt", DblValue).End() // DblAtt can also be set by a sub element.
  71. // .End() // That's it for Complex1.
  72. // .Element("Complex2") // Create the Complex2 sub element.
  73. // .Attribute("C2I", IntValue, DefaultInt) // C2I attribute.
  74. // .Attribute("C2D", DblValue) // C2D attribute - no default.
  75. // .Attribute("C2S", StringValue, DefultString) // C2S attribute - string w/ default.
  76. // .End("Complex2") // End of element throws if doesn't match.
  77. // .Element("Complex3", Special.Contents) // Element 3 using a special configurator.
  78. // .Attribute("A1", Special.Attribute1) // Set A1 and A2 and A3 and when the
  79. // .Attribute("A2", Special.Attribute2) // element has been completed, Special()
  80. // .Attribute("A3", Special.Attribute3) // will be called to record the entries.
  81. // .atEndCall(Special) // Here's where we register the handler.
  82. // .End() // Closing Complex3 to be ice.
  83. // .End() // Closing ComplexElements to be nice.
  84. // .End(); // Closing SampleConfiguration to be nice.
  85. //
  86. // The XML might look like this...
  87. //
  88. // <SampleConfiguration>
  89. // <Integer>10</Integer>
  90. // <Double>2.4</Double>
  91. // <String>This is a sample string</String>
  92. // <ComplexElements>
  93. // <Complex1 IntAtt="4" DblAtt="2.1324">
  94. // <IntAtt>24</IntAtt> <!-- changed IntAtt -->
  95. // </Complex1>
  96. // <Complex2 C2I='3' C2D='5.14' C2S='Some "string" we like' />
  97. // <Complex3> stuff in here </Complex3>
  98. // <Complex3> Another instance </Complex3>
  99. // <Complex3> Each one gets passed to Special() on activation </Complex3>
  100. // <Complex3> This way, Special() can build a list or some other </Complex3>
  101. // <Complex3> interesting thing with all of these. </Complex3>
  102. // <ComplexElements>
  103. // </SampleConfiguration>
  104. //
  105. // Include This Header Once Only ===============================================
  106. #ifndef configuration_included
  107. #define configuration_included
  108. #include <string>
  109. #include <sstream>
  110. #include <fstream>
  111. #include <cstring>
  112. #include <cstdlib>
  113. #include <list>
  114. using namespace std;
  115. class ConfigurationElement; // Elements exist
  116. class ConfigurationAttribute; // Attributes exist
  117. class ConfigurationData; // Data exists
  118. class ConfigurationTranslator; // Translators exist
  119. class ConfigurationMnemonic; // Mnemonics exist
  120. class Configurator; // Configurators exist
  121. //// Configuration Element /////////////////////////////////////////////////////
  122. //
  123. // Elements make up the core of a configuration. That is, a configuration is a
  124. // tree of elements. Elements translate directly to well formed xml elements in
  125. // a configuration file or string.
  126. class ConfigurationElement {
  127. private:
  128. string myName; // Elements have a name.
  129. // External important things I remember but don't touch...
  130. ConfigurationElement* myParent; // They may have a parrent.
  131. list<Configurator*> myStartConfigurators; // Call these when we start Interpret()
  132. list<Configurator*> myEndConfigurators; // Call these when we finish Interpret()
  133. // Internal / subordinate things I own and kill...
  134. list<ConfigurationAttribute*> myAttributes; // They may have a list of attributes.
  135. list<ConfigurationElement*> myElements; // They may have a list of sub-elements.
  136. list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
  137. list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.
  138. // During Interpret() operations we keep track of where we are seen...
  139. int myLine; // Last line number I was seen on.
  140. int myIndex; // Last char position I was seen on.
  141. int myLength; // Last segment length.
  142. bool myCleanFlag; // Keep track of initialization.
  143. bool myInitOnInterpretFlag; // Initialize() at each Interpret()?
  144. void runStartConfigurators(ConfigurationData& D); // Does what it says ;-)
  145. void runEndConfigurators(ConfigurationData& D); // Does what it says ;-)
  146. public:
  147. ConfigurationElement(const char* Name); // Must be constructed with a name
  148. ConfigurationElement(const string Name); // either c string or c++ string.
  149. ConfigurationElement(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
  150. ConfigurationElement(const string Name, ConfigurationElement& Parent); // parrent.
  151. // Upon desctruction an element will delete all subordinate objects:
  152. // * All sub element objects.
  153. // * All attribute objects.
  154. // * All mnemonic objects.
  155. // * All translator objects.
  156. // It is important to use new when passing one of these objects to an
  157. // element or attribute to prevent problems with the delete operation.
  158. // NORMALLY these things would be created using factory methods on the
  159. // element and attribute objects themselves - so be careful.
  160. // It will not delete Configurators - they must
  161. // be deleted elsewhere because they may have been
  162. // re-used and this element wouldn't know about it ;-)
  163. ~ConfigurationElement(); // The descrutor clears and deletes all!
  164. // Elements can be probed for some simple, useful things.
  165. string Name(); // Get the name of this element.
  166. ConfigurationElement& Parent(); // Get the parent of this element.
  167. ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element.
  168. // Note - if there is no parent (an element is the root) then it will
  169. // return a reference to itself when Parent() is called.
  170. int Line(); // Get the last line number.
  171. int Index(); // Get the last data position.
  172. int Length(); // Get the last length.
  173. // Elements can contain either data or sub-elements.
  174. ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name.
  175. ConfigurationElement& Element(const string Name); // Add a new sub element by c++ string name.
  176. //// Mapping element factory methods for convenience.
  177. //// Root-Node elements are _usually_ empty and without attributes in xml
  178. //// so we don't make any of that type of convenience constructor here.
  179. // char* versions
  180. ConfigurationElement& Element( // Mapping factory for convenience,
  181. const char* Name, // requires a name, of course,
  182. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  183. ConfigurationElement& Element( // Mapping factory for convenience,
  184. const char* Name, // requires a name, of course,
  185. string& x, string init = string("")); // Map to a string.
  186. ConfigurationElement& Element( // Mapping factory for convenience,
  187. const char* Name, // requires a name, of course,
  188. int& x, int init = 0, int radix = 0); // Map to an int.
  189. ConfigurationElement& Element( // Mapping factory for convenience,
  190. const char* Name, // requires a name, of course,
  191. double& x, double init = 0.0); // Map to a double.
  192. ConfigurationElement& Element( // Mapping factory for convenience,
  193. const char* Name, // requires a name, of course,
  194. bool& x, bool init = false); // Map to a boolean.
  195. // string versions
  196. ConfigurationElement& Element( // Mapping factory for convenience,
  197. const string Name, // requires a name, of course,
  198. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  199. ConfigurationElement& Element( // Mapping factory for convenience,
  200. const string Name, // requires a name, of course,
  201. string& x, string init = string("")); // Map to a string.
  202. ConfigurationElement& Element( // Mapping factory for convenience,
  203. const string Name, // requires a name, of course,
  204. int& x, int init = 0, int radix = 0); // Map to an int.
  205. ConfigurationElement& Element( // Mapping factory for convenience,
  206. const string Name, // requires a name, of course,
  207. double& x, double init = 0.0); // Map to a double.
  208. ConfigurationElement& Element( // Mapping factory for convenience,
  209. const string Name, // requires a name, of course,
  210. bool& x, bool init = false); // Map to a boolean.
  211. // End methods for heading back up the tree at the end of an element.
  212. class EndNameDoesNotMatch {}; // Throw when End(name) doesn't match.
  213. ConfigurationElement& End(); // Return this element's parent.
  214. ConfigurationElement& End(const char* Name); // Check the name and return the parent
  215. ConfigurationElement& End(const string Name); // if the name is correct - or throw!
  216. // Elements can have attributes.
  217. ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
  218. ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string.
  219. //// Mapping Attribute factory methods for convenience.
  220. // char* versions
  221. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  222. const char* Name, // requires a name, of course,
  223. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  224. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  225. const char* Name, // requires a name, of course,
  226. string& x, string init = string("")); // Map to a string.
  227. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  228. const char* Name, // requires a name, of course,
  229. int& x, int init = 0, int radix = 0); // Map to an int.
  230. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  231. const char* Name, // requires a name, of course,
  232. double& x, double init = 0.0); // Map to a double.
  233. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  234. const char* Name, // requires a name, of course,
  235. bool& x, bool init = false); // Map to a boolean.
  236. // string versions
  237. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  238. const string Name, // requires a name, of course,
  239. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  240. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  241. const string Name, // requires a name, of course,
  242. string& x, string init = string("")); // Map to a string.
  243. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  244. const string Name, // requires a name, of course,
  245. int& x, int init = 0, int radix = 0); // Map to an int.
  246. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  247. const string Name, // requires a name, of course,
  248. double& x, double init = 0.0); // Map to a double.
  249. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  250. const string Name, // requires a name, of course,
  251. bool& x, bool init = false); // Map to a boolean.
  252. // Elements can Initialize() at each Interpret() call.
  253. ConfigurationElement& setInitOnInterpret(); // Set the init on interpret flag.
  254. // Elements can call external functions to aid in special operations
  255. // such as building lists.
  256. ConfigurationElement& atStartCall(Configurator& Functor); // Add an atStart call-back to this element.
  257. ConfigurationElement& atEndCall(Configurator& Functor); // Add an atEnd call-back to this element.
  258. // Extracting data from the element's contents is done with
  259. // translators. A good set of primatives are built in, but the user
  260. // can also make their own. If an Element is mapped to more than
  261. // one then they are all called once the element's contents are
  262. // collected. A translator takes the data provided by the element,
  263. // converts it into the expected type, and sets one or more variables
  264. // to the converted value. Usually - just one variable.
  265. ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  266. ConfigurationElement& mapTo(string& x, string init = string("")); // Map to a string.
  267. ConfigurationElement& mapTo(int& x, int init = 0, int radix = 0); // Map to an int.
  268. ConfigurationElement& mapTo(double& x, double init = 0.0); // Map to a double.
  269. ConfigurationElement& mapTo(bool& x, bool init = false); // Map to a boolean.
  270. // An Element's contents may use some special mnemonics to make a
  271. // configuration easier to understand and less error prone. When the
  272. // contents match a mnemnoic then the translation of the mnemonic is
  273. // passed to the Translators instead of the raw contents.
  274. ConfigurationElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings.
  275. ConfigurationElement& Mnemonic(const char* name, const string value); // Add a mnemonic using c & c++ strings.
  276. ConfigurationElement& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings.
  277. ConfigurationElement& Mnemonic(const string name, const string value); // Add a mnemonic using c++ strings.
  278. // The way data gets into an element tree is that it is Interpret()ed
  279. // recursively. The data is loaded into a ConfigurationData object which
  280. // is passed to the top Element. That element interpretes the data, moves
  281. // the interpretation pointers, and passes the data on to it's subordinate
  282. // elements in turn. They do the same recursively. When the last sub -
  283. // element has had it's way with the data, the interpretation process is
  284. // complete. The ConfigurationData object will contain the original data
  285. // and a log of anything that happened during the interpretation process.
  286. //
  287. // Each time an element is asked to Interpret() data, it calls any atStart
  288. // configurators, translates any attributes, then either translates it's
  289. // contents or passes the data to it's children, then calls any atEnd
  290. // configurators.
  291. //
  292. // To ensure that the correct default values are used the Initialize() is
  293. // always called on all internal attributes and elements before any data is
  294. // interpreted. To prevent this from being inefficient, a boolean flag is
  295. // kept in each element to keep track of whether it is clean and if it is
  296. // then the call to Initialize will simply return (skipping subordinate
  297. // elements along the way).
  298. //
  299. // Interpret returns true if this object found itself at the current
  300. // Data.Index and false if not. This helps keep the recursive parsing
  301. // code simpler ;-)
  302. void initialize(); // Reset all translators to defaults.
  303. void notifyDirty(); // Set dirty (if translators change).
  304. bool interpret(ConfigurationData& Data); // (re) Interpret this data.
  305. };
  306. //// Configuration Attribute ///////////////////////////////////////////////////
  307. //
  308. // Attributes translate directly to well formed xml attributes (within the
  309. // start tag of an element).
  310. class ConfigurationAttribute {
  311. private:
  312. string myName; // Elements have a name.
  313. ConfigurationElement& myParent; // They may have a parrent.
  314. list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
  315. list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.
  316. int myLine; // Last line number I was seen on.
  317. int myIndex; // Last char position I was seen on.
  318. int myLength; // Last segment length.
  319. public:
  320. ConfigurationAttribute(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
  321. ConfigurationAttribute(const string Name, ConfigurationElement& Parent); // parrent.
  322. // Attributes delete their Mnemonics and Translators when they go.
  323. // See Elements for similar warnings about objects provided to
  324. // this object... you must use new to be safe, or better yet - stick to
  325. // the built in factory methods ;-)
  326. ~ConfigurationAttribute(); // Crush, Kill, Destroy!
  327. // Attributes can be probed for some simple, useful things.
  328. string Name(); // Get the name of this attribute.
  329. ConfigurationElement& Parent(); // Get the parent of this attribute.
  330. int Line(); // Get the last line number.
  331. int Index(); // Get the last data position.
  332. int Length(); // Get the last length.
  333. void notifyDirty(); // Attributes use this when they change.
  334. // For convenience in building configurations, an Attribute offers
  335. // some call-through methods to it's parrent Element. This allows for
  336. // clear, concise .method() coding that mimics an outline of the
  337. // configuration structure.
  338. //// For switching back to the parent element and adding new sub-elements.
  339. ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name.
  340. ConfigurationElement& Element(const string Name); // Add a new sub element by c++ string name.
  341. //// Mapping element factory methods for convenience.
  342. //// Root-Node elements are _usually_ empty and without attributes in xml
  343. //// so we don't make any of that type of convenience constructor here.
  344. // char* versions
  345. ConfigurationElement& Element( // Mapping factory for convenience,
  346. const char* Name, // requires a name, of course,
  347. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  348. ConfigurationElement& Element( // Mapping factory for convenience,
  349. const char* Name, // requires a name, of course,
  350. string& x, string init = string("")); // Map to a string.
  351. ConfigurationElement& Element( // Mapping factory for convenience,
  352. const char* Name, // requires a name, of course,
  353. int& x, int init = 0, int radix = 0); // Map to an int.
  354. ConfigurationElement& Element( // Mapping factory for convenience,
  355. const char* Name, // requires a name, of course,
  356. double& x, double init = 0.0); // Map to a double.
  357. ConfigurationElement& Element( // Mapping factory for convenience,
  358. const char* Name, // requires a name, of course,
  359. bool& x, bool init = false); // Map to a boolean.
  360. // string versions
  361. ConfigurationElement& Element( // Mapping factory for convenience,
  362. const string Name, // requires a name, of course,
  363. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  364. ConfigurationElement& Element( // Mapping factory for convenience,
  365. const string Name, // requires a name, of course,
  366. string& x, string init = string("")); // Map to a string.
  367. ConfigurationElement& Element( // Mapping factory for convenience,
  368. const string Name, // requires a name, of course,
  369. int& x, int init = 0, int radix = 0); // Map to an int.
  370. ConfigurationElement& Element( // Mapping factory for convenience,
  371. const string Name, // requires a name, of course,
  372. double& x, double init = 0.0); // Map to a double.
  373. ConfigurationElement& Element( // Mapping factory for convenience,
  374. const string Name, // requires a name, of course,
  375. bool& x, bool init = false); // Map to a boolean.
  376. // End methods for heading back up the tree at the end of an element.
  377. ConfigurationElement& End(); // Return this element's parent.
  378. ConfigurationElement& End(const char* Name); // Check the name and return the parent
  379. ConfigurationElement& End(const string Name); // if the name is correct - or throw!
  380. //// For adding new attributes to the parent element.
  381. ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
  382. ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string.
  383. //// Mapping Attribute factory methods for convenience.
  384. // char* versions
  385. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  386. const char* Name, // requires a name, of course,
  387. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  388. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  389. const char* Name, // requires a name, of course,
  390. string& x, string init = string("")); // Map to a string.
  391. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  392. const char* Name, // requires a name, of course,
  393. int& x, int init = 0, int radix = 0); // Map to an int.
  394. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  395. const char* Name, // requires a name, of course,
  396. double& x, double init = 0.0); // Map to a double.
  397. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  398. const char* Name, // requires a name, of course,
  399. bool& x, bool init = false); // Map to a boolean.
  400. // string versions
  401. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  402. const string Name, // requires a name, of course,
  403. ConfigurationTranslator& newTranslator); // Add a Translator to this element.
  404. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  405. const string Name, // requires a name, of course,
  406. string& x, string init = string("")); // Map to a string.
  407. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  408. const string Name, // requires a name, of course,
  409. int& x, int init = 0, int radix = 0); // Map to an int.
  410. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  411. const string Name, // requires a name, of course,
  412. double& x, double init = 0.0); // Map to a double.
  413. ConfigurationAttribute& Attribute( // Mapping factory for convenience,
  414. const string Name, // requires a name, of course,
  415. bool& x, bool init = false); // Map to a boolean.
  416. //// Set Init On Interprete for the parent element.
  417. ConfigurationElement& setInitOnInterpret(); // Set the init on interpret flag.
  418. //// For adding configurators to the parent element.
  419. ConfigurationElement& atStartCall(Configurator& Functor); // Add an atStart call-back to this element.
  420. ConfigurationElement& atEndCall(Configurator& Functor); // Add an atEnd call-back to this element.
  421. // Of course, the most useful thing about attributes is that they can
  422. // be mapped to variables using translators. The same as those that
  423. // apply to the parent element's contents. Here they are for use on this
  424. // attribute.
  425. ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute.
  426. ConfigurationAttribute& mapTo(string& x, string init = string("")); // Map to a string.
  427. ConfigurationAttribute& mapTo(int& x, int init, int radix = 0); // Map to an int.
  428. ConfigurationAttribute& mapTo(double& x, double init = 0.0); // Map to a double.
  429. ConfigurationAttribute& mapTo(bool& x, bool init = false); // Map to a boolean.
  430. // Attributes can have mnemonics just like elements.
  431. ConfigurationAttribute& Mnemonic(const char* name, const char* value); // Add a mnemonic using a c string.
  432. ConfigurationAttribute& Mnemonic(const char* name, const string value); // Add a mnemonic using c & c++ strings.
  433. ConfigurationAttribute& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings.
  434. ConfigurationAttribute& Mnemonic(const string name, const string value); // Add a mnemonic using a c++ string.
  435. // Attributes participate in the Interprete() task just like elements.
  436. void initialize(); // Reset all translators to defaults.
  437. bool interpret(ConfigurationData& Data); // (re) Interpret this data.
  438. };
  439. //// Configuration Data ////////////////////////////////////////////////////////
  440. //
  441. // A ConfigurationData object holds on to the configuration source data and
  442. // provideds a place to log any information about how the configuration was
  443. // interpreted. It also creates and destroys a handy char[] to contain the
  444. // data. To make this beastie easier to handle, we use the Named Constructor
  445. // Idiom and hide the true constructor in the private section.
  446. class ConfigurationData { // Configuration Data Source
  447. private:
  448. char* myDataBuffer; // The actual data buffer.
  449. int myBufferSize; // Size of the current buffer.
  450. int myIndex; // The current interpretation index.
  451. int myLine; // Current line number.
  452. public:
  453. ConfigurationData(const char* FileName); // Constructor from c string file name.
  454. ConfigurationData(const string FileName); // Constructor from c++ string file name.
  455. ConfigurationData(const char* Data, int Length); // Raw constructor from text buffer.
  456. ~ConfigurationData(); // Destroys the internal buffer etc.
  457. char Data(int Index); // Returns char from Data[Index]
  458. int Index(); // Reads the current Index.
  459. int Index(int i); // Changes the current Index.
  460. int Line(); // Reads the current Line number.
  461. int addNewLines(int Count); // Increments the Line number.
  462. stringstream Log; // Convenient Interpret log.
  463. };
  464. //// Configuration Translator //////////////////////////////////////////////////
  465. //
  466. // A Translator converts the contents provided to it in string form into some
  467. // other data type. The object here is a prototype for that, followed by a
  468. // collection of the basic translators used for built-in mapTo()s.
  469. class ConfigurationTranslator { // Translators exist
  470. public:
  471. virtual void translate(const char* Value) = 0; // Pure virtual translator.
  472. virtual void initialize() = 0; // Pure virtual initializer.
  473. };
  474. class StringTranslator : public ConfigurationTranslator {
  475. private:
  476. string& myVariable; // Variable to map.
  477. string myInitializer; // Initial/Default value.
  478. public:
  479. StringTranslator( // Construct this with
  480. string& Variable, // the variable to map,
  481. string Inititializer); // and the default value.
  482. void translate(const char* Value); // Provide a translation method.
  483. void initialize(); // Provide an initialization method.
  484. };
  485. class IntegerTranslator : public ConfigurationTranslator {
  486. private:
  487. int& myVariable; // Variable to map.
  488. int myInitializer; // Initial/Default value.
  489. int myRadix; // Radix for strtol()
  490. public:
  491. IntegerTranslator( // Construct this with
  492. int& Variable, // the variable to map,
  493. int Inititializer, // and the default value.
  494. int Radix); // For this one we also need a Radix.
  495. void translate(const char* Value); // Provide a translation method.
  496. void initialize(); // Provide an initialization method.
  497. };
  498. class DoubleTranslator : public ConfigurationTranslator {
  499. private:
  500. double& myVariable; // Variable to map.
  501. double myInitializer; // Initial/Default value.
  502. public:
  503. DoubleTranslator( // Construct this with
  504. double& Variable, // the variable to map,
  505. double Inititializer); // and the default value.
  506. void translate(const char* Value); // Provide a translation method.
  507. void initialize(); // Provide an initialization method.
  508. };
  509. class BoolTranslator : public ConfigurationTranslator {
  510. private:
  511. bool& myVariable; // Variable to map.
  512. bool myInitializer; // Initial/Default value.
  513. public:
  514. BoolTranslator( // Construct this with
  515. bool& Variable, // the variable to map,
  516. bool Inititializer); // and the default value.
  517. void translate(const char* Value); // Provide a translation method.
  518. void initialize(); // Provide an initialization method.
  519. };
  520. //// Configuration Mnemonic ////////////////////////////////////////////////////
  521. //
  522. // A Mnemonic allows the actual contents of an element or attribute to be
  523. // exchanged for a different "named" value to help eliminate "magic numbers"
  524. // and "secret codes" from configurations. One way this might be used is to
  525. // map an enumeration to the appropriate integer values, or things like YES and
  526. // NO to boolean true and false (respectively) when turning on/off program
  527. // options.
  528. class ConfigurationMnemonic { // Mnemonics
  529. private:
  530. string myName; // What is the Mnemonic?
  531. string myValue; // What is the translation?
  532. public:
  533. ConfigurationMnemonic(string Name, string Value); // To make one, provide both parts.
  534. bool test(string Name); // Test to see if this Mnemonic matches.
  535. string Value(); // If it does then we will need it's value.
  536. };
  537. //// Configurator //////////////////////////////////////////////////////////////
  538. //
  539. // A configurator is a "functor" or "closure" or "callback" that can be used to
  540. // support sophisticated interpretation options. The most basic and necessary
  541. // of these is support for list building. Consider an object created to contain
  542. // a list of records where each record might be represented as a collection of
  543. // attributes and elements. The object would have data elements mapped to the
  544. // attributes and elements in the configuration and then control elements which
  545. // are functors for initializing the list and storing new entries as they are
  546. // completed. The object here is a pure virtual prototype.
  547. class Configurator { // Configurators exist
  548. public:
  549. virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator.
  550. };
  551. //// Include our inline methods ////////////////////////////////////////////////
  552. #include "configuration.inline.hpp"
  553. //// Utilities /////////////////////////////////////////////////////////////////
  554. // SetTrueOnComplete Configurator //////////////////////////////////////////////
  555. class ConfiguratorSetTrueOnComplete : public Configurator { // Configurator set's a boolean true.
  556. private:
  557. bool* myBoolean; // The boolean to set.
  558. public:
  559. ConfiguratorSetTrueOnComplete(); // Must init to NULL for safety.
  560. void setup(bool& Target); // Link to the target boolean.
  561. void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation.
  562. };
  563. #endif
  564. // End Of Include Only Once