]> Dogcows Code - chaz/yoink/blobdiff - src/stlplus/subsystems/library_manager.cpp
testing new non-autotools build system
[chaz/yoink] / src / stlplus / subsystems / library_manager.cpp
diff --git a/src/stlplus/subsystems/library_manager.cpp b/src/stlplus/subsystems/library_manager.cpp
new file mode 100644 (file)
index 0000000..0daf1be
--- /dev/null
@@ -0,0 +1,2332 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "library_manager.hpp"\r
+#include "file_system.hpp"\r
+#include <algorithm>\r
+#include <fstream>\r
+#include <ctype.h>\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+static const char* LibraryNameExtension = "lmn";\r
+static const char* HeaderExtension = "lmh";\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// local operations\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+typedef std::map<std::string,stlplus::lm_callback_entry> lm_callback_map;\r
+\r
+static std::string lowercase(const std::string& val)\r
+{\r
+  std::string text = val;\r
+  for (unsigned i = 0; i < text.size(); i++)\r
+    text[i] = tolower(text[i]);\r
+  return text;\r
+}\r
+\r
+// Context file and library operations\r
+// These must be readable/writeable without a library data structure present\r
+// so that the name of the library is known before creation\r
+\r
+static bool read_context(const std::string& path, const std::string& owner, std::string& name, bool& writable)\r
+{\r
+  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
+  name = "";\r
+  writable = false;\r
+  if (!stlplus::file_exists(spec)) return false;\r
+  std::ifstream input(spec.c_str());\r
+  input >> name >> writable;\r
+  return !input.fail();\r
+}\r
+\r
+static bool write_context(const std::string& path, const std::string& owner, const std::string& name, bool writable)\r
+{\r
+  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
+  std::ofstream output(spec.c_str());\r
+  output << name << " " << writable << std::endl;\r
+  return !output.fail();\r
+}\r
+\r
+static bool create_library(const std::string& path, const std::string& owner, const std::string& name, bool writable)\r
+{\r
+  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
+  if (stlplus::is_present(path) && !stlplus::is_folder(path)) return false;\r
+  if (!stlplus::folder_exists(path) && !stlplus::folder_create(path)) return false;\r
+  return write_context(path, owner, name, writable);\r
+}\r
+\r
+static bool erase_library(const std::string& path, const std::string& owner)\r
+{\r
+  // check that it is a library before deleting it!\r
+  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
+  if (!stlplus::file_exists(spec)) return false;\r
+  return stlplus::folder_delete(path, true);\r
+}\r
+\r
+// dependency checking\r
+\r
+typedef std::map<std::pair<std::string,stlplus::lm_unit_name>,stlplus::lm_dependencies> visited_map;\r
+\r
+static stlplus::lm_dependencies& out_of_date_check (visited_map& visited,\r
+                                                    const stlplus::library_manager* manager,\r
+                                                    const std::string& library,\r
+                                                    const stlplus::lm_unit_name& name)\r
+{\r
+  // the visited field contains an entry if a unit has been visited - it also contains the reason for out-of-date-ness\r
+  // this is initially set empty (up to date) since the unit has to be added\r
+  // before it is checked just in case there is a recursive loop\r
+  // the dependencies field is filled in if the unit is subsequently found to be out of date\r
+  std::pair<std::string,stlplus::lm_unit_name> full_name = std::make_pair(library,name);\r
+  // first check whether this unit has already been visited - this should in\r
+  // principle never happen because the same test is performed before trying\r
+  // to recurse, so consider this to be paranoid-mode programming\r
+  visited_map::iterator found = visited.find(full_name);\r
+  if (found != visited.end())\r
+    return found->second;\r
+  // now add this unit to prevent recursion loops later. This entry is added\r
+  // to when out-of-date dependencies are found and is also the return value\r
+  // of the function\r
+  visited[full_name] = stlplus::lm_dependencies();\r
+  // now find the unit\r
+  const stlplus::lm_unit_ptr unit = manager->find(library,name);\r
+  if (!unit)\r
+  {\r
+    // if a unit is missing it fails with a dependency on itself - this is a\r
+    // bit of a work-around, but this again is paranoid-mode programming since\r
+    // the calling function (this function calling itself recursively) should\r
+    // check the unit's existence before recursing\r
+    visited[full_name].unit_add(stlplus::lm_unit_dependency(library,name));\r
+  }\r
+  else\r
+  {\r
+    // we're onto the real checks now - first get the datestamp of this unit:\r
+    // all dependencies must be older than this\r
+    time_t unit_modified = unit->modified();\r
+    // check dependency on source file if there is one\r
+    if (unit->source_file_present())\r
+    {\r
+      std::string source_file = unit->source_file().path_full(unit->library_path());\r
+      time_t source_modified = stlplus::file_modified(source_file);\r
+      if (source_modified == 0 || source_modified > unit_modified)\r
+      {\r
+        visited[full_name].set_source_file(unit->source_file());\r
+      }\r
+    }\r
+    // now check the other file dependencies\r
+    for (unsigned i = 0; i < unit->file_size(); i++)\r
+    {\r
+      // a file dependency is a dependency on a file outside of the library system\r
+      const stlplus::lm_file_dependency& dependency = unit->file_dependency(i);\r
+      std::string file_full = dependency.path_full(unit->library_path());\r
+      time_t source_modified = stlplus::file_modified(file_full);\r
+      if (source_modified == 0 || source_modified > unit_modified)\r
+      {\r
+        visited[full_name].file_add(dependency);\r
+      }\r
+    }\r
+    // now check and recurse on unit dependencies\r
+    for (unsigned j = 0; j < unit->unit_size(); j++)\r
+    {\r
+      const stlplus::lm_unit_dependency& dependency = unit->unit_dependency(j);\r
+      std::pair<std::string,stlplus::lm_unit_name> other_name = std::make_pair(dependency.library(), dependency.unit_name());\r
+      // perform the datestamp checking at this level and only recurse if this does not detect an error\r
+      const stlplus::lm_unit_ptr other_unit = manager->find(other_name.first, other_name.second);\r
+      if (!other_unit)\r
+      {\r
+        visited[full_name].unit_add(dependency);\r
+      }\r
+      else\r
+      {\r
+        time_t other_modified = other_unit->modified();\r
+        if (other_modified == 0 || other_modified > unit_modified)\r
+        {\r
+          visited[full_name].unit_add(dependency);\r
+        }\r
+        else\r
+        {\r
+          // prevent recursion before doing it\r
+          visited_map::iterator other_found = visited.find(other_name);\r
+          if (other_found != visited.end())\r
+          {\r
+            // if the unit was found to be out of date on the previous visit, add it to the failed dependencies\r
+            if (!other_found->second.empty())\r
+            {\r
+              visited[full_name].unit_add(dependency);\r
+            }\r
+          }\r
+          else\r
+          {\r
+            // the unit hasn't been visited before, so recurse on it now\r
+            stlplus::lm_dependencies other_dependencies = \r
+              out_of_date_check(visited, manager, other_name.first, other_name.second);\r
+            if (!other_dependencies.empty())\r
+            {\r
+              visited[full_name].unit_add(dependency);\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return visited[full_name];\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// class lm_unit_name\r
+\r
+stlplus::lm_unit_name::lm_unit_name(const std::string& name, const std::string& type) :\r
+  m_name(name), m_type(type)\r
+{\r
+}\r
+\r
+stlplus::lm_unit_name::~lm_unit_name(void)\r
+{\r
+}\r
+\r
+const std::string& stlplus::lm_unit_name::name(void) const\r
+{\r
+  return m_name;\r
+}\r
+\r
+void stlplus::lm_unit_name::set_name(const std::string& name)\r
+{\r
+  m_name = name;\r
+}\r
+\r
+void stlplus::lm_unit_name::lowercase(void)\r
+{\r
+  m_name = ::lowercase(m_name);\r
+}\r
+\r
+const std::string& stlplus::lm_unit_name::type(void) const\r
+{\r
+  return m_type;\r
+}\r
+\r
+void stlplus::lm_unit_name::set_type(const std::string& type)\r
+{\r
+  m_type = type;\r
+}\r
+\r
+bool stlplus::lm_unit_name::write(std::ostream& context) const\r
+{\r
+  context << m_name << " " << m_type;\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_unit_name::read(std::istream& context)\r
+{\r
+  context >> m_name >> m_type;\r
+  return !context.fail();\r
+}\r
+\r
+std::string stlplus::lm_unit_name::to_string(void) const\r
+{\r
+  return m_name + ":" + m_type;\r
+}\r
+\r
+bool stlplus::lm_unit_name::print(std::ostream& str) const\r
+{\r
+  str << to_string();\r
+  return !str.fail();\r
+}\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_name& name)\r
+{\r
+  name.print(str);\r
+  return str;\r
+}\r
+\r
+bool stlplus::operator == (const stlplus::lm_unit_name& l, const stlplus::lm_unit_name& r)\r
+{\r
+  return l.name() == r.name() && l.type() == r.type();\r
+}\r
+\r
+bool stlplus::operator < (const stlplus::lm_unit_name& l, const stlplus::lm_unit_name& r)\r
+{\r
+  // sort by name then type\r
+  return (l.name() != r.name()) ? l.name() < r.name() : l.type() < r.type();\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// dependencies\r
+\r
+// file dependencies\r
+\r
+stlplus::lm_file_dependency::lm_file_dependency(void) : m_line(0), m_column(0)\r
+{\r
+}\r
+\r
+stlplus::lm_file_dependency::lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line, unsigned column)\r
+{\r
+  set_path(library_path, path);\r
+  set_line(line);\r
+  set_column(column);\r
+}\r
+\r
+stlplus::lm_file_dependency::~lm_file_dependency(void)\r
+{\r
+}\r
+\r
+const std::string& stlplus::lm_file_dependency::path(void) const\r
+{\r
+  return m_path;\r
+}\r
+\r
+std::string stlplus::lm_file_dependency::path_full(const std::string& library_path) const\r
+{\r
+  return filespec_to_path(library_path, m_path);\r
+}\r
+\r
+void stlplus::lm_file_dependency::set_path(const std::string& library_path, const std::string& path)\r
+{\r
+  m_path = filespec_to_relative_path(library_path, path);\r
+}\r
+\r
+unsigned stlplus::lm_file_dependency::line(void) const\r
+{\r
+  return m_line;\r
+}\r
+\r
+void stlplus::lm_file_dependency::set_line(unsigned line)\r
+{\r
+  m_line = line;\r
+}\r
+\r
+unsigned stlplus::lm_file_dependency::column(void) const\r
+{\r
+  return m_column;\r
+}\r
+\r
+void stlplus::lm_file_dependency::set_column(unsigned column)\r
+{\r
+  m_column = column;\r
+}\r
+\r
+bool stlplus::lm_file_dependency::write(std::ostream& context) const\r
+{\r
+  context << m_path << " " << m_line << " " << m_column;\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_file_dependency::read(std::istream& context)\r
+{\r
+  context >> m_path >> m_line >> m_column;\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_file_dependency::print(std::ostream& str) const\r
+{\r
+  str << "file: " << m_path;\r
+  if (m_line != 0)\r
+    str << ":" << m_line << ":" << m_column;\r
+  return !str.fail();\r
+}\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_file_dependency& dependency)\r
+{\r
+  dependency.print(str);\r
+  return str;\r
+}\r
+\r
+// unit dependency\r
+\r
+stlplus::lm_unit_dependency::lm_unit_dependency(void)\r
+{\r
+}\r
+\r
+stlplus::lm_unit_dependency::lm_unit_dependency(const std::string& library, const lm_unit_name& name) : \r
+  m_library(library), m_name(name)\r
+{\r
+}\r
+\r
+stlplus::lm_unit_dependency::~lm_unit_dependency(void)\r
+{\r
+}\r
+\r
+const std::string& stlplus::lm_unit_dependency::library(void) const\r
+{\r
+  return m_library;\r
+}\r
+\r
+void stlplus::lm_unit_dependency::set_library(const std::string& library)\r
+{\r
+  m_library = library;\r
+}\r
+\r
+const stlplus::lm_unit_name& stlplus::lm_unit_dependency::unit_name(void) const\r
+{\r
+  return m_name;\r
+}\r
+\r
+void stlplus::lm_unit_dependency::set_unit_name(const lm_unit_name& unit_name)\r
+{\r
+  m_name = unit_name;\r
+}\r
+\r
+const std::string& stlplus::lm_unit_dependency::name(void) const\r
+{\r
+  return m_name.name();\r
+}\r
+\r
+void stlplus::lm_unit_dependency::set_name(const std::string& name)\r
+{\r
+  m_name.set_name(name);\r
+}\r
+\r
+const std::string& stlplus::lm_unit_dependency::type(void) const\r
+{\r
+  return m_name.type();\r
+}\r
+\r
+void stlplus::lm_unit_dependency::set_type(const std::string& type)\r
+{\r
+  m_name.set_type(type);\r
+}\r
+\r
+bool stlplus::lm_unit_dependency::write(std::ostream& context) const\r
+{\r
+  context << m_library;\r
+  m_name.write(context);\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_unit_dependency::read(std::istream& context)\r
+{\r
+  context >> m_library;\r
+  m_name.read(context);;\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_unit_dependency::print(std::ostream& str) const\r
+{\r
+  str << "unit: " << m_library << "." << m_name;\r
+  return !str.fail();\r
+}\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_dependency& dependency)\r
+{\r
+  dependency.print(str);\r
+  return str;\r
+}\r
+\r
+// dependencies\r
+\r
+stlplus::lm_dependencies::lm_dependencies(void) : m_source(0)\r
+{\r
+}\r
+\r
+stlplus::lm_dependencies::lm_dependencies(const lm_dependencies& r) : m_source(0)\r
+{\r
+  *this = r;\r
+}\r
+\r
+stlplus::lm_dependencies& stlplus::lm_dependencies::operator=(const stlplus::lm_dependencies& r)\r
+{\r
+  if (m_source)\r
+    delete m_source;\r
+  m_source = 0;\r
+  if (r.m_source)\r
+    m_source = new lm_file_dependency(*r.m_source);\r
+  m_files = r.m_files;\r
+  m_units = r.m_units;\r
+  return *this;\r
+}\r
+\r
+stlplus::lm_dependencies::~lm_dependencies(void)\r
+{\r
+  if (m_source)\r
+    delete m_source;\r
+}\r
+\r
+void stlplus::lm_dependencies::set_source_file(const lm_file_dependency& source)\r
+{\r
+  if (m_source)\r
+    delete m_source;\r
+  m_source = new lm_file_dependency(source);\r
+}\r
+\r
+bool stlplus::lm_dependencies::source_file_present(void) const\r
+{\r
+  return (m_source != 0);\r
+}\r
+\r
+const stlplus::lm_file_dependency& stlplus::lm_dependencies::source_file(void) const\r
+{\r
+  return *m_source;\r
+}\r
+\r
+unsigned stlplus::lm_dependencies::file_add(const lm_file_dependency& dependency)\r
+{\r
+  m_files.push_back(dependency);\r
+  return m_files.size()-1;\r
+}\r
+\r
+unsigned stlplus::lm_dependencies::file_size(void) const\r
+{\r
+  return m_files.size();\r
+}\r
+\r
+const stlplus::lm_file_dependency& stlplus::lm_dependencies::file_dependency(unsigned i) const\r
+{\r
+  return m_files[i];\r
+}\r
+\r
+void stlplus::lm_dependencies::file_erase(unsigned i)\r
+{\r
+  m_files.erase(m_files.begin()+i);\r
+}\r
+\r
+unsigned stlplus::lm_dependencies::unit_add(const lm_unit_dependency& dependency)\r
+{\r
+  m_units.push_back(dependency);\r
+  return m_units.size()-1;\r
+}\r
+\r
+unsigned stlplus::lm_dependencies::unit_size(void) const\r
+{\r
+  return m_units.size();\r
+}\r
+\r
+const stlplus::lm_unit_dependency& stlplus::lm_dependencies::unit_dependency(unsigned i) const\r
+{\r
+  return m_units[i];\r
+}\r
+\r
+void stlplus::lm_dependencies::unit_erase(unsigned i)\r
+{\r
+  m_units.erase(m_units.begin()+i);\r
+}\r
+\r
+void stlplus::lm_dependencies::clear(void)\r
+{\r
+  if (m_source)\r
+    delete m_source;\r
+  m_source = 0;\r
+  m_files.clear();\r
+  m_units.clear();\r
+}\r
+\r
+bool stlplus::lm_dependencies::empty(void) const\r
+{\r
+  return (m_source == 0) && m_files.empty() && m_units.empty();\r
+}\r
+\r
+bool stlplus::lm_dependencies::write(std::ostream& context) const\r
+{\r
+  context << (m_source ? true : false) << " ";\r
+  if (m_source) m_source->write(context);\r
+  context << std::endl;\r
+  context << m_files.size() << std::endl;\r
+  for (unsigned i = 0; i < m_files.size(); i++)\r
+  {\r
+    m_files[i].write(context);\r
+    context << std::endl;\r
+  }\r
+  context << m_units.size() << std::endl;\r
+  for (unsigned j = 0; j < m_units.size(); j++)\r
+  {\r
+    m_units[j].write(context);\r
+    context << std::endl;\r
+  }\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_dependencies::read(std::istream& context)\r
+{\r
+  clear();\r
+  bool source_present = false;\r
+  context >> source_present;\r
+  if (source_present)\r
+  {\r
+    m_source = new lm_file_dependency();\r
+    m_source->read(context);\r
+  }\r
+  unsigned files_size = 0;\r
+  context >> files_size;\r
+  for (unsigned i = 0; i < files_size; i++)\r
+  {\r
+    m_files.push_back(lm_file_dependency());\r
+    m_files.back().read(context);\r
+  }\r
+  unsigned units_size = 0;\r
+  context >> units_size;\r
+  for (unsigned j = 0; j < units_size; j++)\r
+  {\r
+    m_units.push_back(lm_unit_dependency());\r
+    m_units.back().read(context);\r
+  }\r
+  return !context.fail();\r
+}\r
+\r
+bool stlplus::lm_dependencies::print(std::ostream& str) const\r
+{\r
+  if (m_source)\r
+    str << "  source file: " << *m_source << std::endl;\r
+  for (unsigned i = 0; i < m_files.size(); i++)\r
+    str << "  " << m_files[i] << std::endl;\r
+  for (unsigned j = 0; j < m_units.size(); j++)\r
+    str << "  " << m_units[j] << std::endl;\r
+  return !str.fail();\r
+}\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_dependencies& dependencies)\r
+{\r
+  dependencies.print(str);\r
+  return str;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// lm_unit\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+stlplus::lm_unit::lm_unit(const lm_unit_name& name, lm_library* library) : \r
+  m_name(name), m_header_modified(false), m_loaded(false), m_marked(false), m_library(library), m_error(false)\r
+{\r
+  read_header();\r
+}\r
+\r
+stlplus::lm_unit::~lm_unit(void)\r
+{\r
+  write_header();\r
+}\r
+\r
+////////////////////////////////////////\r
+// Header data\r
+\r
+const stlplus::lm_unit_name& stlplus::lm_unit::unit_name(void) const\r
+{\r
+  return m_name;\r
+}\r
+\r
+const std::string& stlplus::lm_unit::name(void) const\r
+{\r
+  return m_name.name();\r
+}\r
+\r
+const std::string& stlplus::lm_unit::type(void) const\r
+{\r
+  return m_name.type();\r
+}\r
+\r
+// dependencies\r
+\r
+// source file dependency\r
+\r
+void stlplus::lm_unit::set_source_file(const lm_file_dependency& dependency)\r
+{\r
+  m_header_modified = true;\r
+  m_dependencies.set_source_file(dependency);\r
+}\r
+\r
+bool stlplus::lm_unit::source_file_present(void) const\r
+{\r
+  return m_dependencies.source_file_present();\r
+}\r
+\r
+const stlplus::lm_file_dependency& stlplus::lm_unit::source_file(void) const\r
+{\r
+  return m_dependencies.source_file();\r
+}\r
+\r
+// other file dependencies\r
+\r
+unsigned stlplus::lm_unit::file_add(const lm_file_dependency& dependency)\r
+{\r
+  m_header_modified = true;\r
+  return m_dependencies.file_add(dependency);\r
+}\r
+\r
+unsigned stlplus::lm_unit::file_size(void) const\r
+{\r
+  return m_dependencies.file_size();\r
+}\r
+\r
+const stlplus::lm_file_dependency& stlplus::lm_unit::file_dependency(unsigned i) const\r
+{\r
+  return m_dependencies.file_dependency(i);\r
+}\r
+\r
+void stlplus::lm_unit::file_erase(unsigned i)\r
+{\r
+  m_header_modified = true;\r
+  m_dependencies.file_erase(i);\r
+}\r
+\r
+// unit dependencies\r
+\r
+unsigned stlplus::lm_unit::unit_add(const lm_unit_dependency& dependency)\r
+{\r
+  m_header_modified = true;\r
+  return m_dependencies.unit_add(dependency);\r
+}\r
+\r
+unsigned stlplus::lm_unit::unit_size(void) const\r
+{\r
+  return m_dependencies.unit_size();\r
+}\r
+\r
+const stlplus::lm_unit_dependency& stlplus::lm_unit::unit_dependency(unsigned i) const\r
+{\r
+  return m_dependencies.unit_dependency(i);\r
+}\r
+\r
+void stlplus::lm_unit::unit_erase(unsigned i)\r
+{\r
+  m_header_modified = true;\r
+  m_dependencies.unit_erase(i);\r
+}\r
+\r
+const stlplus::lm_dependencies& stlplus::lm_unit::dependencies(void) const\r
+{\r
+  return m_dependencies;\r
+}\r
+\r
+void stlplus::lm_unit::set_dependencies(const lm_dependencies& dependencies)\r
+{\r
+  m_header_modified = true;\r
+  m_dependencies = dependencies;\r
+}\r
+\r
+void stlplus::lm_unit::clear_dependencies(void)\r
+{\r
+  m_header_modified = true;\r
+  m_dependencies.clear();\r
+}\r
+\r
+bool stlplus::lm_unit::empty_dependencies(void) const\r
+{\r
+  return m_dependencies.empty();\r
+}\r
+\r
+// dependency checking\r
+\r
+bool stlplus::lm_unit::out_of_date(void) const\r
+{\r
+  return m_library->out_of_date(m_name);\r
+}\r
+\r
+bool stlplus::lm_unit::up_to_date(void) const\r
+{\r
+  return m_library->up_to_date(m_name);\r
+}\r
+\r
+stlplus::lm_dependencies stlplus::lm_unit::out_of_date_reason(void) const\r
+{\r
+  return m_library->out_of_date_reason(m_name);\r
+}\r
+\r
+// supplementary data\r
+\r
+const std::string& stlplus::lm_unit::supplementary_data(void) const\r
+{\r
+  return m_supplement;\r
+}\r
+\r
+void stlplus::lm_unit::set_supplementary_data(const std::string& data)\r
+{\r
+  m_supplement = data;\r
+  m_header_modified = true;\r
+}\r
+\r
+////////////////////////////////////////\r
+// unit data management\r
+\r
+bool stlplus::lm_unit::load(void)\r
+{\r
+  if (out_of_date()) return false;\r
+  if (m_loaded) return true;\r
+  // get the user data for this type\r
+  lm_callback_map::iterator callback = m_library->m_manager->m_callbacks.find(type());\r
+  if (callback == m_library->m_manager->m_callbacks.end()) return false;\r
+  void* data = callback->second.m_type_data;\r
+  bool result = read(filename(), data);\r
+  m_loaded = true;\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_unit::save(void)\r
+{\r
+  if (!m_marked) return true;\r
+  if (!m_loaded) return false;\r
+  // get the user data for this type\r
+  lm_callback_map::iterator callback = m_library->m_manager->m_callbacks.find(type());\r
+  if (callback == m_library->m_manager->m_callbacks.end()) return false;\r
+  void* data = callback->second.m_type_data;\r
+  bool result = write(filename(), data);\r
+  if (result) m_marked = false;\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_unit::loaded(void) const\r
+{\r
+  return m_loaded;\r
+}\r
+\r
+void stlplus::lm_unit::mark(void)\r
+{\r
+  m_marked = true;\r
+}\r
+\r
+time_t stlplus::lm_unit::modified(void) const\r
+{\r
+  return file_modified(filename());\r
+}\r
+\r
+////////////////////////////////////////\r
+// containing library manager details\r
+\r
+const stlplus::lm_library* stlplus::lm_unit::library(void) const\r
+{\r
+  return m_library;\r
+}\r
+\r
+stlplus::lm_library* stlplus::lm_unit::library(void)\r
+{\r
+  return m_library;\r
+}\r
+\r
+const std::string& stlplus::lm_unit::library_name(void) const\r
+{\r
+  return m_library->name();\r
+}\r
+\r
+const std::string& stlplus::lm_unit::library_path(void) const\r
+{\r
+  return m_library->path();\r
+}\r
+\r
+// error handling - these apply to the last read/write operation\r
+\r
+bool stlplus::lm_unit::error(void) const\r
+{\r
+  return m_error;\r
+}\r
+\r
+// functions that customise subclasses of this superclass\r
+\r
+bool stlplus::lm_unit::read(const std::string& filespec, void* type_data)\r
+{\r
+  std::ifstream input(filespec.c_str());\r
+  bool result = read(input, type_data);\r
+  if (input.fail())\r
+  {\r
+    result = false;\r
+    m_error = true;\r
+  }\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_unit::read(std::istream&, void*)\r
+{\r
+  return false;\r
+}\r
+\r
+bool stlplus::lm_unit::write(const std::string& filespec, void* type_data)\r
+{\r
+  std::ofstream output(filespec.c_str());\r
+  bool result = write(output, type_data);\r
+  if (output.fail())\r
+  {\r
+    result = false;\r
+    m_error = true;\r
+  }\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_unit::write(std::ostream&, void*)\r
+{\r
+  return false;\r
+}\r
+\r
+bool stlplus::lm_unit::purge(void)\r
+{\r
+  return true;\r
+}\r
+\r
+stlplus::lm_unit* stlplus::lm_unit::clone(void) const\r
+{\r
+  return new lm_unit(*this);\r
+}\r
+\r
+bool stlplus::lm_unit::print(std::ostream& str) const\r
+{\r
+  str << m_name << " " << (m_loaded ? "loaded" : "") << " " << (m_marked ? "needs saving" : "");\r
+  return !str.fail();\r
+}\r
+\r
+bool stlplus::lm_unit::print_long(std::ostream& str) const\r
+{\r
+  str << "header:" << std::endl;\r
+  str << "  name: " << m_name.name() << std::endl;\r
+  str << "  type: " << library()->manager()->description(m_name.type()) << std::endl;\r
+  str << "  dependencies:" << std::endl;\r
+  // Note: I've inlined this rather than call the above-defined print for dependencies\r
+  // This is so that I can use the library manager to look up the descriptions of unit types\r
+  // I can also convert paths so that they are relative to the current directory rather than the library\r
+  // print the source file dependency if present\r
+  if (m_dependencies.source_file_present())\r
+  {\r
+    str << "  source file: ";\r
+    str << filespec_to_relative_path(m_dependencies.source_file().path_full(library()->path()));\r
+    if (m_dependencies.source_file().line() != 0)\r
+      str << ":" << m_dependencies.source_file().line() << ":" << m_dependencies.source_file().column();\r
+    str << std::endl;\r
+  }\r
+  // now print other file dependencies\r
+  // convert these to relative paths too\r
+  for (unsigned f = 0; f < m_dependencies.file_size(); f++)\r
+  {\r
+    str << "  file: ";\r
+    str << filespec_to_relative_path(m_dependencies.file_dependency(f).path_full(library()->path()));\r
+    if (m_dependencies.file_dependency(f).line() != 0)\r
+      str << ":" << m_dependencies.file_dependency(f).line() << ":" << m_dependencies.file_dependency(f).column();\r
+    str << std::endl;\r
+  }\r
+  // now print unit dependencies\r
+  // convert unit types to their descriptive strings\r
+  for (unsigned u = 0; u < m_dependencies.unit_size(); u++)\r
+  {\r
+    str << "  " << library()->manager()->description(m_dependencies.unit_dependency(u).type()) << ": ";\r
+    str << m_dependencies.unit_dependency(u).library() << "." << m_dependencies.unit_dependency(u).name();\r
+    str << std::endl;\r
+  }\r
+  if (!m_supplement.empty())\r
+  {\r
+    str << "  supplementary data: " << m_supplement << std::endl;\r
+  }\r
+  return !str.fail();\r
+}\r
+\r
+// header file management\r
+\r
+std::string stlplus::lm_unit::filename(void) const\r
+{\r
+  return stlplus::create_filespec(library_path(), m_name.name(), m_name.type());\r
+}\r
+\r
+std::string stlplus::lm_unit::header_filename(void) const\r
+{\r
+  return stlplus::create_filespec(library_path(), m_name.name(), m_name.type() + std::string(HeaderExtension));\r
+}\r
+\r
+bool stlplus::lm_unit::read_header(void)\r
+{\r
+  if (file_exists(header_filename()))\r
+  {\r
+    std::ifstream input(header_filename().c_str());\r
+    m_dependencies.read(input);\r
+    input.get();\r
+    std::getline(input, m_supplement);\r
+  }\r
+  m_header_modified = false;\r
+  return true;\r
+}\r
+\r
+bool stlplus::lm_unit::write_header(void)\r
+{\r
+  if (!m_header_modified) return true;\r
+  std::ofstream output(header_filename().c_str());\r
+  m_dependencies.write(output);\r
+  output << m_supplement << std::endl;\r
+  m_header_modified = false;\r
+  return true;\r
+}\r
+\r
+// print diagnostics\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit& u)\r
+{\r
+  u.print(str);\r
+  return str;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// lm_library\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// constructors/destructors\r
+// copy operations only legal on unopened libraries\r
+\r
+stlplus::lm_library::lm_library(library_manager* manager) : m_writable(false), m_manager(manager)\r
+{\r
+}\r
+\r
+stlplus::lm_library::lm_library(const lm_library& library) : m_writable(library.m_writable), m_manager(library.m_manager)\r
+{\r
+}\r
+\r
+stlplus::lm_library& stlplus::lm_library::operator = (const stlplus::lm_library& library)\r
+{\r
+  m_writable = library.m_writable;\r
+  m_manager = library.m_manager;\r
+  return *this;\r
+}\r
+\r
+stlplus::lm_library::~lm_library(void)\r
+{\r
+  close();\r
+}\r
+\r
+const stlplus::library_manager* stlplus::lm_library::manager(void) const\r
+{\r
+  return m_manager;\r
+}\r
+\r
+stlplus::library_manager* stlplus::lm_library::manager(void)\r
+{\r
+  return m_manager;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// initialisers\r
+\r
+bool stlplus::lm_library::create(const std::string& name, const std::string& path, bool writable)\r
+{\r
+  close();\r
+  if (!create_library(path, m_manager->m_owner, name, writable)) return false;\r
+  return open(path);\r
+}\r
+\r
+bool stlplus::lm_library::open(const std::string& path)\r
+{\r
+  close();\r
+  if (!read_context(path, m_manager->m_owner, m_name, m_writable)) return false;\r
+  // convert path to full path on load\r
+  m_path = folder_to_path(path);\r
+  return load_types();\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// management of types\r
+\r
+bool stlplus::lm_library::load_type(const std::string& type)\r
+{\r
+  lm_callback_map::iterator callback = m_manager->m_callbacks.find(type);\r
+  if (callback == m_manager->m_callbacks.end()) return false;\r
+  // a null callback means create a dummy unit from the baseclass only\r
+  lm_create_callback fn = callback->second.m_callback;\r
+  void* data = callback->second.m_type_data;\r
+  // for each file in the library folder that matches the type of the create callback, create an unloaded unit\r
+  std::vector<std::string> files = folder_wildcard(m_path, stlplus::create_filename("*", type), false, true);\r
+  for (unsigned i = 0; i < files.size(); i++)\r
+  {\r
+    // key by unit name - lowercase name if case-insensitive\r
+    lm_unit_name uname(basename_part(files[i]),type);\r
+    if (!m_manager->m_unit_case) uname.lowercase();\r
+    lm_unit_ptr unit;\r
+    // if there's a callback, use it to create the subclass, else create the\r
+    // superclass which only contains header information\r
+    if (fn)\r
+      unit.set(fn(uname,this,data));\r
+    else\r
+      unit.set(new lm_unit(uname,this));\r
+    m_units[uname] = unit;\r
+  }\r
+  return true;\r
+}\r
+\r
+bool stlplus::lm_library::load_types(void)\r
+{\r
+  bool result = true;\r
+  for (lm_callback_map::const_iterator i = m_manager->m_callbacks.begin(); i != m_manager->m_callbacks.end(); i++)\r
+    result &= load_type(i->first);\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_library::remove_type(const std::string& type)\r
+{\r
+  bool result = true;\r
+  std::vector<std::string> units = names(type);\r
+  for (std::vector<std::string>::iterator i = units.begin(); i != units.end(); i++)\r
+  {\r
+    lm_unit_name name(*i, type);\r
+    std::map<lm_unit_name,lm_unit_ptr>::iterator ni = local_find(name);\r
+    if (ni != m_units.end())\r
+      m_units.erase(ni);\r
+  }\r
+  return result;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// whole library operations\r
+\r
+bool stlplus::lm_library::load(void)\r
+{\r
+  bool result = true;\r
+  for (std::map<lm_unit_name,lm_unit_ptr>::iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    result &= i->second->load();\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_library::save(void)\r
+{\r
+  bool result = true;\r
+  for (std::map<lm_unit_name,lm_unit_ptr>::iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    result &= i->second->save();\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_library::purge(void)\r
+{\r
+  bool result = true;\r
+  for (std::map<lm_unit_name,lm_unit_ptr>::iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    result &= i->second->purge();\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_library::close(void)\r
+{\r
+  bool result = save();\r
+  m_units.clear();\r
+  m_path = "";\r
+  m_writable = false;\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_library::erase(void)\r
+{\r
+  // preserve the path because close destroys it\r
+  std::string path = m_path;\r
+  return close() && erase_library(path, m_manager->m_owner);\r
+}\r
+\r
+const std::string& stlplus::lm_library::name(void) const\r
+{\r
+  return m_name;\r
+}\r
+\r
+const std::string& stlplus::lm_library::path(void) const\r
+{\r
+  return m_path;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// managing read/write status\r
+\r
+bool stlplus::lm_library::set_read_write(bool writable)\r
+{\r
+  if (m_writable == writable) return true;\r
+  if (os_read_only()) return false;\r
+  m_writable = writable;\r
+  if (!write_context(m_path, m_manager->m_owner, m_name, m_writable))\r
+    read_context(m_path, m_manager->m_owner, m_name, m_writable);\r
+  return m_writable == writable;\r
+}\r
+\r
+bool stlplus::lm_library::set_writable(void)\r
+{\r
+  return set_read_write(true);\r
+}\r
+\r
+bool stlplus::lm_library::set_read_only(void)\r
+{\r
+  return set_read_write(false);\r
+}\r
+\r
+bool stlplus::lm_library::writable(void) const\r
+{\r
+  return os_writable() && lm_writable();\r
+}\r
+\r
+bool stlplus::lm_library::read_only(void) const\r
+{\r
+  return os_read_only() || lm_read_only();\r
+}\r
+\r
+bool stlplus::lm_library::os_writable(void) const\r
+{\r
+  return folder_writable(path());\r
+}\r
+\r
+bool stlplus::lm_library::os_read_only(void) const\r
+{\r
+  return !folder_writable(path());\r
+}\r
+\r
+bool stlplus::lm_library::lm_writable(void) const\r
+{\r
+  return m_writable;\r
+}\r
+\r
+bool stlplus::lm_library::lm_read_only(void) const\r
+{\r
+  return !m_writable;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// unit management\r
+\r
+std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::iterator stlplus::lm_library::local_find(const lm_unit_name& name)\r
+{\r
+  // implement the case-sensitivity\r
+  lm_unit_name local = name;\r
+  if (!m_manager->m_unit_case) local.lowercase();\r
+  return m_units.find(local);\r
+}\r
+\r
+std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator stlplus::lm_library::local_find(const lm_unit_name& name) const\r
+{\r
+  // implement the case-sensitivity\r
+  lm_unit_name local = name;\r
+  if (!m_manager->m_unit_case) local.set_name(lowercase(local.name()));\r
+  return m_units.find(local);\r
+}\r
+\r
+bool stlplus::lm_library::exists(const lm_unit_name& name) const\r
+{\r
+  return find(name).present();\r
+}\r
+\r
+stlplus::lm_unit_ptr stlplus::lm_library::create(const stlplus::lm_unit_name& name)\r
+{\r
+  if (read_only()) return lm_unit_ptr();\r
+  // preserve the unit's name, but use a lowercase key in case-insensitive mode\r
+  lm_unit_name uname = name;\r
+  if (!m_manager->m_unit_case) uname.lowercase();\r
+  // remove any existing unit with the same name\r
+  erase(uname);\r
+  // use the callbacks to create a new unit\r
+  lm_callback_map::iterator callback = m_manager->m_callbacks.find(name.type());\r
+  if (callback == m_manager->m_callbacks.end()) return lm_unit_ptr();\r
+  lm_unit_ptr new_unit;\r
+  new_unit.set(callback->second.m_callback(name,this,callback->second.m_type_data));\r
+  new_unit->m_loaded = true;\r
+  // add it to the library manager\r
+  m_units[uname] = new_unit;\r
+  return m_units[uname];\r
+}\r
+\r
+bool stlplus::lm_library::loaded(const lm_unit_name& name) const\r
+{\r
+  lm_unit_ptr unit = find(name);\r
+  return unit && unit->loaded();\r
+}\r
+\r
+bool stlplus::lm_library::load(const lm_unit_name& name)\r
+{\r
+  lm_unit_ptr unit = find(name);\r
+  if (!unit) return false;\r
+  return unit->load();\r
+}\r
+\r
+bool stlplus::lm_library::purge(const lm_unit_name& name)\r
+{\r
+  lm_unit_ptr unit = find(name);\r
+  if (!unit) return false;\r
+  bool result = save(name);\r
+  result &= unit->purge();\r
+  unit->m_loaded = false;\r
+  return result;\r
+}\r
+\r
+bool stlplus::lm_library::save(const lm_unit_name& name)\r
+{\r
+  if (read_only()) return false;\r
+  lm_unit_ptr unit = find(name);\r
+  if (!unit) return false;\r
+  return unit->save();\r
+}\r
+\r
+bool stlplus::lm_library::erase(const lm_unit_name& name)\r
+{\r
+  if (read_only()) return false;\r
+  std::map<lm_unit_name,lm_unit_ptr>::iterator i = local_find(name);\r
+  if (i == m_units.end()) return false;\r
+  std::string spec = i->second->filename();\r
+  std::string header_spec = i->second->header_filename();\r
+  m_units.erase(i);\r
+  file_delete(spec);\r
+  file_delete(header_spec);\r
+  return true;\r
+}\r
+\r
+bool stlplus::lm_library::mark(const lm_unit_name& name)\r
+{\r
+  if (read_only()) return false;\r
+  lm_unit_ptr unit = find(name);\r
+  if (!unit) return false;\r
+  unit->mark();\r
+  return true;\r
+}\r
+\r
+time_t stlplus::lm_library::modified(const lm_unit_name& name) const\r
+{\r
+  lm_unit_ptr unit = find(name);\r
+  return unit ? unit->modified() : 0;\r
+}\r
+\r
+bool stlplus::lm_library::erase_by_source(const std::string& source_file)\r
+{\r
+  if (read_only()) return false;\r
+  if (source_file.empty()) return false;\r
+  bool result = false;\r
+  std::string source_file_full = filespec_to_path(source_file);\r
+  // erase by unit name so that I don't have to deal with an iterator to a changing map\r
+  std::vector<lm_unit_name> units = names();\r
+  for (std::vector<lm_unit_name>::iterator i = units.begin(); i != units.end(); i++)\r
+  {\r
+    lm_unit_ptr unit = find(*i);\r
+    if (unit && unit->source_file_present())\r
+    {\r
+      std::string file_full = unit->source_file().path_full(unit->library_path());\r
+      if (file_full == source_file_full)\r
+      {\r
+        erase(*i);\r
+        result = true;\r
+      }\r
+    }\r
+  }\r
+  return result;\r
+}\r
+\r
+const stlplus::lm_unit_ptr stlplus::lm_library::find(const stlplus::lm_unit_name& name) const\r
+{\r
+  std::map<lm_unit_name,lm_unit_ptr>::const_iterator i = local_find(name);\r
+  if (i == m_units.end()) return lm_unit_ptr();\r
+  return i->second;\r
+}\r
+\r
+stlplus::lm_unit_ptr stlplus::lm_library::find(const stlplus::lm_unit_name& name)\r
+{\r
+  std::map<lm_unit_name,lm_unit_ptr>::iterator i = local_find(name);\r
+  if (i == m_units.end()) return lm_unit_ptr();\r
+  return i->second;\r
+}\r
+\r
+std::vector<stlplus::lm_unit_name> stlplus::lm_library::names(void) const\r
+{\r
+  std::vector<stlplus::lm_unit_name> result;\r
+  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    result.push_back(i->second->unit_name());\r
+  return result;\r
+}\r
+\r
+std::vector<std::string> stlplus::lm_library::names(const std::string& type) const\r
+{\r
+  std::vector<std::string> result;\r
+  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    if (i->first.type() == type)\r
+      result.push_back(i->second->name());\r
+  return result;\r
+}\r
+\r
+std::vector<stlplus::lm_unit_ptr> stlplus::lm_library::handles(void) const\r
+{\r
+  std::vector<stlplus::lm_unit_ptr> result;\r
+  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    result.push_back(i->second);\r
+  return result;\r
+}\r
+\r
+std::vector<stlplus::lm_unit_ptr> stlplus::lm_library::handles(const std::string& type) const\r
+{\r
+  std::vector<stlplus::lm_unit_ptr> result;\r
+  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    if (i->first.type() == type)\r
+      result.push_back(i->second);\r
+  return result;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// dependency checking\r
+\r
+bool stlplus::lm_library::out_of_date(const stlplus::lm_unit_name& name) const\r
+{\r
+  return m_manager->out_of_date(m_name, name);\r
+}\r
+\r
+bool stlplus::lm_library::up_to_date(const stlplus::lm_unit_name& name) const\r
+{\r
+  return m_manager->up_to_date(m_name, name);\r
+}\r
+\r
+stlplus::lm_dependencies stlplus::lm_library::out_of_date_reason(const stlplus::lm_unit_name& unit) const\r
+{\r
+  return m_manager->out_of_date_reason(m_name, unit);\r
+}\r
+\r
+std::pair<bool,unsigned> stlplus::lm_library::tidy(void)\r
+{\r
+  std::pair<bool,unsigned> result = std::make_pair(true,0);\r
+  // erase every unit that is out of date\r
+  // this will potentially make other units out of date, so keep erasing until\r
+  // everything is up to date or an error occurs\r
+  for (;;)\r
+  {\r
+    std::vector<stlplus::lm_unit_name> units = names();\r
+    unsigned initial_count = result.second;\r
+    for (std::vector<stlplus::lm_unit_name>::iterator i = units.begin(); i != units.end(); i++)\r
+    {\r
+      if (out_of_date(*i))\r
+      {\r
+        if (!erase(*i))\r
+          result.first = false;\r
+        else\r
+          result.second++;\r
+      }\r
+    }\r
+    if (!result.first) break;\r
+    if (result.second == initial_count) break;\r
+  }\r
+  return result;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// do-everything print routine!\r
+\r
+bool stlplus::lm_library::pretty_print(std::ostream& str,\r
+                                       bool print_units,\r
+                                       const std::string& type) const\r
+{\r
+  // print the library information\r
+  if (this == m_manager->work())\r
+    str << "->> ";\r
+  else\r
+    str << "    ";\r
+  str << name() << " in directory " << folder_to_relative_path(path());\r
+  if (read_only()) str << " (locked)";\r
+  str << std::endl;\r
+  // select the units\r
+  if (print_units)\r
+  {\r
+    // separate into a block per unit kind\r
+    for (lm_callback_map::const_iterator j = m_manager->m_callbacks.begin(); j != m_manager->m_callbacks.end(); j++)\r
+    {\r
+      // select the requested unit kind\r
+      if (type.empty() || type == j->first)\r
+      {\r
+        // get all the units of this kind\r
+        std::vector<std::string> unit_names = names(j->first);\r
+        if (!unit_names.empty())\r
+        {\r
+          str << "    " << j->second.m_description << std::endl;\r
+          for (unsigned k = 0; k < unit_names.size(); k++)\r
+          {\r
+            lm_dependencies reason = out_of_date_reason(stlplus::lm_unit_name(unit_names[k],j->first));\r
+            str << "    - " << unit_names[k];\r
+            if (!reason.empty()) str << " (out of date)";\r
+            str << std::endl;\r
+            if (!reason.empty())\r
+            {\r
+              if (reason.source_file_present())\r
+              {\r
+                const lm_file_dependency& file = reason.source_file();\r
+                str << "    * source file " << filespec_to_relative_path(file.path_full(path())) << " has changed" << std::endl;\r
+              }\r
+              for (unsigned i1 = 0; i1 < reason.file_size(); i1++)\r
+              {\r
+                const lm_file_dependency& file = reason.file_dependency(i1);\r
+                str << "    * file " << filespec_to_relative_path(file.path_full(path())) << " has changed" << std::endl;\r
+              }\r
+              for (unsigned i2 = 0; i2 < reason.unit_size(); i2++)\r
+              {\r
+                const lm_unit_dependency& file = reason.unit_dependency(i2);\r
+                lm_callback_map::const_iterator entry = m_manager->m_callbacks.find(file.type());\r
+                str << "    * " << entry->second.m_description << " " << file.library() << "." << file.name() << " has changed" << std::endl;\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// diagnostic print routines\r
+\r
+bool stlplus::lm_library::print(std::ostream& str) const\r
+{\r
+  str << name() << " in " << path() << " " << (writable() ? "writable" : "read-only") << std::endl;\r
+  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    i->second->print(str);\r
+  return !str.fail();\r
+}\r
+\r
+bool stlplus::lm_library::print_long(std::ostream& str) const\r
+{\r
+  str << name() << " in " << path() << " " << (writable() ? "writable" : "read-only") << std::endl;\r
+  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
+    i->second->print_long(str);\r
+  return !str.fail();\r
+}\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_library& lib)\r
+{\r
+  lib.print(str);\r
+  return str;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// library manager\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+// static functions allow you to test whether a directory is a library before opening it\r
+// you can also find the library's name without opening it\r
+\r
+bool stlplus::library_manager::is_library(const std::string& path, const std::string& owner)\r
+{\r
+  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
+  return file_exists(spec);\r
+}\r
+\r
+std::string stlplus::library_manager::library_name(const std::string& path, const std::string& owner)\r
+{\r
+  std::string name;\r
+  bool writable = false;\r
+  if (!read_context(path, owner, name, writable))\r
+    return std::string();\r
+  return name;\r
+}\r
+\r
+bool stlplus::library_manager::is_library(const std::string& path)\r
+{\r
+  return is_library(path, m_owner);\r
+}\r
+\r
+std::string stlplus::library_manager::library_name(const std::string& path)\r
+{\r
+  return library_name(path, m_owner);\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// tructors\r
+\r
+stlplus::library_manager::library_manager(const std::string& owner, bool library_case, bool unit_case) :\r
+  m_owner(owner), m_ini_files(0), m_library_case(library_case), m_unit_case(unit_case)\r
+{\r
+}\r
+\r
+stlplus::library_manager::~library_manager(void)\r
+{\r
+  close();\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// case sensitivity\r
+\r
+bool stlplus::library_manager::library_case(void) const\r
+{\r
+  return m_library_case;\r
+}\r
+\r
+void stlplus::library_manager::set_library_case(bool library_case)\r
+{\r
+  m_library_case = library_case;\r
+}\r
+\r
+bool stlplus::library_manager::unit_case(void) const\r
+{\r
+  return m_unit_case;\r
+}\r
+\r
+void stlplus::library_manager::set_unit_case(bool unit_case)\r
+{\r
+  m_unit_case = unit_case;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// type handling\r
+\r
+bool stlplus::library_manager::add_type(const std::string& type,\r
+                                        const std::string& description,\r
+                                        lm_create_callback fn,\r
+                                        void* type_data)\r
+{\r
+  bool result = true;\r
+  m_callbacks[type] = lm_callback_entry(fn, description, type_data);\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result &= i->load_type(type);\r
+  return result;\r
+}\r
+\r
+bool stlplus::library_manager::remove_type(const std::string& type)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result &= i->remove_type(type);\r
+  m_callbacks.erase(type);\r
+  return result;\r
+}\r
+\r
+std::vector<std::string> stlplus::library_manager::types(void) const\r
+{\r
+  std::vector<std::string> result;\r
+  for (lm_callback_map::const_iterator i = m_callbacks.begin(); i != m_callbacks.end(); i++)\r
+    result.push_back(i->first);\r
+  return result;\r
+}\r
+\r
+std::string stlplus::library_manager::description(const std::string& type) const\r
+{\r
+  lm_callback_map::const_iterator found = m_callbacks.find(type);\r
+  if (found == m_callbacks.end()) return std::string();\r
+  return found->second.m_description;\r
+}\r
+\r
+stlplus::lm_create_callback stlplus::library_manager::callback(const std::string& type) const\r
+{\r
+  lm_callback_map::const_iterator found = m_callbacks.find(type);\r
+  if (found == m_callbacks.end()) return 0;\r
+  return found->second.m_callback;\r
+}\r
+\r
+void* stlplus::library_manager::type_data(const std::string& type) const\r
+{\r
+  lm_callback_map::const_iterator found = m_callbacks.find(type);\r
+  if (found == m_callbacks.end()) return 0;\r
+  return found->second.m_type_data;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// mapping file handling\r
+\r
+void stlplus::library_manager::set_mapping_file(const std::string& mapping_file)\r
+{\r
+  m_mapping_file = mapping_file;\r
+}\r
+\r
+bool stlplus::library_manager::load_mappings(const std::string& mapping_file)\r
+{\r
+  m_mapping_file = mapping_file;\r
+  if (!file_exists(mapping_file))\r
+  {\r
+    return false;\r
+  }\r
+  std::ifstream input(mapping_file.c_str());\r
+  if (input.fail())\r
+    return false;\r
+  // each line of the map file is a path to a library\r
+  // the first line is the work library - may be empty\r
+  // mappings are saved as paths relative to the mapping file and converted to full paths on load\r
+  bool result = true;\r
+  unsigned line = 1;\r
+  for (std::string path = ""; std::getline(input,path); line++)\r
+  {\r
+    if (path.empty()) continue;\r
+    std::string full_path = folder_to_path(folder_part(m_mapping_file), path);\r
+    if (!is_library(full_path))\r
+    {\r
+      result = false;\r
+    }\r
+    else\r
+    {\r
+      lm_library* lib = open(full_path);\r
+      if (!lib)\r
+        result = false;\r
+      else if (line == 1)\r
+        setwork(lib->name());\r
+    }\r
+  }\r
+  return result;\r
+}\r
+\r
+std::string stlplus::library_manager::mapping_file()\r
+{\r
+  return m_mapping_file;\r
+}\r
+\r
+bool stlplus::library_manager::set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_name)\r
+{\r
+  if (!ini_files) return false;\r
+  bool result = true;\r
+  m_ini_files = ini_files;\r
+  m_ini_section = library_section;\r
+  m_ini_work = work_name;\r
+  // now load the existing library mappings if present - in any case create the sections\r
+  // Note: a library mapping is saved as a path relative to the ini file - on load convert it to a path relative to the current directory\r
+  if (m_ini_files->section_exists(m_ini_section))\r
+  {\r
+    std::vector<std::string> library_names = m_ini_files->variable_names(m_ini_section);\r
+    std::string work_name;\r
+    for (unsigned i = 0; i < library_names.size(); i++)\r
+    {\r
+      std::string library_name = library_names[i];\r
+      // if the variable name is the work name, then this is a mapping to an existing library name\r
+      // if it is null, then it is masking a global library definition so ignore it\r
+      // otherwise it is a mapping to a directory containing the library\r
+      if (library_name.empty())\r
+      {\r
+      }\r
+      else if (library_name == m_ini_work)\r
+      {\r
+        work_name = m_ini_files->variable_value(m_ini_section, library_name);\r
+      }\r
+      else\r
+      {\r
+        std::string value = m_ini_files->variable_value(m_ini_section, library_name);\r
+        std::string filename = m_ini_files->variable_filename(m_ini_section, library_name);\r
+        // get the path to the ini file defining this library, strip off the ini filename to get the folder\r
+        // then combine this with the library path from that ini file to the library to get a full path to the library\r
+        // whew!\r
+        std::string full_path = folder_to_path(folder_part(filename),value);\r
+        if (!is_library(full_path))\r
+          result = false;\r
+        else\r
+        {\r
+          lm_library* lib = open(full_path);\r
+          if (!lib)\r
+            result = false;\r
+        }\r
+      }\r
+    }\r
+    // work must be set after all the libraries have been opened because it is\r
+    // illegal to set work to a library that doesn't already exist in the\r
+    // library manager\r
+    if (work_name.empty())\r
+      unsetwork();\r
+    else\r
+      result &= setwork(work_name);\r
+  }\r
+  return result;\r
+}\r
+\r
+stlplus::ini_manager* stlplus::library_manager::get_ini_manager(void) const\r
+{\r
+  return m_ini_files;\r
+}\r
+\r
+bool stlplus::library_manager::save_mappings (void)\r
+{\r
+  bool result = true;\r
+  // save to mapping file or ini manager or both\r
+  if (!m_mapping_file.empty())\r
+  {\r
+    if (m_libraries.size() == 0)\r
+    {\r
+      // if the file would be empty, delete it\r
+      if (!file_delete(m_mapping_file))\r
+        result = false;\r
+    }\r
+    else\r
+    {\r
+      std::ofstream output(m_mapping_file.c_str());\r
+      if (output.fail())\r
+      {\r
+        result = false;\r
+      }\r
+      else\r
+      {\r
+        // each line of the map file is a path to a library\r
+        // the first line is the work library\r
+        // mappings are saved as relative paths to the mapping file and converted to full paths on load\r
+        if (!work_name().empty())\r
+          output << folder_to_relative_path(folder_part(m_mapping_file), path(work_name()));\r
+        output << std::endl;\r
+        std::vector<std::string> libraries = names();\r
+        for (unsigned i = 0; i < libraries.size(); ++i)\r
+        {\r
+          if (libraries[i] != work_name())\r
+            output << folder_to_relative_path(folder_part(m_mapping_file), path(libraries[i])) << std::endl;\r
+        }\r
+        if (output.fail())\r
+          result = false;\r
+      }\r
+    }\r
+  }\r
+  if (m_ini_files)\r
+  {\r
+    // this is somewhat tricky!\r
+    // first remove all local mappings\r
+    // then need to compare the surviving library mappings with the contents of the library manager\r
+    // if there's a library in the ini files not in the library manager, mask it with an empty local declaration\r
+    // if there's a library in the ini files with the same mapping as the library manager, do nothing\r
+    // if there's a library in the ini files with a different mapping write that library mapping\r
+    // if there's a mapping missing from the ini files, write it\r
+    // finally write the work mapping if there is one\r
+    // clear all local mappings\r
+    // TODO - rework this so that the ini files only change if the mappings change\r
+    m_ini_files->clear_section(m_ini_section);\r
+    m_ini_files->add_comment(m_ini_section, "generated automatically by the library manager");\r
+    // look for globally defined library mappings that need to be overridden in the local ini file\r
+    std::vector<std::string> ini_names = m_ini_files->variable_names(m_ini_section);\r
+    for (unsigned i = 0; i < ini_names.size(); i++)\r
+    {\r
+      std::string ini_name = ini_names[i];\r
+      // check for a global library that needs to be locally masked\r
+      if (!exists(ini_name))\r
+        m_ini_files->add_variable(m_ini_section, ini_name, "");\r
+      else\r
+      {\r
+        // check for a library that is locally remapped\r
+        std::string value = m_ini_files->variable_value(m_ini_section, ini_name);\r
+        std::string filename = m_ini_files->variable_filename(m_ini_section, ini_name);\r
+        std::string full_ini_path = folder_to_path(folder_part(filename), value);\r
+        std::string full_lib_path = folder_to_path(path(ini_name));\r
+        if (full_ini_path != full_lib_path)\r
+        {\r
+          // write the path relative to the ini file\r
+          std::string relative_path = folder_to_relative_path(folder_part(filename), full_lib_path);\r
+          m_ini_files->add_variable(m_ini_section, ini_name, relative_path);\r
+        }\r
+      }\r
+    }\r
+    // now scan the library for mappings that aren't yet in the ini file\r
+    std::vector<std::string> lib_names = names();\r
+    for (unsigned j = 0; j < lib_names.size(); j++)\r
+    {\r
+      std::string lib_name = lib_names[j];\r
+      if (std::find(ini_names.begin(), ini_names.end(), lib_name) == ini_names.end())\r
+      {\r
+        // write the path relative to the ini file\r
+        std::string full_lib_path = folder_to_path(path(lib_name));\r
+        std::string filename = m_ini_files->variable_filename(m_ini_section, lib_name);\r
+        std::string relative_path = folder_to_relative_path(folder_part(filename), full_lib_path);\r
+        m_ini_files->add_variable(m_ini_section, lib_name, relative_path);\r
+      }\r
+    }\r
+    // write the work library - also write a blank value if work is not set but is defined in another library\r
+    if (!work_name().empty())\r
+      m_ini_files->add_variable(m_ini_section, m_ini_work, work_name());\r
+    else if (m_ini_files->variable_exists(m_ini_section, m_ini_work))\r
+      m_ini_files->add_variable(m_ini_section, m_ini_work, "");\r
+    m_ini_files->add_blank(m_ini_section);\r
+    // remove the section from the ini file manager if there's nothing in it\r
+    if (m_ini_files->empty_section(m_ini_section))\r
+      m_ini_files->erase_section(m_ini_section);\r
+    if (!m_ini_files->save())\r
+      result = false;\r
+  }\r
+  return result;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// library management\r
+\r
+bool stlplus::library_manager::exists(const std::string& name) const\r
+{\r
+  return find(name) != 0;\r
+}\r
+\r
+stlplus::lm_library* stlplus::library_manager::create(const std::string& name, const std::string& path, bool writable)\r
+{\r
+  if (!create_library(path, m_owner, name, writable)) return 0;\r
+  return open(path);\r
+}\r
+\r
+stlplus::lm_library* stlplus::library_manager::open(const std::string& path)\r
+{\r
+  std::string name;\r
+  bool writable = false;\r
+  if (!read_context(path, m_owner, name, writable)) return 0;\r
+  // remove any pre-existing library with the same name\r
+  close(name);\r
+  // add the library to the manager and open it\r
+  m_libraries.push_back(lm_library(this));\r
+  if (!m_libraries.back().open(folder_to_path(path)))\r
+  {\r
+    // remove the library in the event of an error\r
+    m_libraries.erase(--m_libraries.end());\r
+    return 0;\r
+  }\r
+  return &m_libraries.back();\r
+}\r
+\r
+bool stlplus::library_manager::load(const std::string& name)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->load();\r
+}\r
+\r
+bool stlplus::library_manager::save(const std::string& name)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->save();\r
+}\r
+\r
+bool stlplus::library_manager::purge(const std::string& name)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->purge();\r
+}\r
+\r
+bool stlplus::library_manager::close(const std::string& name)\r
+{\r
+  bool result= true;\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  result &= found->close();\r
+  m_libraries.erase(found);\r
+  if (name == m_work) m_work = "";\r
+  return result;\r
+}\r
+\r
+bool stlplus::library_manager::erase(const std::string& name)\r
+{\r
+  bool result= true;\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  result &= found->erase();\r
+  m_libraries.erase(found);\r
+  if (name == m_work) m_work = "";\r
+  return result;\r
+}\r
+\r
+// operations on all libraries - as above but applied to all the libraries in the manager\r
+\r
+bool stlplus::library_manager::load(void)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result &= i->load();\r
+  return result;\r
+}\r
+\r
+bool stlplus::library_manager::save(void)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result &= i->save();\r
+  return result;\r
+}\r
+\r
+bool stlplus::library_manager::purge(void)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result &= i->purge();\r
+  return result;\r
+}\r
+\r
+bool stlplus::library_manager::close(void)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); )\r
+  {\r
+    std::list<lm_library>::iterator next = i;\r
+    next++;\r
+    result &= i->close();\r
+    m_libraries.erase(i);\r
+    i = next;\r
+  }\r
+  return result;\r
+}\r
+\r
+bool stlplus::library_manager::erase(void)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); )\r
+  {\r
+    std::list<lm_library>::iterator next = i;\r
+    next++;\r
+    result &= i->erase();\r
+    m_libraries.erase(i);\r
+    i = next;\r
+  }\r
+  return result;\r
+}\r
+\r
+// get name and path of a library - name can differ in case if the library manager is case-insensitive\r
+\r
+std::string stlplus::library_manager::name(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return std::string();\r
+  return found->name();\r
+}\r
+\r
+std::string stlplus::library_manager::path(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return std::string();\r
+  return found->path();\r
+}\r
+\r
+// control and test read/write status\r
+\r
+bool stlplus::library_manager::set_writable(const std::string& name)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->set_writable();\r
+}\r
+\r
+bool stlplus::library_manager::set_read_only(const std::string& name)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->set_read_only();\r
+}\r
+\r
+bool stlplus::library_manager::writable(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->writable();\r
+}\r
+\r
+bool stlplus::library_manager::read_only(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->read_only();\r
+}\r
+\r
+bool stlplus::library_manager::os_writable(const std::string& library) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(library);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->os_writable();\r
+}\r
+\r
+bool stlplus::library_manager::os_read_only(const std::string& library) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(library);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->os_read_only();\r
+}\r
+\r
+bool stlplus::library_manager::lm_writable(const std::string& library) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(library);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->lm_writable();\r
+}\r
+\r
+bool stlplus::library_manager::lm_read_only(const std::string& library) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(library);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->lm_read_only();\r
+}\r
+\r
+// find a library in the manager - returns null if not found\r
+\r
+stlplus::lm_library* stlplus::library_manager::find(const std::string& name)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return 0;\r
+  return &(*found);\r
+}\r
+\r
+const stlplus::lm_library* stlplus::library_manager::find(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return 0;\r
+  return &(*found);\r
+}\r
+\r
+// get the set of all library names\r
+\r
+std::vector<std::string> stlplus::library_manager::names(void) const\r
+{\r
+  std::vector<std::string> result;\r
+  for (std::list<lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result.push_back(i->name());\r
+  return result;\r
+}\r
+\r
+// get the set of all libraries\r
+\r
+std::vector<const stlplus::lm_library*> stlplus::library_manager::handles(void) const\r
+{\r
+  std::vector<const lm_library*> result;\r
+  for (std::list<lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result.push_back(&(*i));\r
+  return result;\r
+}\r
+\r
+std::vector<stlplus::lm_library*> stlplus::library_manager::handles(void)\r
+{\r
+  std::vector<stlplus::lm_library*> result;\r
+  for (std::list<stlplus::lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    result.push_back(&(*i));\r
+  return result;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// current library management\r
+\r
+bool stlplus::library_manager::setwork(const std::string& name)\r
+{\r
+  unsetwork();\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  m_work = found->name();\r
+  return true;\r
+}\r
+\r
+bool stlplus::library_manager::unsetwork(void)\r
+{\r
+  m_work = "";\r
+  return true;\r
+}\r
+\r
+const stlplus::lm_library* stlplus::library_manager::work(void) const\r
+{\r
+  if (m_work.empty()) return 0;\r
+  return find(m_work);\r
+}\r
+\r
+stlplus::lm_library* stlplus::library_manager::work(void)\r
+{\r
+  if (m_work.empty()) return 0;\r
+  return find(m_work);\r
+}\r
+\r
+std::string stlplus::library_manager::work_name(void) const\r
+{\r
+  return m_work;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// unit management within a library\r
+\r
+bool stlplus::library_manager::exists(const std::string& name, const stlplus::lm_unit_name& unit) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->exists(unit);\r
+}\r
+\r
+stlplus::lm_unit_ptr stlplus::library_manager::create(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
+  return found->create(unit);\r
+}\r
+\r
+bool stlplus::library_manager::loaded(const std::string& name, const stlplus::lm_unit_name& unit) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
+  return found->loaded(unit);\r
+}\r
+\r
+bool stlplus::library_manager::load(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
+  return found->load(unit);\r
+}\r
+\r
+bool stlplus::library_manager::purge(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->purge(unit);\r
+}\r
+\r
+bool stlplus::library_manager::save(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->save(unit);\r
+}\r
+\r
+bool stlplus::library_manager::erase(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->erase(unit);\r
+}\r
+\r
+bool stlplus::library_manager::mark(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return false;\r
+  return found->mark(unit);\r
+}\r
+\r
+time_t stlplus::library_manager::modified(const std::string& name, const stlplus::lm_unit_name& unit) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return 0;\r
+  return found->modified(unit);\r
+}\r
+\r
+bool stlplus::library_manager::erase_by_source(const std::string& source_file)\r
+{\r
+  bool result = true;\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+    if (i->writable())\r
+      result &= i->erase_by_source(source_file);\r
+  return result;\r
+}\r
+\r
+const stlplus::lm_unit_ptr stlplus::library_manager::find(const std::string& name, const stlplus::lm_unit_name& unit) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end())\r
+    return stlplus::lm_unit_ptr();\r
+  return found->find(unit);\r
+}\r
+\r
+stlplus::lm_unit_ptr stlplus::library_manager::find(const std::string& name, const stlplus::lm_unit_name& unit)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
+  return found->find(unit);\r
+}\r
+\r
+std::vector<stlplus::lm_unit_name> stlplus::library_manager::names(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return std::vector<stlplus::lm_unit_name>();\r
+  return found->names();\r
+}\r
+\r
+std::vector<std::string> stlplus::library_manager::names(const std::string& name, const std::string& type) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return std::vector<std::string>();\r
+  return found->names(type);\r
+}\r
+\r
+std::vector<stlplus::lm_unit_ptr> stlplus::library_manager::handles(const std::string& name) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return std::vector<stlplus::lm_unit_ptr>();\r
+  return found->handles();\r
+}\r
+\r
+std::vector<stlplus::lm_unit_ptr> stlplus::library_manager::handles(const std::string& name, const std::string& type) const\r
+{\r
+  std::list<lm_library>::const_iterator found = local_find(name);\r
+  if (found == m_libraries.end()) return std::vector<stlplus::lm_unit_ptr>();\r
+  return found->handles(type);\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// dependency checking\r
+// done at the top level because a global view of the libraries is required\r
+\r
+bool stlplus::library_manager::out_of_date(const std::string& library, const stlplus::lm_unit_name& name) const\r
+{\r
+  return !up_to_date(library, name);\r
+}\r
+\r
+bool stlplus::library_manager::up_to_date(const std::string& library, const stlplus::lm_unit_name& name) const\r
+{\r
+  lm_dependencies reason = out_of_date_reason(library, name);\r
+  return reason.empty();\r
+}\r
+\r
+stlplus::lm_dependencies stlplus::library_manager::out_of_date_reason(const std::string& library, const stlplus::lm_unit_name& name) const\r
+{\r
+  std::map<std::pair<std::string,stlplus::lm_unit_name>,lm_dependencies> visited;\r
+  return out_of_date_check(visited, this, library, name);\r
+}\r
+\r
+std::pair<bool,unsigned> stlplus::library_manager::tidy(const std::string& library)\r
+{\r
+  std::list<lm_library>::iterator found = local_find(library);\r
+  if (found == m_libraries.end()) return std::make_pair(false,0);\r
+  return found->tidy();\r
+}\r
+\r
+std::pair<bool,unsigned> stlplus::library_manager::tidy(void)\r
+{\r
+  std::pair<bool,unsigned> result = std::make_pair(true,0);\r
+  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+  {\r
+    if (i->writable())\r
+    {\r
+      std::pair<bool,unsigned> library_result = i->tidy();\r
+      result.second += library_result.second;\r
+      result.first &= library_result.first;\r
+    }\r
+  }\r
+  return result;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+// do-everything print routine!\r
+\r
+bool stlplus::library_manager::pretty_print(std::ostream& str,\r
+                                            bool print_units,\r
+                                            const std::string& lib,\r
+                                            const std::string& type) const\r
+{\r
+  bool library_found = false;\r
+  for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)\r
+  {\r
+    // select the library\r
+    if (lib.empty() || lib == l->name())\r
+    {\r
+      l->pretty_print(str, print_units, type);\r
+      library_found = true;\r
+    }\r
+  }\r
+  if (!library_found)\r
+  {\r
+    if (lib.empty())\r
+      str << "there are no libraries in the library list" << std::endl;\r
+    else\r
+      str << "there is no library called " << lib << " in the library list" << std::endl;\r
+    return false;\r
+  }\r
+  return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// diagnostic print routines\r
+\r
+bool stlplus::library_manager::print(std::ostream& str) const\r
+{\r
+  for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)\r
+    l->print(str);\r
+  return str;\r
+}\r
+\r
+bool stlplus::library_manager::print_long(std::ostream& str) const\r
+{\r
+  for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)\r
+    l->print_long(str);\r
+  return str;\r
+}\r
+\r
+// find a library by name\r
+\r
+std::list<stlplus::lm_library>::iterator stlplus::library_manager::local_find(const std::string& name)\r
+{\r
+  for (std::list<stlplus::lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+  {\r
+    if (m_library_case)\r
+    {\r
+      if (i->name() == name) return i;\r
+    }\r
+    else\r
+    {\r
+      if (lowercase(i->name()) == lowercase(name)) return i;\r
+    }\r
+  }\r
+  return m_libraries.end();\r
+}\r
+\r
+std::list<stlplus::lm_library>::const_iterator stlplus::library_manager::local_find(const std::string& name) const\r
+{\r
+  for (std::list<stlplus::lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
+  {\r
+    if (m_library_case)\r
+    {\r
+      if (i->name() == name) return i;\r
+    }\r
+    else\r
+    {\r
+      if (lowercase(i->name()) == lowercase(name)) return i;\r
+    }\r
+  }\r
+  return m_libraries.end();\r
+}\r
+\r
+std::ostream& stlplus::operator << (std::ostream& str, const stlplus::library_manager& manager)\r
+{\r
+  manager.print(str);\r
+  return str;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
This page took 0.068145 seconds and 4 git commands to generate.