configVariableManager.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file configVariableManager.cxx
  10. * @author drose
  11. * @date 2004-10-15
  12. */
  13. #include "configVariableManager.h"
  14. #include "configVariableCore.h"
  15. #include "configDeclaration.h"
  16. #include "configPage.h"
  17. #include "config_prc.h"
  18. using std::string;
  19. ConfigVariableManager *ConfigVariableManager::_global_ptr = nullptr;
  20. /**
  21. * The constructor is private (actually, just protected, but only to avoid a
  22. * gcc compiler warning) because it should not be explicitly constructed.
  23. * There is only one ConfigVariableManager, and it constructs itself.
  24. */
  25. ConfigVariableManager::
  26. ConfigVariableManager() {
  27. init_memory_hook();
  28. }
  29. /**
  30. * The ConfigVariableManager destructor should never be called, because this
  31. * is a global object that is never freed.
  32. */
  33. ConfigVariableManager::
  34. ~ConfigVariableManager() {
  35. prc_cat->error()
  36. << "Internal error--ConfigVariableManager destructor called!\n";
  37. }
  38. /**
  39. * Creates and returns a new, undefined ConfigVariableCore with the indicated
  40. * name; or if a variable with this name has already been created, returns
  41. * that one instead.
  42. */
  43. ConfigVariableCore *ConfigVariableManager::
  44. make_variable(const string &name) {
  45. VariablesByName::iterator ni;
  46. ni = _variables_by_name.find(name);
  47. if (ni != _variables_by_name.end()) {
  48. return (*ni).second;
  49. }
  50. ConfigVariableCore *variable = nullptr;
  51. // See if there's a template that matches this name.
  52. VariableTemplates::const_iterator ti;
  53. for (ti = _variable_templates.begin();
  54. ti != _variable_templates.end() && variable == nullptr;
  55. ++ti) {
  56. const GlobPattern &pattern = (*ti).first;
  57. ConfigVariableCore *templ = (*ti).second;
  58. if (pattern.matches(name)) {
  59. variable = new ConfigVariableCore(*templ, name);
  60. }
  61. }
  62. if (variable == nullptr) {
  63. variable = new ConfigVariableCore(name);
  64. }
  65. _variables_by_name[name] = variable;
  66. _variables.push_back(variable);
  67. return variable;
  68. }
  69. /**
  70. * Defines a variable "template" to match against dynamically-defined
  71. * variables that may or may not be created in the future.
  72. *
  73. * The template consists of a glob pattern, e.g. `notify-level-*`, which will
  74. * be tested against any config variable passed to a future call to
  75. * make_variable(). If the pattern matches, the returned ConfigVariableCore
  76. * is copied to define the new variable, instead of creating a default, empty
  77. * one.
  78. *
  79. * This is useful to pre-specify default values for a family of variables that
  80. * all have similar properties, and all may not be created at the same time.
  81. * It is especially useful to avoid cluttering up the list of available
  82. * variables with user-declared variables that have not been defined yet by
  83. * the application (e.g. `egg-object-type-*`).
  84. *
  85. * This method basically pre-defines all variables that match the specified
  86. * glob pattern.
  87. */
  88. ConfigVariableCore *ConfigVariableManager::
  89. make_variable_template(const string &pattern,
  90. ConfigFlags::ValueType value_type,
  91. const string &default_value,
  92. const string &description, int flags) {
  93. ConfigVariableCore *core;
  94. GlobPattern gp(pattern);
  95. VariableTemplates::const_iterator ti = _variable_templates.find(gp);
  96. if (ti != _variable_templates.end()) {
  97. core = (*ti).second;
  98. } else {
  99. core = new ConfigVariableCore(pattern);
  100. _variable_templates[gp] = core;
  101. }
  102. if (value_type != ConfigFlags::VT_undefined) {
  103. core->set_value_type(value_type);
  104. }
  105. if (!default_value.empty() ||
  106. core->get_default_value() == nullptr) {
  107. core->set_default_value(default_value);
  108. }
  109. if (!description.empty()) {
  110. core->set_description(description);
  111. }
  112. if (flags != 0) {
  113. core->set_flags(flags);
  114. }
  115. core->set_used();
  116. // Also apply the same changes to any previously-defined variables that
  117. // match the pattern.
  118. Variables::iterator vi;
  119. for (vi = _variables.begin(); vi != _variables.end(); ++vi) {
  120. ConfigVariableCore *variable = (*vi);
  121. if (gp.matches(variable->get_name())) {
  122. if (value_type != ConfigFlags::VT_undefined) {
  123. variable->set_value_type(value_type);
  124. }
  125. if (!default_value.empty() ||
  126. variable->get_default_value() == nullptr) {
  127. variable->set_default_value(default_value);
  128. }
  129. if (!description.empty()) {
  130. variable->set_description(description);
  131. }
  132. if (flags != 0) {
  133. variable->set_flags(flags);
  134. }
  135. variable->set_used();
  136. }
  137. }
  138. return core;
  139. }
  140. /**
  141. * Returns the name of the nth active ConfigVariable in the list.
  142. */
  143. string ConfigVariableManager::
  144. get_variable_name(size_t n) const {
  145. if (n < _variables.size()) {
  146. return _variables[n]->get_name();
  147. }
  148. return string();
  149. }
  150. /**
  151. * Returns true if the nth active ConfigVariable in the list has been used by
  152. * code, false otherwise.
  153. */
  154. bool ConfigVariableManager::
  155. is_variable_used(size_t n) const {
  156. if (n < _variables.size()) {
  157. return _variables[n]->is_used();
  158. }
  159. return false;
  160. }
  161. /**
  162. *
  163. */
  164. void ConfigVariableManager::
  165. output(std::ostream &out) const {
  166. out << "ConfigVariableManager, " << _variables.size() << " variables.";
  167. }
  168. /**
  169. *
  170. */
  171. void ConfigVariableManager::
  172. write(std::ostream &out) const {
  173. VariablesByName::const_iterator ni;
  174. for (ni = _variables_by_name.begin();
  175. ni != _variables_by_name.end();
  176. ++ni) {
  177. ConfigVariableCore *variable = (*ni).second;
  178. if (variable->get_num_trusted_references() != 0 ||
  179. variable->has_local_value()) {
  180. list_variable(variable, false);
  181. }
  182. }
  183. }
  184. /**
  185. * Writes all of the prc-set config variables, as they appear in a prc file
  186. * somewhere, one per line, very concisely. This lists the dominant value in
  187. * the prc file; it does not list shadowed values, and it does not list
  188. * locally-set values.
  189. *
  190. * This is mainly intended for generating a hash of the input config file
  191. * state.
  192. */
  193. void ConfigVariableManager::
  194. write_prc_variables(std::ostream &out) const {
  195. VariablesByName::const_iterator ni;
  196. for (ni = _variables_by_name.begin();
  197. ni != _variables_by_name.end();
  198. ++ni) {
  199. ConfigVariableCore *variable = (*ni).second;
  200. if (variable->get_num_trusted_references() != 0) {
  201. if (variable->get_value_type() == ConfigVariableCore::VT_list ||
  202. variable->get_value_type() == ConfigVariableCore::VT_search_path) {
  203. // List all of the values for a "list" variable.
  204. size_t num_references = variable->get_num_trusted_references();
  205. for (size_t i = 0; i < num_references; ++i) {
  206. out << variable->get_name() << " "
  207. << variable->get_trusted_reference(i)->get_string_value()
  208. << "\n";
  209. }
  210. } else {
  211. // List just the one value for a non-list variable.
  212. out << variable->get_name() << " "
  213. << variable->get_trusted_reference(0)->get_string_value()
  214. << "\n";
  215. }
  216. }
  217. }
  218. }
  219. /**
  220. * Writes a list of all the variables that have been defined in a prc file
  221. * without having been declared somewhere in code.
  222. */
  223. void ConfigVariableManager::
  224. list_unused_variables() const {
  225. VariablesByName::const_iterator ni;
  226. for (ni = _variables_by_name.begin();
  227. ni != _variables_by_name.end();
  228. ++ni) {
  229. ConfigVariableCore *variable = (*ni).second;
  230. if (!variable->is_used()) {
  231. nout << variable->get_name() << "\n";
  232. size_t num_references = variable->get_num_references();
  233. for (size_t i = 0; i < num_references; i++) {
  234. nout << " " << variable->get_reference(i)->get_page()->get_name()
  235. << "\n";
  236. }
  237. }
  238. }
  239. }
  240. /**
  241. * Writes a list of all the variables that have been declared somewhere in
  242. * code, along with a brief description.
  243. */
  244. void ConfigVariableManager::
  245. list_variables() const {
  246. VariablesByName::const_iterator ni;
  247. for (ni = _variables_by_name.begin();
  248. ni != _variables_by_name.end();
  249. ++ni) {
  250. const ConfigVariableCore *variable = (*ni).second;
  251. if (variable->is_used() && !variable->is_dynamic()) {
  252. list_variable(variable, true);
  253. }
  254. }
  255. }
  256. /**
  257. * Writes a list of all the "dynamic" variables that have been declared
  258. * somewhere in code, along with a brief description. This is a (usually
  259. * large) list of config variables that are declared with a generated variable
  260. * name.
  261. */
  262. void ConfigVariableManager::
  263. list_dynamic_variables() const {
  264. VariablesByName::const_iterator ni;
  265. for (ni = _variables_by_name.begin();
  266. ni != _variables_by_name.end();
  267. ++ni) {
  268. const ConfigVariableCore *variable = (*ni).second;
  269. if (variable->is_used() && variable->is_dynamic()) {
  270. list_variable(variable, false);
  271. }
  272. }
  273. }
  274. /**
  275. *
  276. */
  277. ConfigVariableManager *ConfigVariableManager::
  278. get_global_ptr() {
  279. if (_global_ptr == nullptr) {
  280. _global_ptr = new ConfigVariableManager;
  281. }
  282. return _global_ptr;
  283. }
  284. /**
  285. * Lists a single variable and its value.
  286. */
  287. void ConfigVariableManager::
  288. list_variable(const ConfigVariableCore *variable,
  289. bool include_descriptions) const {
  290. if (!variable->is_used()) {
  291. // If the variable is unused, just show its name.
  292. nout << variable->get_name() << " not used";
  293. if (variable->get_num_references() > 0) {
  294. nout << " (referenced in "
  295. << variable->get_reference(0)->get_page()->get_name()
  296. << ")";
  297. }
  298. nout << "\n";
  299. } else {
  300. // If the variable is used--it's been defined somewhere--show its name,
  301. // its type, its current and default values, and if available, its
  302. // description.
  303. nout << variable->get_name() << " "
  304. << variable->get_value_type() << "\n";
  305. const ConfigDeclaration *decl;
  306. if (variable->get_value_type() == ConfigVariableCore::VT_list ||
  307. variable->get_value_type() == ConfigVariableCore::VT_search_path) {
  308. // We treat a "list" variable as a special case: list all of its values.
  309. nout << " current value:\n";
  310. size_t num_references = variable->get_num_trusted_references();
  311. for (size_t i = 0; i < num_references; ++i) {
  312. decl = variable->get_trusted_reference(i);
  313. nout << " " << decl->get_string_value()
  314. << " (from " << decl->get_page()->get_name() << ")\n";
  315. }
  316. } else {
  317. // An ordinary, non-list variable gets one line for its current value
  318. // (if it has one) and another line for its default value.
  319. decl = variable->get_declaration(0);
  320. if (decl != variable->get_default_value()) {
  321. nout << " current value = " << decl->get_string_value();
  322. if (!decl->get_page()->is_special()) {
  323. nout << " (from " << decl->get_page()->get_name() << ")\n";
  324. } else {
  325. nout << " (defined locally)\n";
  326. }
  327. }
  328. decl = variable->get_default_value();
  329. if (decl != nullptr) {
  330. nout << " default value = " << decl->get_string_value() << "\n";
  331. }
  332. }
  333. if (!variable->get_description().empty() && include_descriptions) {
  334. nout << " " << variable->get_description() << "\n";
  335. }
  336. }
  337. nout << "\n";
  338. }