1 ////////////////////////////////////////////////////////////////////////////////
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "library_manager.hpp"
10 #include "file_system.hpp"
15 ////////////////////////////////////////////////////////////////////////////////
17 static const char* LibraryNameExtension
= "lmn";
18 static const char* HeaderExtension
= "lmh";
20 ////////////////////////////////////////////////////////////////////////////////
22 ////////////////////////////////////////////////////////////////////////////////
24 typedef std::map
<std::string
,stlplus::lm_callback_entry
> lm_callback_map
;
26 static std::string
lowercase(const std::string
& val
)
28 std::string text
= val
;
29 for (unsigned i
= 0; i
< text
.size(); i
++)
30 text
[i
] = tolower(text
[i
]);
34 // Context file and library operations
35 // These must be readable/writeable without a library data structure present
36 // so that the name of the library is known before creation
38 static bool read_context(const std::string
& path
, const std::string
& owner
, std::string
& name
, bool& writable
)
40 std::string spec
= stlplus::create_filespec(path
, owner
, LibraryNameExtension
);
43 if (!stlplus::file_exists(spec
)) return false;
44 std::ifstream
input(spec
.c_str());
45 input
>> name
>> writable
;
49 static bool write_context(const std::string
& path
, const std::string
& owner
, const std::string
& name
, bool writable
)
51 std::string spec
= stlplus::create_filespec(path
, owner
, LibraryNameExtension
);
52 std::ofstream
output(spec
.c_str());
53 output
<< name
<< " " << writable
<< std::endl
;
54 return !output
.fail();
57 static bool create_library(const std::string
& path
, const std::string
& owner
, const std::string
& name
, bool writable
)
59 std::string spec
= stlplus::create_filespec(path
, owner
, LibraryNameExtension
);
60 if (stlplus::is_present(path
) && !stlplus::is_folder(path
)) return false;
61 if (!stlplus::folder_exists(path
) && !stlplus::folder_create(path
)) return false;
62 return write_context(path
, owner
, name
, writable
);
65 static bool erase_library(const std::string
& path
, const std::string
& owner
)
67 // check that it is a library before deleting it!
68 std::string spec
= stlplus::create_filespec(path
, owner
, LibraryNameExtension
);
69 if (!stlplus::file_exists(spec
)) return false;
70 return stlplus::folder_delete(path
, true);
73 // dependency checking
75 typedef std::map
<std::pair
<std::string
,stlplus::lm_unit_name
>,stlplus::lm_dependencies
> visited_map
;
77 static stlplus::lm_dependencies
& out_of_date_check (visited_map
& visited
,
78 const stlplus::library_manager
* manager
,
79 const std::string
& library
,
80 const stlplus::lm_unit_name
& name
)
82 // the visited field contains an entry if a unit has been visited - it also contains the reason for out-of-date-ness
83 // this is initially set empty (up to date) since the unit has to be added
84 // before it is checked just in case there is a recursive loop
85 // the dependencies field is filled in if the unit is subsequently found to be out of date
86 std::pair
<std::string
,stlplus::lm_unit_name
> full_name
= std::make_pair(library
,name
);
87 // first check whether this unit has already been visited - this should in
88 // principle never happen because the same test is performed before trying
89 // to recurse, so consider this to be paranoid-mode programming
90 visited_map::iterator found
= visited
.find(full_name
);
91 if (found
!= visited
.end())
93 // now add this unit to prevent recursion loops later. This entry is added
94 // to when out-of-date dependencies are found and is also the return value
96 visited
[full_name
] = stlplus::lm_dependencies();
98 const stlplus::lm_unit_ptr unit
= manager
->find(library
,name
);
101 // if a unit is missing it fails with a dependency on itself - this is a
102 // bit of a work-around, but this again is paranoid-mode programming since
103 // the calling function (this function calling itself recursively) should
104 // check the unit's existence before recursing
105 visited
[full_name
].unit_add(stlplus::lm_unit_dependency(library
,name
));
109 // we're onto the real checks now - first get the datestamp of this unit:
110 // all dependencies must be older than this
111 time_t unit_modified
= unit
->modified();
112 // check dependency on source file if there is one
113 if (unit
->source_file_present())
115 std::string source_file
= unit
->source_file().path_full(unit
->library_path());
116 time_t source_modified
= stlplus::file_modified(source_file
);
117 if (source_modified
== 0 || source_modified
> unit_modified
)
119 visited
[full_name
].set_source_file(unit
->source_file());
122 // now check the other file dependencies
123 for (unsigned i
= 0; i
< unit
->file_size(); i
++)
125 // a file dependency is a dependency on a file outside of the library system
126 const stlplus::lm_file_dependency
& dependency
= unit
->file_dependency(i
);
127 std::string file_full
= dependency
.path_full(unit
->library_path());
128 time_t source_modified
= stlplus::file_modified(file_full
);
129 if (source_modified
== 0 || source_modified
> unit_modified
)
131 visited
[full_name
].file_add(dependency
);
134 // now check and recurse on unit dependencies
135 for (unsigned j
= 0; j
< unit
->unit_size(); j
++)
137 const stlplus::lm_unit_dependency
& dependency
= unit
->unit_dependency(j
);
138 std::pair
<std::string
,stlplus::lm_unit_name
> other_name
= std::make_pair(dependency
.library(), dependency
.unit_name());
139 // perform the datestamp checking at this level and only recurse if this does not detect an error
140 const stlplus::lm_unit_ptr other_unit
= manager
->find(other_name
.first
, other_name
.second
);
143 visited
[full_name
].unit_add(dependency
);
147 time_t other_modified
= other_unit
->modified();
148 if (other_modified
== 0 || other_modified
> unit_modified
)
150 visited
[full_name
].unit_add(dependency
);
154 // prevent recursion before doing it
155 visited_map::iterator other_found
= visited
.find(other_name
);
156 if (other_found
!= visited
.end())
158 // if the unit was found to be out of date on the previous visit, add it to the failed dependencies
159 if (!other_found
->second
.empty())
161 visited
[full_name
].unit_add(dependency
);
166 // the unit hasn't been visited before, so recurse on it now
167 stlplus::lm_dependencies other_dependencies
=
168 out_of_date_check(visited
, manager
, other_name
.first
, other_name
.second
);
169 if (!other_dependencies
.empty())
171 visited
[full_name
].unit_add(dependency
);
178 return visited
[full_name
];
181 ////////////////////////////////////////////////////////////////////////////////
182 // class lm_unit_name
184 stlplus::lm_unit_name::lm_unit_name(const std::string
& name
, const std::string
& type
) :
185 m_name(name
), m_type(type
)
189 stlplus::lm_unit_name::~lm_unit_name(void)
193 const std::string
& stlplus::lm_unit_name::name(void) const
198 void stlplus::lm_unit_name::set_name(const std::string
& name
)
203 void stlplus::lm_unit_name::lowercase(void)
205 m_name
= ::lowercase(m_name
);
208 const std::string
& stlplus::lm_unit_name::type(void) const
213 void stlplus::lm_unit_name::set_type(const std::string
& type
)
218 bool stlplus::lm_unit_name::write(std::ostream
& context
) const
220 context
<< m_name
<< " " << m_type
;
221 return !context
.fail();
224 bool stlplus::lm_unit_name::read(std::istream
& context
)
226 context
>> m_name
>> m_type
;
227 return !context
.fail();
230 std::string
stlplus::lm_unit_name::to_string(void) const
232 return m_name
+ ":" + m_type
;
235 bool stlplus::lm_unit_name::print(std::ostream
& str
) const
241 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::lm_unit_name
& name
)
247 bool stlplus::operator == (const stlplus::lm_unit_name
& l
, const stlplus::lm_unit_name
& r
)
249 return l
.name() == r
.name() && l
.type() == r
.type();
252 bool stlplus::operator < (const stlplus::lm_unit_name
& l
, const stlplus::lm_unit_name
& r
)
254 // sort by name then type
255 return (l
.name() != r
.name()) ? l
.name() < r
.name() : l
.type() < r
.type();
258 ////////////////////////////////////////////////////////////////////////////////
263 stlplus::lm_file_dependency::lm_file_dependency(void) : m_line(0), m_column(0)
267 stlplus::lm_file_dependency::lm_file_dependency(const std::string
& library_path
, const std::string
& path
, unsigned line
, unsigned column
)
269 set_path(library_path
, path
);
274 stlplus::lm_file_dependency::~lm_file_dependency(void)
278 const std::string
& stlplus::lm_file_dependency::path(void) const
283 std::string
stlplus::lm_file_dependency::path_full(const std::string
& library_path
) const
285 return filespec_to_path(library_path
, m_path
);
288 void stlplus::lm_file_dependency::set_path(const std::string
& library_path
, const std::string
& path
)
290 m_path
= filespec_to_relative_path(library_path
, path
);
293 unsigned stlplus::lm_file_dependency::line(void) const
298 void stlplus::lm_file_dependency::set_line(unsigned line
)
303 unsigned stlplus::lm_file_dependency::column(void) const
308 void stlplus::lm_file_dependency::set_column(unsigned column
)
313 bool stlplus::lm_file_dependency::write(std::ostream
& context
) const
315 context
<< m_path
<< " " << m_line
<< " " << m_column
;
316 return !context
.fail();
319 bool stlplus::lm_file_dependency::read(std::istream
& context
)
321 context
>> m_path
>> m_line
>> m_column
;
322 return !context
.fail();
325 bool stlplus::lm_file_dependency::print(std::ostream
& str
) const
327 str
<< "file: " << m_path
;
329 str
<< ":" << m_line
<< ":" << m_column
;
333 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::lm_file_dependency
& dependency
)
335 dependency
.print(str
);
341 stlplus::lm_unit_dependency::lm_unit_dependency(void)
345 stlplus::lm_unit_dependency::lm_unit_dependency(const std::string
& library
, const lm_unit_name
& name
) :
346 m_library(library
), m_name(name
)
350 stlplus::lm_unit_dependency::~lm_unit_dependency(void)
354 const std::string
& stlplus::lm_unit_dependency::library(void) const
359 void stlplus::lm_unit_dependency::set_library(const std::string
& library
)
364 const stlplus::lm_unit_name
& stlplus::lm_unit_dependency::unit_name(void) const
369 void stlplus::lm_unit_dependency::set_unit_name(const lm_unit_name
& unit_name
)
374 const std::string
& stlplus::lm_unit_dependency::name(void) const
376 return m_name
.name();
379 void stlplus::lm_unit_dependency::set_name(const std::string
& name
)
381 m_name
.set_name(name
);
384 const std::string
& stlplus::lm_unit_dependency::type(void) const
386 return m_name
.type();
389 void stlplus::lm_unit_dependency::set_type(const std::string
& type
)
391 m_name
.set_type(type
);
394 bool stlplus::lm_unit_dependency::write(std::ostream
& context
) const
396 context
<< m_library
;
397 m_name
.write(context
);
398 return !context
.fail();
401 bool stlplus::lm_unit_dependency::read(std::istream
& context
)
403 context
>> m_library
;
404 m_name
.read(context
);;
405 return !context
.fail();
408 bool stlplus::lm_unit_dependency::print(std::ostream
& str
) const
410 str
<< "unit: " << m_library
<< "." << m_name
;
414 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::lm_unit_dependency
& dependency
)
416 dependency
.print(str
);
422 stlplus::lm_dependencies::lm_dependencies(void) : m_source(0)
426 stlplus::lm_dependencies::lm_dependencies(const lm_dependencies
& r
) : m_source(0)
431 stlplus::lm_dependencies
& stlplus::lm_dependencies::operator=(const stlplus::lm_dependencies
& r
)
437 m_source
= new lm_file_dependency(*r
.m_source
);
443 stlplus::lm_dependencies::~lm_dependencies(void)
449 void stlplus::lm_dependencies::set_source_file(const lm_file_dependency
& source
)
453 m_source
= new lm_file_dependency(source
);
456 bool stlplus::lm_dependencies::source_file_present(void) const
458 return (m_source
!= 0);
461 const stlplus::lm_file_dependency
& stlplus::lm_dependencies::source_file(void) const
466 unsigned stlplus::lm_dependencies::file_add(const lm_file_dependency
& dependency
)
468 m_files
.push_back(dependency
);
469 return m_files
.size()-1;
472 unsigned stlplus::lm_dependencies::file_size(void) const
474 return m_files
.size();
477 const stlplus::lm_file_dependency
& stlplus::lm_dependencies::file_dependency(unsigned i
) const
482 void stlplus::lm_dependencies::file_erase(unsigned i
)
484 m_files
.erase(m_files
.begin()+i
);
487 unsigned stlplus::lm_dependencies::unit_add(const lm_unit_dependency
& dependency
)
489 m_units
.push_back(dependency
);
490 return m_units
.size()-1;
493 unsigned stlplus::lm_dependencies::unit_size(void) const
495 return m_units
.size();
498 const stlplus::lm_unit_dependency
& stlplus::lm_dependencies::unit_dependency(unsigned i
) const
503 void stlplus::lm_dependencies::unit_erase(unsigned i
)
505 m_units
.erase(m_units
.begin()+i
);
508 void stlplus::lm_dependencies::clear(void)
517 bool stlplus::lm_dependencies::empty(void) const
519 return (m_source
== 0) && m_files
.empty() && m_units
.empty();
522 bool stlplus::lm_dependencies::write(std::ostream
& context
) const
524 context
<< (m_source
? true : false) << " ";
525 if (m_source
) m_source
->write(context
);
526 context
<< std::endl
;
527 context
<< m_files
.size() << std::endl
;
528 for (unsigned i
= 0; i
< m_files
.size(); i
++)
530 m_files
[i
].write(context
);
531 context
<< std::endl
;
533 context
<< m_units
.size() << std::endl
;
534 for (unsigned j
= 0; j
< m_units
.size(); j
++)
536 m_units
[j
].write(context
);
537 context
<< std::endl
;
539 return !context
.fail();
542 bool stlplus::lm_dependencies::read(std::istream
& context
)
545 bool source_present
= false;
546 context
>> source_present
;
549 m_source
= new lm_file_dependency();
550 m_source
->read(context
);
552 unsigned files_size
= 0;
553 context
>> files_size
;
554 for (unsigned i
= 0; i
< files_size
; i
++)
556 m_files
.push_back(lm_file_dependency());
557 m_files
.back().read(context
);
559 unsigned units_size
= 0;
560 context
>> units_size
;
561 for (unsigned j
= 0; j
< units_size
; j
++)
563 m_units
.push_back(lm_unit_dependency());
564 m_units
.back().read(context
);
566 return !context
.fail();
569 bool stlplus::lm_dependencies::print(std::ostream
& str
) const
572 str
<< " source file: " << *m_source
<< std::endl
;
573 for (unsigned i
= 0; i
< m_files
.size(); i
++)
574 str
<< " " << m_files
[i
] << std::endl
;
575 for (unsigned j
= 0; j
< m_units
.size(); j
++)
576 str
<< " " << m_units
[j
] << std::endl
;
580 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::lm_dependencies
& dependencies
)
582 dependencies
.print(str
);
586 ////////////////////////////////////////////////////////////////////////////////
588 ////////////////////////////////////////////////////////////////////////////////
590 stlplus::lm_unit::lm_unit(const lm_unit_name
& name
, lm_library
* library
) :
591 m_name(name
), m_header_modified(false), m_loaded(false), m_marked(false), m_library(library
), m_error(false)
596 stlplus::lm_unit::~lm_unit(void)
601 ////////////////////////////////////////
604 const stlplus::lm_unit_name
& stlplus::lm_unit::unit_name(void) const
609 const std::string
& stlplus::lm_unit::name(void) const
611 return m_name
.name();
614 const std::string
& stlplus::lm_unit::type(void) const
616 return m_name
.type();
621 // source file dependency
623 void stlplus::lm_unit::set_source_file(const lm_file_dependency
& dependency
)
625 m_header_modified
= true;
626 m_dependencies
.set_source_file(dependency
);
629 bool stlplus::lm_unit::source_file_present(void) const
631 return m_dependencies
.source_file_present();
634 const stlplus::lm_file_dependency
& stlplus::lm_unit::source_file(void) const
636 return m_dependencies
.source_file();
639 // other file dependencies
641 unsigned stlplus::lm_unit::file_add(const lm_file_dependency
& dependency
)
643 m_header_modified
= true;
644 return m_dependencies
.file_add(dependency
);
647 unsigned stlplus::lm_unit::file_size(void) const
649 return m_dependencies
.file_size();
652 const stlplus::lm_file_dependency
& stlplus::lm_unit::file_dependency(unsigned i
) const
654 return m_dependencies
.file_dependency(i
);
657 void stlplus::lm_unit::file_erase(unsigned i
)
659 m_header_modified
= true;
660 m_dependencies
.file_erase(i
);
665 unsigned stlplus::lm_unit::unit_add(const lm_unit_dependency
& dependency
)
667 m_header_modified
= true;
668 return m_dependencies
.unit_add(dependency
);
671 unsigned stlplus::lm_unit::unit_size(void) const
673 return m_dependencies
.unit_size();
676 const stlplus::lm_unit_dependency
& stlplus::lm_unit::unit_dependency(unsigned i
) const
678 return m_dependencies
.unit_dependency(i
);
681 void stlplus::lm_unit::unit_erase(unsigned i
)
683 m_header_modified
= true;
684 m_dependencies
.unit_erase(i
);
687 const stlplus::lm_dependencies
& stlplus::lm_unit::dependencies(void) const
689 return m_dependencies
;
692 void stlplus::lm_unit::set_dependencies(const lm_dependencies
& dependencies
)
694 m_header_modified
= true;
695 m_dependencies
= dependencies
;
698 void stlplus::lm_unit::clear_dependencies(void)
700 m_header_modified
= true;
701 m_dependencies
.clear();
704 bool stlplus::lm_unit::empty_dependencies(void) const
706 return m_dependencies
.empty();
709 // dependency checking
711 bool stlplus::lm_unit::out_of_date(void) const
713 return m_library
->out_of_date(m_name
);
716 bool stlplus::lm_unit::up_to_date(void) const
718 return m_library
->up_to_date(m_name
);
721 stlplus::lm_dependencies
stlplus::lm_unit::out_of_date_reason(void) const
723 return m_library
->out_of_date_reason(m_name
);
726 // supplementary data
728 const std::string
& stlplus::lm_unit::supplementary_data(void) const
733 void stlplus::lm_unit::set_supplementary_data(const std::string
& data
)
736 m_header_modified
= true;
739 ////////////////////////////////////////
740 // unit data management
742 bool stlplus::lm_unit::load(void)
744 if (out_of_date()) return false;
745 if (m_loaded
) return true;
746 // get the user data for this type
747 lm_callback_map::iterator callback
= m_library
->m_manager
->m_callbacks
.find(type());
748 if (callback
== m_library
->m_manager
->m_callbacks
.end()) return false;
749 void* data
= callback
->second
.m_type_data
;
750 bool result
= read(filename(), data
);
755 bool stlplus::lm_unit::save(void)
757 if (!m_marked
) return true;
758 if (!m_loaded
) return false;
759 // get the user data for this type
760 lm_callback_map::iterator callback
= m_library
->m_manager
->m_callbacks
.find(type());
761 if (callback
== m_library
->m_manager
->m_callbacks
.end()) return false;
762 void* data
= callback
->second
.m_type_data
;
763 bool result
= write(filename(), data
);
764 if (result
) m_marked
= false;
768 bool stlplus::lm_unit::loaded(void) const
773 void stlplus::lm_unit::mark(void)
778 time_t stlplus::lm_unit::modified(void) const
780 return file_modified(filename());
783 ////////////////////////////////////////
784 // containing library manager details
786 const stlplus::lm_library
* stlplus::lm_unit::library(void) const
791 stlplus::lm_library
* stlplus::lm_unit::library(void)
796 const std::string
& stlplus::lm_unit::library_name(void) const
798 return m_library
->name();
801 const std::string
& stlplus::lm_unit::library_path(void) const
803 return m_library
->path();
806 // error handling - these apply to the last read/write operation
808 bool stlplus::lm_unit::error(void) const
813 // functions that customise subclasses of this superclass
815 bool stlplus::lm_unit::read(const std::string
& filespec
, void* type_data
)
817 std::ifstream
input(filespec
.c_str());
818 bool result
= read(input
, type_data
);
827 bool stlplus::lm_unit::read(std::istream
&, void*)
832 bool stlplus::lm_unit::write(const std::string
& filespec
, void* type_data
)
834 std::ofstream
output(filespec
.c_str());
835 bool result
= write(output
, type_data
);
844 bool stlplus::lm_unit::write(std::ostream
&, void*)
849 bool stlplus::lm_unit::purge(void)
854 stlplus::lm_unit
* stlplus::lm_unit::clone(void) const
856 return new lm_unit(*this);
859 bool stlplus::lm_unit::print(std::ostream
& str
) const
861 str
<< m_name
<< " " << (m_loaded
? "loaded" : "") << " " << (m_marked
? "needs saving" : "");
865 bool stlplus::lm_unit::print_long(std::ostream
& str
) const
867 str
<< "header:" << std::endl
;
868 str
<< " name: " << m_name
.name() << std::endl
;
869 str
<< " type: " << library()->manager()->description(m_name
.type()) << std::endl
;
870 str
<< " dependencies:" << std::endl
;
871 // Note: I've inlined this rather than call the above-defined print for dependencies
872 // This is so that I can use the library manager to look up the descriptions of unit types
873 // I can also convert paths so that they are relative to the current directory rather than the library
874 // print the source file dependency if present
875 if (m_dependencies
.source_file_present())
877 str
<< " source file: ";
878 str
<< filespec_to_relative_path(m_dependencies
.source_file().path_full(library()->path()));
879 if (m_dependencies
.source_file().line() != 0)
880 str
<< ":" << m_dependencies
.source_file().line() << ":" << m_dependencies
.source_file().column();
883 // now print other file dependencies
884 // convert these to relative paths too
885 for (unsigned f
= 0; f
< m_dependencies
.file_size(); f
++)
888 str
<< filespec_to_relative_path(m_dependencies
.file_dependency(f
).path_full(library()->path()));
889 if (m_dependencies
.file_dependency(f
).line() != 0)
890 str
<< ":" << m_dependencies
.file_dependency(f
).line() << ":" << m_dependencies
.file_dependency(f
).column();
893 // now print unit dependencies
894 // convert unit types to their descriptive strings
895 for (unsigned u
= 0; u
< m_dependencies
.unit_size(); u
++)
897 str
<< " " << library()->manager()->description(m_dependencies
.unit_dependency(u
).type()) << ": ";
898 str
<< m_dependencies
.unit_dependency(u
).library() << "." << m_dependencies
.unit_dependency(u
).name();
901 if (!m_supplement
.empty())
903 str
<< " supplementary data: " << m_supplement
<< std::endl
;
908 // header file management
910 std::string
stlplus::lm_unit::filename(void) const
912 return stlplus::create_filespec(library_path(), m_name
.name(), m_name
.type());
915 std::string
stlplus::lm_unit::header_filename(void) const
917 return stlplus::create_filespec(library_path(), m_name
.name(), m_name
.type() + std::string(HeaderExtension
));
920 bool stlplus::lm_unit::read_header(void)
922 if (file_exists(header_filename()))
924 std::ifstream
input(header_filename().c_str());
925 m_dependencies
.read(input
);
927 std::getline(input
, m_supplement
);
929 m_header_modified
= false;
933 bool stlplus::lm_unit::write_header(void)
935 if (!m_header_modified
) return true;
936 std::ofstream
output(header_filename().c_str());
937 m_dependencies
.write(output
);
938 output
<< m_supplement
<< std::endl
;
939 m_header_modified
= false;
945 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::lm_unit
& u
)
951 ////////////////////////////////////////////////////////////////////////////////
953 ////////////////////////////////////////////////////////////////////////////////
955 ////////////////////////////////////////////////////////////////////////////////
956 // constructors/destructors
957 // copy operations only legal on unopened libraries
959 stlplus::lm_library::lm_library(library_manager
* manager
) : m_writable(false), m_manager(manager
)
963 stlplus::lm_library::lm_library(const lm_library
& library
) : m_writable(library
.m_writable
), m_manager(library
.m_manager
)
967 stlplus::lm_library
& stlplus::lm_library::operator = (const stlplus::lm_library
& library
)
969 m_writable
= library
.m_writable
;
970 m_manager
= library
.m_manager
;
974 stlplus::lm_library::~lm_library(void)
979 const stlplus::library_manager
* stlplus::lm_library::manager(void) const
984 stlplus::library_manager
* stlplus::lm_library::manager(void)
989 //////////////////////////////////////////////////////////////////////////////
992 bool stlplus::lm_library::create(const std::string
& name
, const std::string
& path
, bool writable
)
995 if (!create_library(path
, m_manager
->m_owner
, name
, writable
)) return false;
999 bool stlplus::lm_library::open(const std::string
& path
)
1002 if (!read_context(path
, m_manager
->m_owner
, m_name
, m_writable
)) return false;
1003 // convert path to full path on load
1004 m_path
= folder_to_path(path
);
1005 return load_types();
1008 //////////////////////////////////////////////////////////////////////////////
1009 // management of types
1011 bool stlplus::lm_library::load_type(const std::string
& type
)
1013 lm_callback_map::iterator callback
= m_manager
->m_callbacks
.find(type
);
1014 if (callback
== m_manager
->m_callbacks
.end()) return false;
1015 // a null callback means create a dummy unit from the baseclass only
1016 lm_create_callback fn
= callback
->second
.m_callback
;
1017 void* data
= callback
->second
.m_type_data
;
1018 // for each file in the library folder that matches the type of the create callback, create an unloaded unit
1019 std::vector
<std::string
> files
= folder_wildcard(m_path
, stlplus::create_filename("*", type
), false, true);
1020 for (unsigned i
= 0; i
< files
.size(); i
++)
1022 // key by unit name - lowercase name if case-insensitive
1023 lm_unit_name
uname(basename_part(files
[i
]),type
);
1024 if (!m_manager
->m_unit_case
) uname
.lowercase();
1026 // if there's a callback, use it to create the subclass, else create the
1027 // superclass which only contains header information
1029 unit
.set(fn(uname
,this,data
));
1031 unit
.set(new lm_unit(uname
,this));
1032 m_units
[uname
] = unit
;
1037 bool stlplus::lm_library::load_types(void)
1040 for (lm_callback_map::const_iterator i
= m_manager
->m_callbacks
.begin(); i
!= m_manager
->m_callbacks
.end(); i
++)
1041 result
&= load_type(i
->first
);
1045 bool stlplus::lm_library::remove_type(const std::string
& type
)
1048 std::vector
<std::string
> units
= names(type
);
1049 for (std::vector
<std::string
>::iterator i
= units
.begin(); i
!= units
.end(); i
++)
1051 lm_unit_name
name(*i
, type
);
1052 std::map
<lm_unit_name
,lm_unit_ptr
>::iterator ni
= local_find(name
);
1053 if (ni
!= m_units
.end())
1059 //////////////////////////////////////////////////////////////////////////////
1060 // whole library operations
1062 bool stlplus::lm_library::load(void)
1065 for (std::map
<lm_unit_name
,lm_unit_ptr
>::iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1066 result
&= i
->second
->load();
1070 bool stlplus::lm_library::save(void)
1073 for (std::map
<lm_unit_name
,lm_unit_ptr
>::iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1074 result
&= i
->second
->save();
1078 bool stlplus::lm_library::purge(void)
1081 for (std::map
<lm_unit_name
,lm_unit_ptr
>::iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1082 result
&= i
->second
->purge();
1086 bool stlplus::lm_library::close(void)
1088 bool result
= save();
1095 bool stlplus::lm_library::erase(void)
1097 // preserve the path because close destroys it
1098 std::string path
= m_path
;
1099 return close() && erase_library(path
, m_manager
->m_owner
);
1102 const std::string
& stlplus::lm_library::name(void) const
1107 const std::string
& stlplus::lm_library::path(void) const
1112 //////////////////////////////////////////////////////////////////////////////
1113 // managing read/write status
1115 bool stlplus::lm_library::set_read_write(bool writable
)
1117 if (m_writable
== writable
) return true;
1118 if (os_read_only()) return false;
1119 m_writable
= writable
;
1120 if (!write_context(m_path
, m_manager
->m_owner
, m_name
, m_writable
))
1121 read_context(m_path
, m_manager
->m_owner
, m_name
, m_writable
);
1122 return m_writable
== writable
;
1125 bool stlplus::lm_library::set_writable(void)
1127 return set_read_write(true);
1130 bool stlplus::lm_library::set_read_only(void)
1132 return set_read_write(false);
1135 bool stlplus::lm_library::writable(void) const
1137 return os_writable() && lm_writable();
1140 bool stlplus::lm_library::read_only(void) const
1142 return os_read_only() || lm_read_only();
1145 bool stlplus::lm_library::os_writable(void) const
1147 return folder_writable(path());
1150 bool stlplus::lm_library::os_read_only(void) const
1152 return !folder_writable(path());
1155 bool stlplus::lm_library::lm_writable(void) const
1160 bool stlplus::lm_library::lm_read_only(void) const
1165 //////////////////////////////////////////////////////////////////////////////
1168 std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::iterator
stlplus::lm_library::local_find(const lm_unit_name
& name
)
1170 // implement the case-sensitivity
1171 lm_unit_name local
= name
;
1172 if (!m_manager
->m_unit_case
) local
.lowercase();
1173 return m_units
.find(local
);
1176 std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator
stlplus::lm_library::local_find(const lm_unit_name
& name
) const
1178 // implement the case-sensitivity
1179 lm_unit_name local
= name
;
1180 if (!m_manager
->m_unit_case
) local
.set_name(lowercase(local
.name()));
1181 return m_units
.find(local
);
1184 bool stlplus::lm_library::exists(const lm_unit_name
& name
) const
1186 return find(name
).present();
1189 stlplus::lm_unit_ptr
stlplus::lm_library::create(const stlplus::lm_unit_name
& name
)
1191 if (read_only()) return lm_unit_ptr();
1192 // preserve the unit's name, but use a lowercase key in case-insensitive mode
1193 lm_unit_name uname
= name
;
1194 if (!m_manager
->m_unit_case
) uname
.lowercase();
1195 // remove any existing unit with the same name
1197 // use the callbacks to create a new unit
1198 lm_callback_map::iterator callback
= m_manager
->m_callbacks
.find(name
.type());
1199 if (callback
== m_manager
->m_callbacks
.end()) return lm_unit_ptr();
1200 lm_unit_ptr new_unit
;
1201 new_unit
.set(callback
->second
.m_callback(name
,this,callback
->second
.m_type_data
));
1202 new_unit
->m_loaded
= true;
1203 // add it to the library manager
1204 m_units
[uname
] = new_unit
;
1205 return m_units
[uname
];
1208 bool stlplus::lm_library::loaded(const lm_unit_name
& name
) const
1210 lm_unit_ptr unit
= find(name
);
1211 return unit
&& unit
->loaded();
1214 bool stlplus::lm_library::load(const lm_unit_name
& name
)
1216 lm_unit_ptr unit
= find(name
);
1217 if (!unit
) return false;
1218 return unit
->load();
1221 bool stlplus::lm_library::purge(const lm_unit_name
& name
)
1223 lm_unit_ptr unit
= find(name
);
1224 if (!unit
) return false;
1225 bool result
= save(name
);
1226 result
&= unit
->purge();
1227 unit
->m_loaded
= false;
1231 bool stlplus::lm_library::save(const lm_unit_name
& name
)
1233 if (read_only()) return false;
1234 lm_unit_ptr unit
= find(name
);
1235 if (!unit
) return false;
1236 return unit
->save();
1239 bool stlplus::lm_library::erase(const lm_unit_name
& name
)
1241 if (read_only()) return false;
1242 std::map
<lm_unit_name
,lm_unit_ptr
>::iterator i
= local_find(name
);
1243 if (i
== m_units
.end()) return false;
1244 std::string spec
= i
->second
->filename();
1245 std::string header_spec
= i
->second
->header_filename();
1248 file_delete(header_spec
);
1252 bool stlplus::lm_library::mark(const lm_unit_name
& name
)
1254 if (read_only()) return false;
1255 lm_unit_ptr unit
= find(name
);
1256 if (!unit
) return false;
1261 time_t stlplus::lm_library::modified(const lm_unit_name
& name
) const
1263 lm_unit_ptr unit
= find(name
);
1264 return unit
? unit
->modified() : 0;
1267 bool stlplus::lm_library::erase_by_source(const std::string
& source_file
)
1269 if (read_only()) return false;
1270 if (source_file
.empty()) return false;
1271 bool result
= false;
1272 std::string source_file_full
= filespec_to_path(source_file
);
1273 // erase by unit name so that I don't have to deal with an iterator to a changing map
1274 std::vector
<lm_unit_name
> units
= names();
1275 for (std::vector
<lm_unit_name
>::iterator i
= units
.begin(); i
!= units
.end(); i
++)
1277 lm_unit_ptr unit
= find(*i
);
1278 if (unit
&& unit
->source_file_present())
1280 std::string file_full
= unit
->source_file().path_full(unit
->library_path());
1281 if (file_full
== source_file_full
)
1291 const stlplus::lm_unit_ptr
stlplus::lm_library::find(const stlplus::lm_unit_name
& name
) const
1293 std::map
<lm_unit_name
,lm_unit_ptr
>::const_iterator i
= local_find(name
);
1294 if (i
== m_units
.end()) return lm_unit_ptr();
1298 stlplus::lm_unit_ptr
stlplus::lm_library::find(const stlplus::lm_unit_name
& name
)
1300 std::map
<lm_unit_name
,lm_unit_ptr
>::iterator i
= local_find(name
);
1301 if (i
== m_units
.end()) return lm_unit_ptr();
1305 std::vector
<stlplus::lm_unit_name
> stlplus::lm_library::names(void) const
1307 std::vector
<stlplus::lm_unit_name
> result
;
1308 for (std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1309 result
.push_back(i
->second
->unit_name());
1313 std::vector
<std::string
> stlplus::lm_library::names(const std::string
& type
) const
1315 std::vector
<std::string
> result
;
1316 for (std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1317 if (i
->first
.type() == type
)
1318 result
.push_back(i
->second
->name());
1322 std::vector
<stlplus::lm_unit_ptr
> stlplus::lm_library::handles(void) const
1324 std::vector
<stlplus::lm_unit_ptr
> result
;
1325 for (std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1326 result
.push_back(i
->second
);
1330 std::vector
<stlplus::lm_unit_ptr
> stlplus::lm_library::handles(const std::string
& type
) const
1332 std::vector
<stlplus::lm_unit_ptr
> result
;
1333 for (std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1334 if (i
->first
.type() == type
)
1335 result
.push_back(i
->second
);
1339 ////////////////////////////////////////////////////////////////////////////////
1340 // dependency checking
1342 bool stlplus::lm_library::out_of_date(const stlplus::lm_unit_name
& name
) const
1344 return m_manager
->out_of_date(m_name
, name
);
1347 bool stlplus::lm_library::up_to_date(const stlplus::lm_unit_name
& name
) const
1349 return m_manager
->up_to_date(m_name
, name
);
1352 stlplus::lm_dependencies
stlplus::lm_library::out_of_date_reason(const stlplus::lm_unit_name
& unit
) const
1354 return m_manager
->out_of_date_reason(m_name
, unit
);
1357 std::pair
<bool,unsigned> stlplus::lm_library::tidy(void)
1359 std::pair
<bool,unsigned> result
= std::make_pair(true,0);
1360 // erase every unit that is out of date
1361 // this will potentially make other units out of date, so keep erasing until
1362 // everything is up to date or an error occurs
1365 std::vector
<stlplus::lm_unit_name
> units
= names();
1366 unsigned initial_count
= result
.second
;
1367 for (std::vector
<stlplus::lm_unit_name
>::iterator i
= units
.begin(); i
!= units
.end(); i
++)
1369 if (out_of_date(*i
))
1372 result
.first
= false;
1377 if (!result
.first
) break;
1378 if (result
.second
== initial_count
) break;
1383 ////////////////////////////////////////////////////////////////////////////////
1384 // do-everything print routine!
1386 bool stlplus::lm_library::pretty_print(std::ostream
& str
,
1388 const std::string
& type
) const
1390 // print the library information
1391 if (this == m_manager
->work())
1395 str
<< name() << " in directory " << folder_to_relative_path(path());
1396 if (read_only()) str
<< " (locked)";
1401 // separate into a block per unit kind
1402 for (lm_callback_map::const_iterator j
= m_manager
->m_callbacks
.begin(); j
!= m_manager
->m_callbacks
.end(); j
++)
1404 // select the requested unit kind
1405 if (type
.empty() || type
== j
->first
)
1407 // get all the units of this kind
1408 std::vector
<std::string
> unit_names
= names(j
->first
);
1409 if (!unit_names
.empty())
1411 str
<< " " << j
->second
.m_description
<< std::endl
;
1412 for (unsigned k
= 0; k
< unit_names
.size(); k
++)
1414 lm_dependencies reason
= out_of_date_reason(stlplus::lm_unit_name(unit_names
[k
],j
->first
));
1415 str
<< " - " << unit_names
[k
];
1416 if (!reason
.empty()) str
<< " (out of date)";
1418 if (!reason
.empty())
1420 if (reason
.source_file_present())
1422 const lm_file_dependency
& file
= reason
.source_file();
1423 str
<< " * source file " << filespec_to_relative_path(file
.path_full(path())) << " has changed" << std::endl
;
1425 for (unsigned i1
= 0; i1
< reason
.file_size(); i1
++)
1427 const lm_file_dependency
& file
= reason
.file_dependency(i1
);
1428 str
<< " * file " << filespec_to_relative_path(file
.path_full(path())) << " has changed" << std::endl
;
1430 for (unsigned i2
= 0; i2
< reason
.unit_size(); i2
++)
1432 const lm_unit_dependency
& file
= reason
.unit_dependency(i2
);
1433 lm_callback_map::const_iterator entry
= m_manager
->m_callbacks
.find(file
.type());
1434 str
<< " * " << entry
->second
.m_description
<< " " << file
.library() << "." << file
.name() << " has changed" << std::endl
;
1445 ////////////////////////////////////////////////////////////////////////////////
1446 // diagnostic print routines
1448 bool stlplus::lm_library::print(std::ostream
& str
) const
1450 str
<< name() << " in " << path() << " " << (writable() ? "writable" : "read-only") << std::endl
;
1451 for (std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1452 i
->second
->print(str
);
1456 bool stlplus::lm_library::print_long(std::ostream
& str
) const
1458 str
<< name() << " in " << path() << " " << (writable() ? "writable" : "read-only") << std::endl
;
1459 for (std::map
<stlplus::lm_unit_name
,stlplus::lm_unit_ptr
>::const_iterator i
= m_units
.begin(); i
!= m_units
.end(); i
++)
1460 i
->second
->print_long(str
);
1464 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::lm_library
& lib
)
1470 ////////////////////////////////////////////////////////////////////////////////
1472 ////////////////////////////////////////////////////////////////////////////////
1474 // static functions allow you to test whether a directory is a library before opening it
1475 // you can also find the library's name without opening it
1477 bool stlplus::library_manager::is_library(const std::string
& path
, const std::string
& owner
)
1479 std::string spec
= stlplus::create_filespec(path
, owner
, LibraryNameExtension
);
1480 return file_exists(spec
);
1483 std::string
stlplus::library_manager::library_name(const std::string
& path
, const std::string
& owner
)
1486 bool writable
= false;
1487 if (!read_context(path
, owner
, name
, writable
))
1488 return std::string();
1492 bool stlplus::library_manager::is_library(const std::string
& path
)
1494 return is_library(path
, m_owner
);
1497 std::string
stlplus::library_manager::library_name(const std::string
& path
)
1499 return library_name(path
, m_owner
);
1502 //////////////////////////////////////////////////////////////////////////////
1505 stlplus::library_manager::library_manager(const std::string
& owner
, bool library_case
, bool unit_case
) :
1506 m_owner(owner
), m_ini_files(0), m_library_case(library_case
), m_unit_case(unit_case
)
1510 stlplus::library_manager::~library_manager(void)
1515 //////////////////////////////////////////////////////////////////////////////
1518 bool stlplus::library_manager::library_case(void) const
1520 return m_library_case
;
1523 void stlplus::library_manager::set_library_case(bool library_case
)
1525 m_library_case
= library_case
;
1528 bool stlplus::library_manager::unit_case(void) const
1533 void stlplus::library_manager::set_unit_case(bool unit_case
)
1535 m_unit_case
= unit_case
;
1538 ////////////////////////////////////////////////////////////////////////////////
1541 bool stlplus::library_manager::add_type(const std::string
& type
,
1542 const std::string
& description
,
1543 lm_create_callback fn
,
1547 m_callbacks
[type
] = lm_callback_entry(fn
, description
, type_data
);
1548 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
1549 result
&= i
->load_type(type
);
1553 bool stlplus::library_manager::remove_type(const std::string
& type
)
1556 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
1557 result
&= i
->remove_type(type
);
1558 m_callbacks
.erase(type
);
1562 std::vector
<std::string
> stlplus::library_manager::types(void) const
1564 std::vector
<std::string
> result
;
1565 for (lm_callback_map::const_iterator i
= m_callbacks
.begin(); i
!= m_callbacks
.end(); i
++)
1566 result
.push_back(i
->first
);
1570 std::string
stlplus::library_manager::description(const std::string
& type
) const
1572 lm_callback_map::const_iterator found
= m_callbacks
.find(type
);
1573 if (found
== m_callbacks
.end()) return std::string();
1574 return found
->second
.m_description
;
1577 stlplus::lm_create_callback
stlplus::library_manager::callback(const std::string
& type
) const
1579 lm_callback_map::const_iterator found
= m_callbacks
.find(type
);
1580 if (found
== m_callbacks
.end()) return 0;
1581 return found
->second
.m_callback
;
1584 void* stlplus::library_manager::type_data(const std::string
& type
) const
1586 lm_callback_map::const_iterator found
= m_callbacks
.find(type
);
1587 if (found
== m_callbacks
.end()) return 0;
1588 return found
->second
.m_type_data
;
1591 //////////////////////////////////////////////////////////////////////////////
1592 // mapping file handling
1594 void stlplus::library_manager::set_mapping_file(const std::string
& mapping_file
)
1596 m_mapping_file
= mapping_file
;
1599 bool stlplus::library_manager::load_mappings(const std::string
& mapping_file
)
1601 m_mapping_file
= mapping_file
;
1602 if (!file_exists(mapping_file
))
1606 std::ifstream
input(mapping_file
.c_str());
1609 // each line of the map file is a path to a library
1610 // the first line is the work library - may be empty
1611 // mappings are saved as paths relative to the mapping file and converted to full paths on load
1614 for (std::string path
= ""; std::getline(input
,path
); line
++)
1616 if (path
.empty()) continue;
1617 std::string full_path
= folder_to_path(folder_part(m_mapping_file
), path
);
1618 if (!is_library(full_path
))
1624 lm_library
* lib
= open(full_path
);
1628 setwork(lib
->name());
1634 std::string
stlplus::library_manager::mapping_file()
1636 return m_mapping_file
;
1639 bool stlplus::library_manager::set_ini_manager(ini_manager
* ini_files
, const std::string
& library_section
, const std::string
& work_name
)
1641 if (!ini_files
) return false;
1643 m_ini_files
= ini_files
;
1644 m_ini_section
= library_section
;
1645 m_ini_work
= work_name
;
1646 // now load the existing library mappings if present - in any case create the sections
1647 // 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
1648 if (m_ini_files
->section_exists(m_ini_section
))
1650 std::vector
<std::string
> library_names
= m_ini_files
->variable_names(m_ini_section
);
1651 std::string work_name
;
1652 for (unsigned i
= 0; i
< library_names
.size(); i
++)
1654 std::string library_name
= library_names
[i
];
1655 // if the variable name is the work name, then this is a mapping to an existing library name
1656 // if it is null, then it is masking a global library definition so ignore it
1657 // otherwise it is a mapping to a directory containing the library
1658 if (library_name
.empty())
1661 else if (library_name
== m_ini_work
)
1663 work_name
= m_ini_files
->variable_value(m_ini_section
, library_name
);
1667 std::string value
= m_ini_files
->variable_value(m_ini_section
, library_name
);
1668 std::string filename
= m_ini_files
->variable_filename(m_ini_section
, library_name
);
1669 // get the path to the ini file defining this library, strip off the ini filename to get the folder
1670 // then combine this with the library path from that ini file to the library to get a full path to the library
1672 std::string full_path
= folder_to_path(folder_part(filename
),value
);
1673 if (!is_library(full_path
))
1677 lm_library
* lib
= open(full_path
);
1683 // work must be set after all the libraries have been opened because it is
1684 // illegal to set work to a library that doesn't already exist in the
1686 if (work_name
.empty())
1689 result
&= setwork(work_name
);
1694 stlplus::ini_manager
* stlplus::library_manager::get_ini_manager(void) const
1699 bool stlplus::library_manager::save_mappings (void)
1702 // save to mapping file or ini manager or both
1703 if (!m_mapping_file
.empty())
1705 if (m_libraries
.size() == 0)
1707 // if the file would be empty, delete it
1708 if (!file_delete(m_mapping_file
))
1713 std::ofstream
output(m_mapping_file
.c_str());
1720 // each line of the map file is a path to a library
1721 // the first line is the work library
1722 // mappings are saved as relative paths to the mapping file and converted to full paths on load
1723 if (!work_name().empty())
1724 output
<< folder_to_relative_path(folder_part(m_mapping_file
), path(work_name()));
1725 output
<< std::endl
;
1726 std::vector
<std::string
> libraries
= names();
1727 for (unsigned i
= 0; i
< libraries
.size(); ++i
)
1729 if (libraries
[i
] != work_name())
1730 output
<< folder_to_relative_path(folder_part(m_mapping_file
), path(libraries
[i
])) << std::endl
;
1739 // this is somewhat tricky!
1740 // first remove all local mappings
1741 // then need to compare the surviving library mappings with the contents of the library manager
1742 // if there's a library in the ini files not in the library manager, mask it with an empty local declaration
1743 // if there's a library in the ini files with the same mapping as the library manager, do nothing
1744 // if there's a library in the ini files with a different mapping write that library mapping
1745 // if there's a mapping missing from the ini files, write it
1746 // finally write the work mapping if there is one
1747 // clear all local mappings
1748 // TODO - rework this so that the ini files only change if the mappings change
1749 m_ini_files
->clear_section(m_ini_section
);
1750 m_ini_files
->add_comment(m_ini_section
, "generated automatically by the library manager");
1751 // look for globally defined library mappings that need to be overridden in the local ini file
1752 std::vector
<std::string
> ini_names
= m_ini_files
->variable_names(m_ini_section
);
1753 for (unsigned i
= 0; i
< ini_names
.size(); i
++)
1755 std::string ini_name
= ini_names
[i
];
1756 // check for a global library that needs to be locally masked
1757 if (!exists(ini_name
))
1758 m_ini_files
->add_variable(m_ini_section
, ini_name
, "");
1761 // check for a library that is locally remapped
1762 std::string value
= m_ini_files
->variable_value(m_ini_section
, ini_name
);
1763 std::string filename
= m_ini_files
->variable_filename(m_ini_section
, ini_name
);
1764 std::string full_ini_path
= folder_to_path(folder_part(filename
), value
);
1765 std::string full_lib_path
= folder_to_path(path(ini_name
));
1766 if (full_ini_path
!= full_lib_path
)
1768 // write the path relative to the ini file
1769 std::string relative_path
= folder_to_relative_path(folder_part(filename
), full_lib_path
);
1770 m_ini_files
->add_variable(m_ini_section
, ini_name
, relative_path
);
1774 // now scan the library for mappings that aren't yet in the ini file
1775 std::vector
<std::string
> lib_names
= names();
1776 for (unsigned j
= 0; j
< lib_names
.size(); j
++)
1778 std::string lib_name
= lib_names
[j
];
1779 if (std::find(ini_names
.begin(), ini_names
.end(), lib_name
) == ini_names
.end())
1781 // write the path relative to the ini file
1782 std::string full_lib_path
= folder_to_path(path(lib_name
));
1783 std::string filename
= m_ini_files
->variable_filename(m_ini_section
, lib_name
);
1784 std::string relative_path
= folder_to_relative_path(folder_part(filename
), full_lib_path
);
1785 m_ini_files
->add_variable(m_ini_section
, lib_name
, relative_path
);
1788 // write the work library - also write a blank value if work is not set but is defined in another library
1789 if (!work_name().empty())
1790 m_ini_files
->add_variable(m_ini_section
, m_ini_work
, work_name());
1791 else if (m_ini_files
->variable_exists(m_ini_section
, m_ini_work
))
1792 m_ini_files
->add_variable(m_ini_section
, m_ini_work
, "");
1793 m_ini_files
->add_blank(m_ini_section
);
1794 // remove the section from the ini file manager if there's nothing in it
1795 if (m_ini_files
->empty_section(m_ini_section
))
1796 m_ini_files
->erase_section(m_ini_section
);
1797 if (!m_ini_files
->save())
1803 //////////////////////////////////////////////////////////////////////////////
1804 // library management
1806 bool stlplus::library_manager::exists(const std::string
& name
) const
1808 return find(name
) != 0;
1811 stlplus::lm_library
* stlplus::library_manager::create(const std::string
& name
, const std::string
& path
, bool writable
)
1813 if (!create_library(path
, m_owner
, name
, writable
)) return 0;
1817 stlplus::lm_library
* stlplus::library_manager::open(const std::string
& path
)
1820 bool writable
= false;
1821 if (!read_context(path
, m_owner
, name
, writable
)) return 0;
1822 // remove any pre-existing library with the same name
1824 // add the library to the manager and open it
1825 m_libraries
.push_back(lm_library(this));
1826 if (!m_libraries
.back().open(folder_to_path(path
)))
1828 // remove the library in the event of an error
1829 m_libraries
.erase(--m_libraries
.end());
1832 return &m_libraries
.back();
1835 bool stlplus::library_manager::load(const std::string
& name
)
1837 std::list
<lm_library
>::iterator found
= local_find(name
);
1838 if (found
== m_libraries
.end()) return false;
1839 return found
->load();
1842 bool stlplus::library_manager::save(const std::string
& name
)
1844 std::list
<lm_library
>::iterator found
= local_find(name
);
1845 if (found
== m_libraries
.end()) return false;
1846 return found
->save();
1849 bool stlplus::library_manager::purge(const std::string
& name
)
1851 std::list
<lm_library
>::iterator found
= local_find(name
);
1852 if (found
== m_libraries
.end()) return false;
1853 return found
->purge();
1856 bool stlplus::library_manager::close(const std::string
& name
)
1859 std::list
<lm_library
>::iterator found
= local_find(name
);
1860 if (found
== m_libraries
.end()) return false;
1861 result
&= found
->close();
1862 m_libraries
.erase(found
);
1863 if (name
== m_work
) m_work
= "";
1867 bool stlplus::library_manager::erase(const std::string
& name
)
1870 std::list
<lm_library
>::iterator found
= local_find(name
);
1871 if (found
== m_libraries
.end()) return false;
1872 result
&= found
->erase();
1873 m_libraries
.erase(found
);
1874 if (name
== m_work
) m_work
= "";
1878 // operations on all libraries - as above but applied to all the libraries in the manager
1880 bool stlplus::library_manager::load(void)
1883 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
1884 result
&= i
->load();
1888 bool stlplus::library_manager::save(void)
1891 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
1892 result
&= i
->save();
1896 bool stlplus::library_manager::purge(void)
1899 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
1900 result
&= i
->purge();
1904 bool stlplus::library_manager::close(void)
1907 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); )
1909 std::list
<lm_library
>::iterator next
= i
;
1911 result
&= i
->close();
1912 m_libraries
.erase(i
);
1918 bool stlplus::library_manager::erase(void)
1921 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); )
1923 std::list
<lm_library
>::iterator next
= i
;
1925 result
&= i
->erase();
1926 m_libraries
.erase(i
);
1932 // get name and path of a library - name can differ in case if the library manager is case-insensitive
1934 std::string
stlplus::library_manager::name(const std::string
& name
) const
1936 std::list
<lm_library
>::const_iterator found
= local_find(name
);
1937 if (found
== m_libraries
.end()) return std::string();
1938 return found
->name();
1941 std::string
stlplus::library_manager::path(const std::string
& name
) const
1943 std::list
<lm_library
>::const_iterator found
= local_find(name
);
1944 if (found
== m_libraries
.end()) return std::string();
1945 return found
->path();
1948 // control and test read/write status
1950 bool stlplus::library_manager::set_writable(const std::string
& name
)
1952 std::list
<lm_library
>::iterator found
= local_find(name
);
1953 if (found
== m_libraries
.end()) return false;
1954 return found
->set_writable();
1957 bool stlplus::library_manager::set_read_only(const std::string
& name
)
1959 std::list
<lm_library
>::iterator found
= local_find(name
);
1960 if (found
== m_libraries
.end()) return false;
1961 return found
->set_read_only();
1964 bool stlplus::library_manager::writable(const std::string
& name
) const
1966 std::list
<lm_library
>::const_iterator found
= local_find(name
);
1967 if (found
== m_libraries
.end()) return false;
1968 return found
->writable();
1971 bool stlplus::library_manager::read_only(const std::string
& name
) const
1973 std::list
<lm_library
>::const_iterator found
= local_find(name
);
1974 if (found
== m_libraries
.end()) return false;
1975 return found
->read_only();
1978 bool stlplus::library_manager::os_writable(const std::string
& library
) const
1980 std::list
<lm_library
>::const_iterator found
= local_find(library
);
1981 if (found
== m_libraries
.end()) return false;
1982 return found
->os_writable();
1985 bool stlplus::library_manager::os_read_only(const std::string
& library
) const
1987 std::list
<lm_library
>::const_iterator found
= local_find(library
);
1988 if (found
== m_libraries
.end()) return false;
1989 return found
->os_read_only();
1992 bool stlplus::library_manager::lm_writable(const std::string
& library
) const
1994 std::list
<lm_library
>::const_iterator found
= local_find(library
);
1995 if (found
== m_libraries
.end()) return false;
1996 return found
->lm_writable();
1999 bool stlplus::library_manager::lm_read_only(const std::string
& library
) const
2001 std::list
<lm_library
>::const_iterator found
= local_find(library
);
2002 if (found
== m_libraries
.end()) return false;
2003 return found
->lm_read_only();
2006 // find a library in the manager - returns null if not found
2008 stlplus::lm_library
* stlplus::library_manager::find(const std::string
& name
)
2010 std::list
<lm_library
>::iterator found
= local_find(name
);
2011 if (found
== m_libraries
.end()) return 0;
2015 const stlplus::lm_library
* stlplus::library_manager::find(const std::string
& name
) const
2017 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2018 if (found
== m_libraries
.end()) return 0;
2022 // get the set of all library names
2024 std::vector
<std::string
> stlplus::library_manager::names(void) const
2026 std::vector
<std::string
> result
;
2027 for (std::list
<lm_library
>::const_iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2028 result
.push_back(i
->name());
2032 // get the set of all libraries
2034 std::vector
<const stlplus::lm_library
*> stlplus::library_manager::handles(void) const
2036 std::vector
<const lm_library
*> result
;
2037 for (std::list
<lm_library
>::const_iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2038 result
.push_back(&(*i
));
2042 std::vector
<stlplus::lm_library
*> stlplus::library_manager::handles(void)
2044 std::vector
<stlplus::lm_library
*> result
;
2045 for (std::list
<stlplus::lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2046 result
.push_back(&(*i
));
2050 //////////////////////////////////////////////////////////////////////////////
2051 // current library management
2053 bool stlplus::library_manager::setwork(const std::string
& name
)
2056 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2057 if (found
== m_libraries
.end()) return false;
2058 m_work
= found
->name();
2062 bool stlplus::library_manager::unsetwork(void)
2068 const stlplus::lm_library
* stlplus::library_manager::work(void) const
2070 if (m_work
.empty()) return 0;
2071 return find(m_work
);
2074 stlplus::lm_library
* stlplus::library_manager::work(void)
2076 if (m_work
.empty()) return 0;
2077 return find(m_work
);
2080 std::string
stlplus::library_manager::work_name(void) const
2085 //////////////////////////////////////////////////////////////////////////////
2086 // unit management within a library
2088 bool stlplus::library_manager::exists(const std::string
& name
, const stlplus::lm_unit_name
& unit
) const
2090 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2091 if (found
== m_libraries
.end()) return false;
2092 return found
->exists(unit
);
2095 stlplus::lm_unit_ptr
stlplus::library_manager::create(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2097 std::list
<lm_library
>::iterator found
= local_find(name
);
2098 if (found
== m_libraries
.end()) return stlplus::lm_unit_ptr();
2099 return found
->create(unit
);
2102 bool stlplus::library_manager::loaded(const std::string
& name
, const stlplus::lm_unit_name
& unit
) const
2104 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2105 if (found
== m_libraries
.end()) return stlplus::lm_unit_ptr();
2106 return found
->loaded(unit
);
2109 bool stlplus::library_manager::load(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2111 std::list
<lm_library
>::iterator found
= local_find(name
);
2112 if (found
== m_libraries
.end()) return stlplus::lm_unit_ptr();
2113 return found
->load(unit
);
2116 bool stlplus::library_manager::purge(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2118 std::list
<lm_library
>::iterator found
= local_find(name
);
2119 if (found
== m_libraries
.end()) return false;
2120 return found
->purge(unit
);
2123 bool stlplus::library_manager::save(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2125 std::list
<lm_library
>::iterator found
= local_find(name
);
2126 if (found
== m_libraries
.end()) return false;
2127 return found
->save(unit
);
2130 bool stlplus::library_manager::erase(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2132 std::list
<lm_library
>::iterator found
= local_find(name
);
2133 if (found
== m_libraries
.end()) return false;
2134 return found
->erase(unit
);
2137 bool stlplus::library_manager::mark(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2139 std::list
<lm_library
>::iterator found
= local_find(name
);
2140 if (found
== m_libraries
.end()) return false;
2141 return found
->mark(unit
);
2144 time_t stlplus::library_manager::modified(const std::string
& name
, const stlplus::lm_unit_name
& unit
) const
2146 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2147 if (found
== m_libraries
.end()) return 0;
2148 return found
->modified(unit
);
2151 bool stlplus::library_manager::erase_by_source(const std::string
& source_file
)
2154 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2156 result
&= i
->erase_by_source(source_file
);
2160 const stlplus::lm_unit_ptr
stlplus::library_manager::find(const std::string
& name
, const stlplus::lm_unit_name
& unit
) const
2162 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2163 if (found
== m_libraries
.end())
2164 return stlplus::lm_unit_ptr();
2165 return found
->find(unit
);
2168 stlplus::lm_unit_ptr
stlplus::library_manager::find(const std::string
& name
, const stlplus::lm_unit_name
& unit
)
2170 std::list
<lm_library
>::iterator found
= local_find(name
);
2171 if (found
== m_libraries
.end()) return stlplus::lm_unit_ptr();
2172 return found
->find(unit
);
2175 std::vector
<stlplus::lm_unit_name
> stlplus::library_manager::names(const std::string
& name
) const
2177 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2178 if (found
== m_libraries
.end()) return std::vector
<stlplus::lm_unit_name
>();
2179 return found
->names();
2182 std::vector
<std::string
> stlplus::library_manager::names(const std::string
& name
, const std::string
& type
) const
2184 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2185 if (found
== m_libraries
.end()) return std::vector
<std::string
>();
2186 return found
->names(type
);
2189 std::vector
<stlplus::lm_unit_ptr
> stlplus::library_manager::handles(const std::string
& name
) const
2191 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2192 if (found
== m_libraries
.end()) return std::vector
<stlplus::lm_unit_ptr
>();
2193 return found
->handles();
2196 std::vector
<stlplus::lm_unit_ptr
> stlplus::library_manager::handles(const std::string
& name
, const std::string
& type
) const
2198 std::list
<lm_library
>::const_iterator found
= local_find(name
);
2199 if (found
== m_libraries
.end()) return std::vector
<stlplus::lm_unit_ptr
>();
2200 return found
->handles(type
);
2203 //////////////////////////////////////////////////////////////////////////////
2204 // dependency checking
2205 // done at the top level because a global view of the libraries is required
2207 bool stlplus::library_manager::out_of_date(const std::string
& library
, const stlplus::lm_unit_name
& name
) const
2209 return !up_to_date(library
, name
);
2212 bool stlplus::library_manager::up_to_date(const std::string
& library
, const stlplus::lm_unit_name
& name
) const
2214 lm_dependencies reason
= out_of_date_reason(library
, name
);
2215 return reason
.empty();
2218 stlplus::lm_dependencies
stlplus::library_manager::out_of_date_reason(const std::string
& library
, const stlplus::lm_unit_name
& name
) const
2220 std::map
<std::pair
<std::string
,stlplus::lm_unit_name
>,lm_dependencies
> visited
;
2221 return out_of_date_check(visited
, this, library
, name
);
2224 std::pair
<bool,unsigned> stlplus::library_manager::tidy(const std::string
& library
)
2226 std::list
<lm_library
>::iterator found
= local_find(library
);
2227 if (found
== m_libraries
.end()) return std::make_pair(false,0);
2228 return found
->tidy();
2231 std::pair
<bool,unsigned> stlplus::library_manager::tidy(void)
2233 std::pair
<bool,unsigned> result
= std::make_pair(true,0);
2234 for (std::list
<lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2238 std::pair
<bool,unsigned> library_result
= i
->tidy();
2239 result
.second
+= library_result
.second
;
2240 result
.first
&= library_result
.first
;
2246 //////////////////////////////////////////////////////////////////////////////
2247 // do-everything print routine!
2249 bool stlplus::library_manager::pretty_print(std::ostream
& str
,
2251 const std::string
& lib
,
2252 const std::string
& type
) const
2254 bool library_found
= false;
2255 for (std::list
<lm_library
>::const_iterator l
= m_libraries
.begin(); l
!= m_libraries
.end(); l
++)
2257 // select the library
2258 if (lib
.empty() || lib
== l
->name())
2260 l
->pretty_print(str
, print_units
, type
);
2261 library_found
= true;
2267 str
<< "there are no libraries in the library list" << std::endl
;
2269 str
<< "there is no library called " << lib
<< " in the library list" << std::endl
;
2275 ////////////////////////////////////////////////////////////////////////////////
2276 // diagnostic print routines
2278 bool stlplus::library_manager::print(std::ostream
& str
) const
2280 for (std::list
<lm_library
>::const_iterator l
= m_libraries
.begin(); l
!= m_libraries
.end(); l
++)
2285 bool stlplus::library_manager::print_long(std::ostream
& str
) const
2287 for (std::list
<lm_library
>::const_iterator l
= m_libraries
.begin(); l
!= m_libraries
.end(); l
++)
2292 // find a library by name
2294 std::list
<stlplus::lm_library
>::iterator
stlplus::library_manager::local_find(const std::string
& name
)
2296 for (std::list
<stlplus::lm_library
>::iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2300 if (i
->name() == name
) return i
;
2304 if (lowercase(i
->name()) == lowercase(name
)) return i
;
2307 return m_libraries
.end();
2310 std::list
<stlplus::lm_library
>::const_iterator
stlplus::library_manager::local_find(const std::string
& name
) const
2312 for (std::list
<stlplus::lm_library
>::const_iterator i
= m_libraries
.begin(); i
!= m_libraries
.end(); i
++)
2316 if (i
->name() == name
) return i
;
2320 if (lowercase(i
->name()) == lowercase(name
)) return i
;
2323 return m_libraries
.end();
2326 std::ostream
& stlplus::operator << (std::ostream
& str
, const stlplus::library_manager
& manager
)
2332 ////////////////////////////////////////////////////////////////////////////////