1 ////////////////////////////////////////////////////////////////////////////////
2 
3 //   Author:    Andy Rushton
4 //   Copyright: (c) Southampton University 1999-2004
5 //              (c) Andy Rushton           2004 onwards
6 //   License:   BSD License, see ../docs/license.html
7 
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "library_manager.hpp"
10 #include "file_system.hpp"
11 #include <algorithm>
12 #include <fstream>
13 #include <ctype.h>
14 
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 static const char* LibraryNameExtension = "lmn";
18 static const char* HeaderExtension = "lmh";
19 
20 ////////////////////////////////////////////////////////////////////////////////
21 // local operations
22 ////////////////////////////////////////////////////////////////////////////////
23 
24 typedef std::map<std::string,stlplus::lm_callback_entry> lm_callback_map;
25 
lowercase(const std::string & val)26 static std::string lowercase(const std::string& val)
27 {
28   std::string text = val;
29   for (unsigned i = 0; i < text.size(); i++)
30     text[i] = tolower(text[i]);
31   return text;
32 }
33 
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
37 
read_context(const std::string & path,const std::string & owner,std::string & name,bool & writable)38 static bool read_context(const std::string& path, const std::string& owner, std::string& name, bool& writable)
39 {
40   std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);
41   name = "";
42   writable = false;
43   if (!stlplus::file_exists(spec)) return false;
44   std::ifstream input(spec.c_str());
45   input >> name >> writable;
46   return !input.fail();
47 }
48 
write_context(const std::string & path,const std::string & owner,const std::string & name,bool writable)49 static bool write_context(const std::string& path, const std::string& owner, const std::string& name, bool writable)
50 {
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();
55 }
56 
create_library(const std::string & path,const std::string & owner,const std::string & name,bool writable)57 static bool create_library(const std::string& path, const std::string& owner, const std::string& name, bool writable)
58 {
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);
63 }
64 
erase_library(const std::string & path,const std::string & owner)65 static bool erase_library(const std::string& path, const std::string& owner)
66 {
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);
71 }
72 
73 // dependency checking
74 
75 typedef std::map<std::pair<std::string,stlplus::lm_unit_name>,stlplus::lm_dependencies> visited_map;
76 
out_of_date_check(visited_map & visited,const stlplus::library_manager * manager,const std::string & library,const stlplus::lm_unit_name & name)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)
81 {
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())
92     return found->second;
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
95   // of the function
96   visited[full_name] = stlplus::lm_dependencies();
97   // now find the unit
98   const stlplus::lm_unit_ptr unit = manager->find(library,name);
99   if (!unit)
100   {
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));
106   }
107   else
108   {
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())
114     {
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)
118       {
119         visited[full_name].set_source_file(unit->source_file());
120       }
121     }
122     // now check the other file dependencies
123     for (unsigned i = 0; i < unit->file_size(); i++)
124     {
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)
130       {
131         visited[full_name].file_add(dependency);
132       }
133     }
134     // now check and recurse on unit dependencies
135     for (unsigned j = 0; j < unit->unit_size(); j++)
136     {
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);
141       if (!other_unit)
142       {
143         visited[full_name].unit_add(dependency);
144       }
145       else
146       {
147         time_t other_modified = other_unit->modified();
148         if (other_modified == 0 || other_modified > unit_modified)
149         {
150           visited[full_name].unit_add(dependency);
151         }
152         else
153         {
154           // prevent recursion before doing it
155           visited_map::iterator other_found = visited.find(other_name);
156           if (other_found != visited.end())
157           {
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())
160             {
161               visited[full_name].unit_add(dependency);
162             }
163           }
164           else
165           {
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())
170             {
171               visited[full_name].unit_add(dependency);
172             }
173           }
174         }
175       }
176     }
177   }
178   return visited[full_name];
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 // class lm_unit_name
183 
lm_unit_name(const std::string & name,const std::string & type)184 stlplus::lm_unit_name::lm_unit_name(const std::string& name, const std::string& type) :
185   m_name(name), m_type(type)
186 {
187 }
188 
~lm_unit_name(void)189 stlplus::lm_unit_name::~lm_unit_name(void)
190 {
191 }
192 
name(void) const193 const std::string& stlplus::lm_unit_name::name(void) const
194 {
195   return m_name;
196 }
197 
set_name(const std::string & name)198 void stlplus::lm_unit_name::set_name(const std::string& name)
199 {
200   m_name = name;
201 }
202 
lowercase(void)203 void stlplus::lm_unit_name::lowercase(void)
204 {
205   m_name = ::lowercase(m_name);
206 }
207 
type(void) const208 const std::string& stlplus::lm_unit_name::type(void) const
209 {
210   return m_type;
211 }
212 
set_type(const std::string & type)213 void stlplus::lm_unit_name::set_type(const std::string& type)
214 {
215   m_type = type;
216 }
217 
write(std::ostream & context) const218 bool stlplus::lm_unit_name::write(std::ostream& context) const
219 {
220   context << m_name << " " << m_type;
221   return !context.fail();
222 }
223 
read(std::istream & context)224 bool stlplus::lm_unit_name::read(std::istream& context)
225 {
226   context >> m_name >> m_type;
227   return !context.fail();
228 }
229 
to_string(void) const230 std::string stlplus::lm_unit_name::to_string(void) const
231 {
232   return m_name + ":" + m_type;
233 }
234 
print(std::ostream & str) const235 bool stlplus::lm_unit_name::print(std::ostream& str) const
236 {
237   str << to_string();
238   return !str.fail();
239 }
240 
operator <<(std::ostream & str,const stlplus::lm_unit_name & name)241 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_name& name)
242 {
243   name.print(str);
244   return str;
245 }
246 
operator ==(const stlplus::lm_unit_name & l,const stlplus::lm_unit_name & r)247 bool stlplus::operator == (const stlplus::lm_unit_name& l, const stlplus::lm_unit_name& r)
248 {
249   return l.name() == r.name() && l.type() == r.type();
250 }
251 
operator <(const stlplus::lm_unit_name & l,const stlplus::lm_unit_name & r)252 bool stlplus::operator < (const stlplus::lm_unit_name& l, const stlplus::lm_unit_name& r)
253 {
254   // sort by name then type
255   return (l.name() != r.name()) ? l.name() < r.name() : l.type() < r.type();
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 // dependencies
260 
261 // file dependencies
262 
lm_file_dependency(void)263 stlplus::lm_file_dependency::lm_file_dependency(void) : m_line(0), m_column(0)
264 {
265 }
266 
lm_file_dependency(const std::string & library_path,const std::string & path,unsigned line,unsigned column)267 stlplus::lm_file_dependency::lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line, unsigned column)
268 {
269   set_path(library_path, path);
270   set_line(line);
271   set_column(column);
272 }
273 
~lm_file_dependency(void)274 stlplus::lm_file_dependency::~lm_file_dependency(void)
275 {
276 }
277 
path(void) const278 const std::string& stlplus::lm_file_dependency::path(void) const
279 {
280   return m_path;
281 }
282 
path_full(const std::string & library_path) const283 std::string stlplus::lm_file_dependency::path_full(const std::string& library_path) const
284 {
285   return filespec_to_path(library_path, m_path);
286 }
287 
set_path(const std::string & library_path,const std::string & path)288 void stlplus::lm_file_dependency::set_path(const std::string& library_path, const std::string& path)
289 {
290   m_path = filespec_to_relative_path(library_path, path);
291 }
292 
line(void) const293 unsigned stlplus::lm_file_dependency::line(void) const
294 {
295   return m_line;
296 }
297 
set_line(unsigned line)298 void stlplus::lm_file_dependency::set_line(unsigned line)
299 {
300   m_line = line;
301 }
302 
column(void) const303 unsigned stlplus::lm_file_dependency::column(void) const
304 {
305   return m_column;
306 }
307 
set_column(unsigned column)308 void stlplus::lm_file_dependency::set_column(unsigned column)
309 {
310   m_column = column;
311 }
312 
write(std::ostream & context) const313 bool stlplus::lm_file_dependency::write(std::ostream& context) const
314 {
315   context << m_path << " " << m_line << " " << m_column;
316   return !context.fail();
317 }
318 
read(std::istream & context)319 bool stlplus::lm_file_dependency::read(std::istream& context)
320 {
321   context >> m_path >> m_line >> m_column;
322   return !context.fail();
323 }
324 
print(std::ostream & str) const325 bool stlplus::lm_file_dependency::print(std::ostream& str) const
326 {
327   str << "file: " << m_path;
328   if (m_line != 0)
329     str << ":" << m_line << ":" << m_column;
330   return !str.fail();
331 }
332 
operator <<(std::ostream & str,const stlplus::lm_file_dependency & dependency)333 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_file_dependency& dependency)
334 {
335   dependency.print(str);
336   return str;
337 }
338 
339 // unit dependency
340 
lm_unit_dependency(void)341 stlplus::lm_unit_dependency::lm_unit_dependency(void)
342 {
343 }
344 
lm_unit_dependency(const std::string & library,const lm_unit_name & name)345 stlplus::lm_unit_dependency::lm_unit_dependency(const std::string& library, const lm_unit_name& name) :
346   m_library(library), m_name(name)
347 {
348 }
349 
~lm_unit_dependency(void)350 stlplus::lm_unit_dependency::~lm_unit_dependency(void)
351 {
352 }
353 
library(void) const354 const std::string& stlplus::lm_unit_dependency::library(void) const
355 {
356   return m_library;
357 }
358 
set_library(const std::string & library)359 void stlplus::lm_unit_dependency::set_library(const std::string& library)
360 {
361   m_library = library;
362 }
363 
unit_name(void) const364 const stlplus::lm_unit_name& stlplus::lm_unit_dependency::unit_name(void) const
365 {
366   return m_name;
367 }
368 
set_unit_name(const lm_unit_name & unit_name)369 void stlplus::lm_unit_dependency::set_unit_name(const lm_unit_name& unit_name)
370 {
371   m_name = unit_name;
372 }
373 
name(void) const374 const std::string& stlplus::lm_unit_dependency::name(void) const
375 {
376   return m_name.name();
377 }
378 
set_name(const std::string & name)379 void stlplus::lm_unit_dependency::set_name(const std::string& name)
380 {
381   m_name.set_name(name);
382 }
383 
type(void) const384 const std::string& stlplus::lm_unit_dependency::type(void) const
385 {
386   return m_name.type();
387 }
388 
set_type(const std::string & type)389 void stlplus::lm_unit_dependency::set_type(const std::string& type)
390 {
391   m_name.set_type(type);
392 }
393 
write(std::ostream & context) const394 bool stlplus::lm_unit_dependency::write(std::ostream& context) const
395 {
396   context << m_library;
397   m_name.write(context);
398   return !context.fail();
399 }
400 
read(std::istream & context)401 bool stlplus::lm_unit_dependency::read(std::istream& context)
402 {
403   context >> m_library;
404   m_name.read(context);;
405   return !context.fail();
406 }
407 
print(std::ostream & str) const408 bool stlplus::lm_unit_dependency::print(std::ostream& str) const
409 {
410   str << "unit: " << m_library << "." << m_name;
411   return !str.fail();
412 }
413 
operator <<(std::ostream & str,const stlplus::lm_unit_dependency & dependency)414 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_dependency& dependency)
415 {
416   dependency.print(str);
417   return str;
418 }
419 
420 // dependencies
421 
lm_dependencies(void)422 stlplus::lm_dependencies::lm_dependencies(void) : m_source(0)
423 {
424 }
425 
lm_dependencies(const lm_dependencies & r)426 stlplus::lm_dependencies::lm_dependencies(const lm_dependencies& r) : m_source(0)
427 {
428   *this = r;
429 }
430 
operator =(const stlplus::lm_dependencies & r)431 stlplus::lm_dependencies& stlplus::lm_dependencies::operator=(const stlplus::lm_dependencies& r)
432 {
433   if (m_source)
434     delete m_source;
435   m_source = 0;
436   if (r.m_source)
437     m_source = new lm_file_dependency(*r.m_source);
438   m_files = r.m_files;
439   m_units = r.m_units;
440   return *this;
441 }
442 
~lm_dependencies(void)443 stlplus::lm_dependencies::~lm_dependencies(void)
444 {
445   if (m_source)
446     delete m_source;
447 }
448 
set_source_file(const lm_file_dependency & source)449 void stlplus::lm_dependencies::set_source_file(const lm_file_dependency& source)
450 {
451   if (m_source)
452     delete m_source;
453   m_source = new lm_file_dependency(source);
454 }
455 
source_file_present(void) const456 bool stlplus::lm_dependencies::source_file_present(void) const
457 {
458   return (m_source != 0);
459 }
460 
source_file(void) const461 const stlplus::lm_file_dependency& stlplus::lm_dependencies::source_file(void) const
462 {
463   return *m_source;
464 }
465 
file_add(const lm_file_dependency & dependency)466 unsigned stlplus::lm_dependencies::file_add(const lm_file_dependency& dependency)
467 {
468   m_files.push_back(dependency);
469   return file_size()-1;
470 }
471 
file_size(void) const472 unsigned stlplus::lm_dependencies::file_size(void) const
473 {
474   return static_cast<unsigned>(m_files.size());
475 }
476 
file_dependency(unsigned i) const477 const stlplus::lm_file_dependency& stlplus::lm_dependencies::file_dependency(unsigned i) const
478 {
479   return m_files[i];
480 }
481 
file_erase(unsigned i)482 void stlplus::lm_dependencies::file_erase(unsigned i)
483 {
484   m_files.erase(m_files.begin()+i);
485 }
486 
unit_add(const lm_unit_dependency & dependency)487 unsigned stlplus::lm_dependencies::unit_add(const lm_unit_dependency& dependency)
488 {
489   m_units.push_back(dependency);
490   return unit_size()-1;
491 }
492 
unit_size(void) const493 unsigned stlplus::lm_dependencies::unit_size(void) const
494 {
495   return static_cast<unsigned>(m_units.size());
496 }
497 
unit_dependency(unsigned i) const498 const stlplus::lm_unit_dependency& stlplus::lm_dependencies::unit_dependency(unsigned i) const
499 {
500   return m_units[i];
501 }
502 
unit_erase(unsigned i)503 void stlplus::lm_dependencies::unit_erase(unsigned i)
504 {
505   m_units.erase(m_units.begin()+i);
506 }
507 
clear(void)508 void stlplus::lm_dependencies::clear(void)
509 {
510   if (m_source)
511     delete m_source;
512   m_source = 0;
513   m_files.clear();
514   m_units.clear();
515 }
516 
empty(void) const517 bool stlplus::lm_dependencies::empty(void) const
518 {
519   return (m_source == 0) && m_files.empty() && m_units.empty();
520 }
521 
write(std::ostream & context) const522 bool stlplus::lm_dependencies::write(std::ostream& context) const
523 {
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++)
529   {
530     m_files[i].write(context);
531     context << std::endl;
532   }
533   context << m_units.size() << std::endl;
534   for (unsigned j = 0; j < m_units.size(); j++)
535   {
536     m_units[j].write(context);
537     context << std::endl;
538   }
539   return !context.fail();
540 }
541 
read(std::istream & context)542 bool stlplus::lm_dependencies::read(std::istream& context)
543 {
544   clear();
545   bool source_present = false;
546   context >> source_present;
547   if (source_present)
548   {
549     m_source = new lm_file_dependency();
550     m_source->read(context);
551   }
552   unsigned files_size = 0;
553   context >> files_size;
554   for (unsigned i = 0; i < files_size; i++)
555   {
556     m_files.push_back(lm_file_dependency());
557     m_files.back().read(context);
558   }
559   unsigned units_size = 0;
560   context >> units_size;
561   for (unsigned j = 0; j < units_size; j++)
562   {
563     m_units.push_back(lm_unit_dependency());
564     m_units.back().read(context);
565   }
566   return !context.fail();
567 }
568 
print(std::ostream & str) const569 bool stlplus::lm_dependencies::print(std::ostream& str) const
570 {
571   if (m_source)
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;
577   return !str.fail();
578 }
579 
operator <<(std::ostream & str,const stlplus::lm_dependencies & dependencies)580 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_dependencies& dependencies)
581 {
582   dependencies.print(str);
583   return str;
584 }
585 
586 ////////////////////////////////////////////////////////////////////////////////
587 // lm_unit
588 ////////////////////////////////////////////////////////////////////////////////
589 
lm_unit(const lm_unit_name & name,lm_library * library)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)
592 {
593   read_header();
594 }
595 
~lm_unit(void)596 stlplus::lm_unit::~lm_unit(void)
597 {
598   write_header();
599 }
600 
601 ////////////////////////////////////////
602 // Header data
603 
unit_name(void) const604 const stlplus::lm_unit_name& stlplus::lm_unit::unit_name(void) const
605 {
606   return m_name;
607 }
608 
name(void) const609 const std::string& stlplus::lm_unit::name(void) const
610 {
611   return m_name.name();
612 }
613 
type(void) const614 const std::string& stlplus::lm_unit::type(void) const
615 {
616   return m_name.type();
617 }
618 
619 // dependencies
620 
621 // source file dependency
622 
set_source_file(const lm_file_dependency & dependency)623 void stlplus::lm_unit::set_source_file(const lm_file_dependency& dependency)
624 {
625   m_header_modified = true;
626   m_dependencies.set_source_file(dependency);
627 }
628 
source_file_present(void) const629 bool stlplus::lm_unit::source_file_present(void) const
630 {
631   return m_dependencies.source_file_present();
632 }
633 
source_file(void) const634 const stlplus::lm_file_dependency& stlplus::lm_unit::source_file(void) const
635 {
636   return m_dependencies.source_file();
637 }
638 
639 // other file dependencies
640 
file_add(const lm_file_dependency & dependency)641 unsigned stlplus::lm_unit::file_add(const lm_file_dependency& dependency)
642 {
643   m_header_modified = true;
644   return m_dependencies.file_add(dependency);
645 }
646 
file_size(void) const647 unsigned stlplus::lm_unit::file_size(void) const
648 {
649   return m_dependencies.file_size();
650 }
651 
file_dependency(unsigned i) const652 const stlplus::lm_file_dependency& stlplus::lm_unit::file_dependency(unsigned i) const
653 {
654   return m_dependencies.file_dependency(i);
655 }
656 
file_erase(unsigned i)657 void stlplus::lm_unit::file_erase(unsigned i)
658 {
659   m_header_modified = true;
660   m_dependencies.file_erase(i);
661 }
662 
663 // unit dependencies
664 
unit_add(const lm_unit_dependency & dependency)665 unsigned stlplus::lm_unit::unit_add(const lm_unit_dependency& dependency)
666 {
667   m_header_modified = true;
668   return m_dependencies.unit_add(dependency);
669 }
670 
unit_size(void) const671 unsigned stlplus::lm_unit::unit_size(void) const
672 {
673   return m_dependencies.unit_size();
674 }
675 
unit_dependency(unsigned i) const676 const stlplus::lm_unit_dependency& stlplus::lm_unit::unit_dependency(unsigned i) const
677 {
678   return m_dependencies.unit_dependency(i);
679 }
680 
unit_erase(unsigned i)681 void stlplus::lm_unit::unit_erase(unsigned i)
682 {
683   m_header_modified = true;
684   m_dependencies.unit_erase(i);
685 }
686 
dependencies(void) const687 const stlplus::lm_dependencies& stlplus::lm_unit::dependencies(void) const
688 {
689   return m_dependencies;
690 }
691 
set_dependencies(const lm_dependencies & dependencies)692 void stlplus::lm_unit::set_dependencies(const lm_dependencies& dependencies)
693 {
694   m_header_modified = true;
695   m_dependencies = dependencies;
696 }
697 
clear_dependencies(void)698 void stlplus::lm_unit::clear_dependencies(void)
699 {
700   m_header_modified = true;
701   m_dependencies.clear();
702 }
703 
empty_dependencies(void) const704 bool stlplus::lm_unit::empty_dependencies(void) const
705 {
706   return m_dependencies.empty();
707 }
708 
709 // dependency checking
710 
out_of_date(void) const711 bool stlplus::lm_unit::out_of_date(void) const
712 {
713   return m_library->out_of_date(m_name);
714 }
715 
up_to_date(void) const716 bool stlplus::lm_unit::up_to_date(void) const
717 {
718   return m_library->up_to_date(m_name);
719 }
720 
out_of_date_reason(void) const721 stlplus::lm_dependencies stlplus::lm_unit::out_of_date_reason(void) const
722 {
723   return m_library->out_of_date_reason(m_name);
724 }
725 
726 // supplementary data
727 
supplementary_data(void) const728 const std::string& stlplus::lm_unit::supplementary_data(void) const
729 {
730   return m_supplement;
731 }
732 
set_supplementary_data(const std::string & data)733 void stlplus::lm_unit::set_supplementary_data(const std::string& data)
734 {
735   m_supplement = data;
736   m_header_modified = true;
737 }
738 
739 ////////////////////////////////////////
740 // unit data management
741 
load(void)742 bool stlplus::lm_unit::load(void)
743 {
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);
751   m_loaded = true;
752   return result;
753 }
754 
save(void)755 bool stlplus::lm_unit::save(void)
756 {
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;
765   return result;
766 }
767 
loaded(void) const768 bool stlplus::lm_unit::loaded(void) const
769 {
770   return m_loaded;
771 }
772 
mark(void)773 void stlplus::lm_unit::mark(void)
774 {
775   m_marked = true;
776 }
777 
modified(void) const778 time_t stlplus::lm_unit::modified(void) const
779 {
780   return file_modified(filename());
781 }
782 
783 ////////////////////////////////////////
784 // containing library manager details
785 
library(void) const786 const stlplus::lm_library* stlplus::lm_unit::library(void) const
787 {
788   return m_library;
789 }
790 
library(void)791 stlplus::lm_library* stlplus::lm_unit::library(void)
792 {
793   return m_library;
794 }
795 
library_name(void) const796 const std::string& stlplus::lm_unit::library_name(void) const
797 {
798   return m_library->name();
799 }
800 
library_path(void) const801 const std::string& stlplus::lm_unit::library_path(void) const
802 {
803   return m_library->path();
804 }
805 
806 // error handling - these apply to the last read/write operation
807 
error(void) const808 bool stlplus::lm_unit::error(void) const
809 {
810   return m_error;
811 }
812 
813 // functions that customise subclasses of this superclass
814 
read(const std::string & filespec,void * type_data)815 bool stlplus::lm_unit::read(const std::string& filespec, void* type_data)
816 {
817   std::ifstream input(filespec.c_str());
818   bool result = read(input, type_data);
819   if (input.fail())
820   {
821     result = false;
822     m_error = true;
823   }
824   return result;
825 }
826 
read(std::istream &,void *)827 bool stlplus::lm_unit::read(std::istream&, void*)
828 {
829   return false;
830 }
831 
write(const std::string & filespec,void * type_data)832 bool stlplus::lm_unit::write(const std::string& filespec, void* type_data)
833 {
834   std::ofstream output(filespec.c_str());
835   bool result = write(output, type_data);
836   if (output.fail())
837   {
838     result = false;
839     m_error = true;
840   }
841   return result;
842 }
843 
write(std::ostream &,void *)844 bool stlplus::lm_unit::write(std::ostream&, void*)
845 {
846   return false;
847 }
848 
purge(void)849 bool stlplus::lm_unit::purge(void)
850 {
851   return true;
852 }
853 
clone(void) const854 stlplus::lm_unit* stlplus::lm_unit::clone(void) const
855 {
856   return new lm_unit(*this);
857 }
858 
print(std::ostream & str) const859 bool stlplus::lm_unit::print(std::ostream& str) const
860 {
861   str << m_name << " " << (m_loaded ? "loaded" : "") << " " << (m_marked ? "needs saving" : "");
862   return !str.fail();
863 }
864 
print_long(std::ostream & str) const865 bool stlplus::lm_unit::print_long(std::ostream& str) const
866 {
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())
876   {
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();
881     str << std::endl;
882   }
883   // now print other file dependencies
884   // convert these to relative paths too
885   for (unsigned f = 0; f < m_dependencies.file_size(); f++)
886   {
887     str << "  file: ";
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();
891     str << std::endl;
892   }
893   // now print unit dependencies
894   // convert unit types to their descriptive strings
895   for (unsigned u = 0; u < m_dependencies.unit_size(); u++)
896   {
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();
899     str << std::endl;
900   }
901   if (!m_supplement.empty())
902   {
903     str << "  supplementary data: " << m_supplement << std::endl;
904   }
905   return !str.fail();
906 }
907 
908 // header file management
909 
filename(void) const910 std::string stlplus::lm_unit::filename(void) const
911 {
912   return stlplus::create_filespec(library_path(), m_name.name(), m_name.type());
913 }
914 
header_filename(void) const915 std::string stlplus::lm_unit::header_filename(void) const
916 {
917   return stlplus::create_filespec(library_path(), m_name.name(), m_name.type() + std::string(HeaderExtension));
918 }
919 
read_header(void)920 bool stlplus::lm_unit::read_header(void)
921 {
922   if (file_exists(header_filename()))
923   {
924     std::ifstream input(header_filename().c_str());
925     m_dependencies.read(input);
926     input.get();
927     std::getline(input, m_supplement);
928   }
929   m_header_modified = false;
930   return true;
931 }
932 
write_header(void)933 bool stlplus::lm_unit::write_header(void)
934 {
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;
940   return true;
941 }
942 
943 // print diagnostics
944 
operator <<(std::ostream & str,const stlplus::lm_unit & u)945 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit& u)
946 {
947   u.print(str);
948   return str;
949 }
950 
951 ////////////////////////////////////////////////////////////////////////////////
952 // lm_library
953 ////////////////////////////////////////////////////////////////////////////////
954 
955 ////////////////////////////////////////////////////////////////////////////////
956 // constructors/destructors
957 // copy operations only legal on unopened libraries
958 
lm_library(library_manager * manager)959 stlplus::lm_library::lm_library(library_manager* manager) : m_writable(false), m_manager(manager)
960 {
961 }
962 
lm_library(const lm_library & library)963 stlplus::lm_library::lm_library(const lm_library& library) : m_writable(library.m_writable), m_manager(library.m_manager)
964 {
965 }
966 
operator =(const stlplus::lm_library & library)967 stlplus::lm_library& stlplus::lm_library::operator = (const stlplus::lm_library& library)
968 {
969   m_writable = library.m_writable;
970   m_manager = library.m_manager;
971   return *this;
972 }
973 
~lm_library(void)974 stlplus::lm_library::~lm_library(void)
975 {
976   close();
977 }
978 
manager(void) const979 const stlplus::library_manager* stlplus::lm_library::manager(void) const
980 {
981   return m_manager;
982 }
983 
manager(void)984 stlplus::library_manager* stlplus::lm_library::manager(void)
985 {
986   return m_manager;
987 }
988 
989 //////////////////////////////////////////////////////////////////////////////
990 // initialisers
991 
create(const std::string & name,const std::string & path,bool writable)992 bool stlplus::lm_library::create(const std::string& name, const std::string& path, bool writable)
993 {
994   close();
995   if (!create_library(path, m_manager->m_owner, name, writable)) return false;
996   return open(path);
997 }
998 
open(const std::string & path)999 bool stlplus::lm_library::open(const std::string& path)
1000 {
1001   close();
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();
1006 }
1007 
1008 //////////////////////////////////////////////////////////////////////////////
1009 // management of types
1010 
load_type(const std::string & type)1011 bool stlplus::lm_library::load_type(const std::string& type)
1012 {
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++)
1021   {
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();
1025     lm_unit_ptr unit;
1026     // if there's a callback, use it to create the subclass, else create the
1027     // superclass which only contains header information
1028     if (fn)
1029       unit.set(fn(uname,this,data));
1030     else
1031       unit.set(new lm_unit(uname,this));
1032     m_units[uname] = unit;
1033   }
1034   return true;
1035 }
1036 
load_types(void)1037 bool stlplus::lm_library::load_types(void)
1038 {
1039   bool result = true;
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);
1042   return result;
1043 }
1044 
remove_type(const std::string & type)1045 bool stlplus::lm_library::remove_type(const std::string& type)
1046 {
1047   bool result = true;
1048   std::vector<std::string> units = names(type);
1049   for (std::vector<std::string>::iterator i = units.begin(); i != units.end(); i++)
1050   {
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())
1054       m_units.erase(ni);
1055   }
1056   return result;
1057 }
1058 
1059 //////////////////////////////////////////////////////////////////////////////
1060 // whole library operations
1061 
load(void)1062 bool stlplus::lm_library::load(void)
1063 {
1064   bool result = true;
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();
1067   return result;
1068 }
1069 
save(void)1070 bool stlplus::lm_library::save(void)
1071 {
1072   bool result = true;
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();
1075   return result;
1076 }
1077 
purge(void)1078 bool stlplus::lm_library::purge(void)
1079 {
1080   bool result = true;
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();
1083   return result;
1084 }
1085 
close(void)1086 bool stlplus::lm_library::close(void)
1087 {
1088   bool result = save();
1089   m_units.clear();
1090   m_path = "";
1091   m_writable = false;
1092   return result;
1093 }
1094 
erase(void)1095 bool stlplus::lm_library::erase(void)
1096 {
1097   // preserve the path because close destroys it
1098   std::string path = m_path;
1099   return close() && erase_library(path, m_manager->m_owner);
1100 }
1101 
name(void) const1102 const std::string& stlplus::lm_library::name(void) const
1103 {
1104   return m_name;
1105 }
1106 
path(void) const1107 const std::string& stlplus::lm_library::path(void) const
1108 {
1109   return m_path;
1110 }
1111 
1112 //////////////////////////////////////////////////////////////////////////////
1113 // managing read/write status
1114 
set_read_write(bool writable)1115 bool stlplus::lm_library::set_read_write(bool writable)
1116 {
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;
1123 }
1124 
set_writable(void)1125 bool stlplus::lm_library::set_writable(void)
1126 {
1127   return set_read_write(true);
1128 }
1129 
set_read_only(void)1130 bool stlplus::lm_library::set_read_only(void)
1131 {
1132   return set_read_write(false);
1133 }
1134 
writable(void) const1135 bool stlplus::lm_library::writable(void) const
1136 {
1137   return os_writable() && lm_writable();
1138 }
1139 
read_only(void) const1140 bool stlplus::lm_library::read_only(void) const
1141 {
1142   return os_read_only() || lm_read_only();
1143 }
1144 
os_writable(void) const1145 bool stlplus::lm_library::os_writable(void) const
1146 {
1147   return folder_writable(path());
1148 }
1149 
os_read_only(void) const1150 bool stlplus::lm_library::os_read_only(void) const
1151 {
1152   return !folder_writable(path());
1153 }
1154 
lm_writable(void) const1155 bool stlplus::lm_library::lm_writable(void) const
1156 {
1157   return m_writable;
1158 }
1159 
lm_read_only(void) const1160 bool stlplus::lm_library::lm_read_only(void) const
1161 {
1162   return !m_writable;
1163 }
1164 
1165 //////////////////////////////////////////////////////////////////////////////
1166 // unit management
1167 
local_find(const lm_unit_name & name)1168 std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::iterator stlplus::lm_library::local_find(const lm_unit_name& name)
1169 {
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);
1174 }
1175 
local_find(const lm_unit_name & name) const1176 std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator stlplus::lm_library::local_find(const lm_unit_name& name) const
1177 {
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);
1182 }
1183 
exists(const lm_unit_name & name) const1184 bool stlplus::lm_library::exists(const lm_unit_name& name) const
1185 {
1186   return find(name).present();
1187 }
1188 
create(const stlplus::lm_unit_name & name)1189 stlplus::lm_unit_ptr stlplus::lm_library::create(const stlplus::lm_unit_name& name)
1190 {
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
1196   erase(uname);
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];
1206 }
1207 
loaded(const lm_unit_name & name) const1208 bool stlplus::lm_library::loaded(const lm_unit_name& name) const
1209 {
1210   lm_unit_ptr unit = find(name);
1211   return unit && unit->loaded();
1212 }
1213 
load(const lm_unit_name & name)1214 bool stlplus::lm_library::load(const lm_unit_name& name)
1215 {
1216   lm_unit_ptr unit = find(name);
1217   if (!unit) return false;
1218   return unit->load();
1219 }
1220 
purge(const lm_unit_name & name)1221 bool stlplus::lm_library::purge(const lm_unit_name& name)
1222 {
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;
1228   return result;
1229 }
1230 
save(const lm_unit_name & name)1231 bool stlplus::lm_library::save(const lm_unit_name& name)
1232 {
1233   if (read_only()) return false;
1234   lm_unit_ptr unit = find(name);
1235   if (!unit) return false;
1236   return unit->save();
1237 }
1238 
erase(const lm_unit_name & name)1239 bool stlplus::lm_library::erase(const lm_unit_name& name)
1240 {
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();
1246   m_units.erase(i);
1247   file_delete(spec);
1248   file_delete(header_spec);
1249   return true;
1250 }
1251 
mark(const lm_unit_name & name)1252 bool stlplus::lm_library::mark(const lm_unit_name& name)
1253 {
1254   if (read_only()) return false;
1255   lm_unit_ptr unit = find(name);
1256   if (!unit) return false;
1257   unit->mark();
1258   return true;
1259 }
1260 
modified(const lm_unit_name & name) const1261 time_t stlplus::lm_library::modified(const lm_unit_name& name) const
1262 {
1263   lm_unit_ptr unit = find(name);
1264   return unit ? unit->modified() : 0;
1265 }
1266 
erase_by_source(const std::string & source_file)1267 bool stlplus::lm_library::erase_by_source(const std::string& source_file)
1268 {
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++)
1276   {
1277     lm_unit_ptr unit = find(*i);
1278     if (unit && unit->source_file_present())
1279     {
1280       std::string file_full = unit->source_file().path_full(unit->library_path());
1281       if (file_full == source_file_full)
1282       {
1283         erase(*i);
1284         result = true;
1285       }
1286     }
1287   }
1288   return result;
1289 }
1290 
find(const stlplus::lm_unit_name & name) const1291 const stlplus::lm_unit_ptr stlplus::lm_library::find(const stlplus::lm_unit_name& name) const
1292 {
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();
1295   return i->second;
1296 }
1297 
find(const stlplus::lm_unit_name & name)1298 stlplus::lm_unit_ptr stlplus::lm_library::find(const stlplus::lm_unit_name& name)
1299 {
1300   std::map<lm_unit_name,lm_unit_ptr>::iterator i = local_find(name);
1301   if (i == m_units.end()) return lm_unit_ptr();
1302   return i->second;
1303 }
1304 
names(void) const1305 std::vector<stlplus::lm_unit_name> stlplus::lm_library::names(void) const
1306 {
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());
1310   return result;
1311 }
1312 
names(const std::string & type) const1313 std::vector<std::string> stlplus::lm_library::names(const std::string& type) const
1314 {
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());
1319   return result;
1320 }
1321 
handles(void) const1322 std::vector<stlplus::lm_unit_ptr> stlplus::lm_library::handles(void) const
1323 {
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);
1327   return result;
1328 }
1329 
handles(const std::string & type) const1330 std::vector<stlplus::lm_unit_ptr> stlplus::lm_library::handles(const std::string& type) const
1331 {
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);
1336   return result;
1337 }
1338 
1339 ////////////////////////////////////////////////////////////////////////////////
1340 // dependency checking
1341 
out_of_date(const stlplus::lm_unit_name & name) const1342 bool stlplus::lm_library::out_of_date(const stlplus::lm_unit_name& name) const
1343 {
1344   return m_manager->out_of_date(m_name, name);
1345 }
1346 
up_to_date(const stlplus::lm_unit_name & name) const1347 bool stlplus::lm_library::up_to_date(const stlplus::lm_unit_name& name) const
1348 {
1349   return m_manager->up_to_date(m_name, name);
1350 }
1351 
out_of_date_reason(const stlplus::lm_unit_name & unit) const1352 stlplus::lm_dependencies stlplus::lm_library::out_of_date_reason(const stlplus::lm_unit_name& unit) const
1353 {
1354   return m_manager->out_of_date_reason(m_name, unit);
1355 }
1356 
tidy(void)1357 std::pair<bool,unsigned> stlplus::lm_library::tidy(void)
1358 {
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
1363   for (;;)
1364   {
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++)
1368     {
1369       if (out_of_date(*i))
1370       {
1371         if (!erase(*i))
1372           result.first = false;
1373         else
1374           result.second++;
1375       }
1376     }
1377     if (!result.first) break;
1378     if (result.second == initial_count) break;
1379   }
1380   return result;
1381 }
1382 
1383 ////////////////////////////////////////////////////////////////////////////////
1384 // do-everything print routine!
1385 
pretty_print(std::ostream & str,bool print_units,const std::string & type) const1386 bool stlplus::lm_library::pretty_print(std::ostream& str,
1387                                        bool print_units,
1388                                        const std::string& type) const
1389 {
1390   // print the library information
1391   if (this == m_manager->work())
1392     str << "->> ";
1393   else
1394     str << "    ";
1395   str << name() << " in directory " << folder_to_relative_path(path());
1396   if (read_only()) str << " (locked)";
1397   str << std::endl;
1398   // select the units
1399   if (print_units)
1400   {
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++)
1403     {
1404       // select the requested unit kind
1405       if (type.empty() || type == j->first)
1406       {
1407         // get all the units of this kind
1408         std::vector<std::string> unit_names = names(j->first);
1409         if (!unit_names.empty())
1410         {
1411           str << "    " << j->second.m_description << std::endl;
1412           for (unsigned k = 0; k < unit_names.size(); k++)
1413           {
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)";
1417             str << std::endl;
1418             if (!reason.empty())
1419             {
1420               if (reason.source_file_present())
1421               {
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;
1424               }
1425               for (unsigned i1 = 0; i1 < reason.file_size(); i1++)
1426               {
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;
1429               }
1430               for (unsigned i2 = 0; i2 < reason.unit_size(); i2++)
1431               {
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;
1435               }
1436             }
1437           }
1438         }
1439       }
1440     }
1441   }
1442   return true;
1443 }
1444 
1445 ////////////////////////////////////////////////////////////////////////////////
1446 // diagnostic print routines
1447 
print(std::ostream & str) const1448 bool stlplus::lm_library::print(std::ostream& str) const
1449 {
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);
1453   return !str.fail();
1454 }
1455 
print_long(std::ostream & str) const1456 bool stlplus::lm_library::print_long(std::ostream& str) const
1457 {
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);
1461   return !str.fail();
1462 }
1463 
operator <<(std::ostream & str,const stlplus::lm_library & lib)1464 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_library& lib)
1465 {
1466   lib.print(str);
1467   return str;
1468 }
1469 
1470 ////////////////////////////////////////////////////////////////////////////////
1471 // library manager
1472 ////////////////////////////////////////////////////////////////////////////////
1473 
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
1476 
is_library(const std::string & path,const std::string & owner)1477 bool stlplus::library_manager::is_library(const std::string& path, const std::string& owner)
1478 {
1479   std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);
1480   return file_exists(spec);
1481 }
1482 
library_name(const std::string & path,const std::string & owner)1483 std::string stlplus::library_manager::library_name(const std::string& path, const std::string& owner)
1484 {
1485   std::string name;
1486   bool writable = false;
1487   if (!read_context(path, owner, name, writable))
1488     return std::string();
1489   return name;
1490 }
1491 
is_library(const std::string & path)1492 bool stlplus::library_manager::is_library(const std::string& path)
1493 {
1494   return is_library(path, m_owner);
1495 }
1496 
library_name(const std::string & path)1497 std::string stlplus::library_manager::library_name(const std::string& path)
1498 {
1499   return library_name(path, m_owner);
1500 }
1501 
1502 //////////////////////////////////////////////////////////////////////////////
1503 // tructors
1504 
library_manager(const std::string & owner,bool library_case,bool unit_case)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)
1507 {
1508 }
1509 
~library_manager(void)1510 stlplus::library_manager::~library_manager(void)
1511 {
1512   close();
1513 }
1514 
1515 //////////////////////////////////////////////////////////////////////////////
1516 // case sensitivity
1517 
library_case(void) const1518 bool stlplus::library_manager::library_case(void) const
1519 {
1520   return m_library_case;
1521 }
1522 
set_library_case(bool library_case)1523 void stlplus::library_manager::set_library_case(bool library_case)
1524 {
1525   m_library_case = library_case;
1526 }
1527 
unit_case(void) const1528 bool stlplus::library_manager::unit_case(void) const
1529 {
1530   return m_unit_case;
1531 }
1532 
set_unit_case(bool unit_case)1533 void stlplus::library_manager::set_unit_case(bool unit_case)
1534 {
1535   m_unit_case = unit_case;
1536 }
1537 
1538 ////////////////////////////////////////////////////////////////////////////////
1539 // type handling
1540 
add_type(const std::string & type,const std::string & description,lm_create_callback fn,void * type_data)1541 bool stlplus::library_manager::add_type(const std::string& type,
1542                                         const std::string& description,
1543                                         lm_create_callback fn,
1544                                         void* type_data)
1545 {
1546   bool result = true;
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);
1550   return result;
1551 }
1552 
remove_type(const std::string & type)1553 bool stlplus::library_manager::remove_type(const std::string& type)
1554 {
1555   bool result = true;
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);
1559   return result;
1560 }
1561 
types(void) const1562 std::vector<std::string> stlplus::library_manager::types(void) const
1563 {
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);
1567   return result;
1568 }
1569 
description(const std::string & type) const1570 std::string stlplus::library_manager::description(const std::string& type) const
1571 {
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;
1575 }
1576 
callback(const std::string & type) const1577 stlplus::lm_create_callback stlplus::library_manager::callback(const std::string& type) const
1578 {
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;
1582 }
1583 
type_data(const std::string & type) const1584 void* stlplus::library_manager::type_data(const std::string& type) const
1585 {
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;
1589 }
1590 
1591 //////////////////////////////////////////////////////////////////////////////
1592 // mapping file handling
1593 
set_mapping_file(const std::string & mapping_file)1594 void stlplus::library_manager::set_mapping_file(const std::string& mapping_file)
1595 {
1596   m_mapping_file = mapping_file;
1597 }
1598 
load_mappings(const std::string & mapping_file)1599 bool stlplus::library_manager::load_mappings(const std::string& mapping_file)
1600 {
1601   m_mapping_file = mapping_file;
1602   if (!file_exists(mapping_file))
1603   {
1604     return false;
1605   }
1606   std::ifstream input(mapping_file.c_str());
1607   if (input.fail())
1608     return false;
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
1612   bool result = true;
1613   unsigned line = 1;
1614   for (std::string path = ""; std::getline(input,path); line++)
1615   {
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))
1619     {
1620       result = false;
1621     }
1622     else
1623     {
1624       lm_library* lib = open(full_path);
1625       if (!lib)
1626         result = false;
1627       else if (line == 1)
1628         setwork(lib->name());
1629     }
1630   }
1631   return result;
1632 }
1633 
mapping_file()1634 std::string stlplus::library_manager::mapping_file()
1635 {
1636   return m_mapping_file;
1637 }
1638 
set_ini_manager(ini_manager * ini_files,const std::string & library_section,const std::string & work_name)1639 bool stlplus::library_manager::set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_name)
1640 {
1641   if (!ini_files) return false;
1642   bool result = true;
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))
1649   {
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++)
1653     {
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())
1659       {
1660       }
1661       else if (library_name == m_ini_work)
1662       {
1663         work_name = m_ini_files->variable_value(m_ini_section, library_name);
1664       }
1665       else
1666       {
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
1671         // whew!
1672         std::string full_path = folder_to_path(folder_part(filename),value);
1673         if (!is_library(full_path))
1674           result = false;
1675         else
1676         {
1677           lm_library* lib = open(full_path);
1678           if (!lib)
1679             result = false;
1680         }
1681       }
1682     }
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
1685     // library manager
1686     if (work_name.empty())
1687       unsetwork();
1688     else
1689       result &= setwork(work_name);
1690   }
1691   return result;
1692 }
1693 
get_ini_manager(void) const1694 stlplus::ini_manager* stlplus::library_manager::get_ini_manager(void) const
1695 {
1696   return m_ini_files;
1697 }
1698 
save_mappings(void)1699 bool stlplus::library_manager::save_mappings (void)
1700 {
1701   bool result = true;
1702   // save to mapping file or ini manager or both
1703   if (!m_mapping_file.empty())
1704   {
1705     if (m_libraries.size() == 0)
1706     {
1707       // if the file would be empty, delete it
1708       if (!file_delete(m_mapping_file))
1709         result = false;
1710     }
1711     else
1712     {
1713       std::ofstream output(m_mapping_file.c_str());
1714       if (output.fail())
1715       {
1716         result = false;
1717       }
1718       else
1719       {
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)
1728         {
1729           if (libraries[i] != work_name())
1730             output << folder_to_relative_path(folder_part(m_mapping_file), path(libraries[i])) << std::endl;
1731         }
1732         if (output.fail())
1733           result = false;
1734       }
1735     }
1736   }
1737   if (m_ini_files)
1738   {
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++)
1754     {
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, "");
1759       else
1760       {
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)
1767         {
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);
1771         }
1772       }
1773     }
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++)
1777     {
1778       std::string lib_name = lib_names[j];
1779       if (std::find(ini_names.begin(), ini_names.end(), lib_name) == ini_names.end())
1780       {
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);
1786       }
1787     }
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())
1798       result = false;
1799   }
1800   return result;
1801 }
1802 
1803 //////////////////////////////////////////////////////////////////////////////
1804 // library management
1805 
exists(const std::string & name) const1806 bool stlplus::library_manager::exists(const std::string& name) const
1807 {
1808   return find(name) != 0;
1809 }
1810 
create(const std::string & name,const std::string & path,bool writable)1811 stlplus::lm_library* stlplus::library_manager::create(const std::string& name, const std::string& path, bool writable)
1812 {
1813   if (!create_library(path, m_owner, name, writable)) return 0;
1814   return open(path);
1815 }
1816 
open(const std::string & path)1817 stlplus::lm_library* stlplus::library_manager::open(const std::string& path)
1818 {
1819   std::string name;
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
1823   close(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)))
1827   {
1828     // remove the library in the event of an error
1829     m_libraries.erase(--m_libraries.end());
1830     return 0;
1831   }
1832   return &m_libraries.back();
1833 }
1834 
load(const std::string & name)1835 bool stlplus::library_manager::load(const std::string& name)
1836 {
1837   std::list<lm_library>::iterator found = local_find(name);
1838   if (found == m_libraries.end()) return false;
1839   return found->load();
1840 }
1841 
save(const std::string & name)1842 bool stlplus::library_manager::save(const std::string& name)
1843 {
1844   std::list<lm_library>::iterator found = local_find(name);
1845   if (found == m_libraries.end()) return false;
1846   return found->save();
1847 }
1848 
purge(const std::string & name)1849 bool stlplus::library_manager::purge(const std::string& name)
1850 {
1851   std::list<lm_library>::iterator found = local_find(name);
1852   if (found == m_libraries.end()) return false;
1853   return found->purge();
1854 }
1855 
close(const std::string & name)1856 bool stlplus::library_manager::close(const std::string& name)
1857 {
1858   bool result= true;
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 = "";
1864   return result;
1865 }
1866 
erase(const std::string & name)1867 bool stlplus::library_manager::erase(const std::string& name)
1868 {
1869   bool result= true;
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 = "";
1875   return result;
1876 }
1877 
1878 // operations on all libraries - as above but applied to all the libraries in the manager
1879 
load(void)1880 bool stlplus::library_manager::load(void)
1881 {
1882   bool result = true;
1883   for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)
1884     result &= i->load();
1885   return result;
1886 }
1887 
save(void)1888 bool stlplus::library_manager::save(void)
1889 {
1890   bool result = true;
1891   for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)
1892     result &= i->save();
1893   return result;
1894 }
1895 
purge(void)1896 bool stlplus::library_manager::purge(void)
1897 {
1898   bool result = true;
1899   for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)
1900     result &= i->purge();
1901   return result;
1902 }
1903 
close(void)1904 bool stlplus::library_manager::close(void)
1905 {
1906   bool result = true;
1907   for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); )
1908   {
1909     std::list<lm_library>::iterator next = i;
1910     next++;
1911     result &= i->close();
1912     m_libraries.erase(i);
1913     i = next;
1914   }
1915   return result;
1916 }
1917 
erase(void)1918 bool stlplus::library_manager::erase(void)
1919 {
1920   bool result = true;
1921   for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); )
1922   {
1923     std::list<lm_library>::iterator next = i;
1924     next++;
1925     result &= i->erase();
1926     m_libraries.erase(i);
1927     i = next;
1928   }
1929   return result;
1930 }
1931 
1932 // get name and path of a library - name can differ in case if the library manager is case-insensitive
1933 
name(const std::string & name) const1934 std::string stlplus::library_manager::name(const std::string& name) const
1935 {
1936   std::list<lm_library>::const_iterator found = local_find(name);
1937   if (found == m_libraries.end()) return std::string();
1938   return found->name();
1939 }
1940 
path(const std::string & name) const1941 std::string stlplus::library_manager::path(const std::string& name) const
1942 {
1943   std::list<lm_library>::const_iterator found = local_find(name);
1944   if (found == m_libraries.end()) return std::string();
1945   return found->path();
1946 }
1947 
1948 // control and test read/write status
1949 
set_writable(const std::string & name)1950 bool stlplus::library_manager::set_writable(const std::string& name)
1951 {
1952   std::list<lm_library>::iterator found = local_find(name);
1953   if (found == m_libraries.end()) return false;
1954   return found->set_writable();
1955 }
1956 
set_read_only(const std::string & name)1957 bool stlplus::library_manager::set_read_only(const std::string& name)
1958 {
1959   std::list<lm_library>::iterator found = local_find(name);
1960   if (found == m_libraries.end()) return false;
1961   return found->set_read_only();
1962 }
1963 
writable(const std::string & name) const1964 bool stlplus::library_manager::writable(const std::string& name) const
1965 {
1966   std::list<lm_library>::const_iterator found = local_find(name);
1967   if (found == m_libraries.end()) return false;
1968   return found->writable();
1969 }
1970 
read_only(const std::string & name) const1971 bool stlplus::library_manager::read_only(const std::string& name) const
1972 {
1973   std::list<lm_library>::const_iterator found = local_find(name);
1974   if (found == m_libraries.end()) return false;
1975   return found->read_only();
1976 }
1977 
os_writable(const std::string & library) const1978 bool stlplus::library_manager::os_writable(const std::string& library) const
1979 {
1980   std::list<lm_library>::const_iterator found = local_find(library);
1981   if (found == m_libraries.end()) return false;
1982   return found->os_writable();
1983 }
1984 
os_read_only(const std::string & library) const1985 bool stlplus::library_manager::os_read_only(const std::string& library) const
1986 {
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();
1990 }
1991 
lm_writable(const std::string & library) const1992 bool stlplus::library_manager::lm_writable(const std::string& library) const
1993 {
1994   std::list<lm_library>::const_iterator found = local_find(library);
1995   if (found == m_libraries.end()) return false;
1996   return found->lm_writable();
1997 }
1998 
lm_read_only(const std::string & library) const1999 bool stlplus::library_manager::lm_read_only(const std::string& library) const
2000 {
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();
2004 }
2005 
2006 // find a library in the manager - returns null if not found
2007 
find(const std::string & name)2008 stlplus::lm_library* stlplus::library_manager::find(const std::string& name)
2009 {
2010   std::list<lm_library>::iterator found = local_find(name);
2011   if (found == m_libraries.end()) return 0;
2012   return &(*found);
2013 }
2014 
find(const std::string & name) const2015 const stlplus::lm_library* stlplus::library_manager::find(const std::string& name) const
2016 {
2017   std::list<lm_library>::const_iterator found = local_find(name);
2018   if (found == m_libraries.end()) return 0;
2019   return &(*found);
2020 }
2021 
2022 // get the set of all library names
2023 
names(void) const2024 std::vector<std::string> stlplus::library_manager::names(void) const
2025 {
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());
2029   return result;
2030 }
2031 
2032 // get the set of all libraries
2033 
handles(void) const2034 std::vector<const stlplus::lm_library*> stlplus::library_manager::handles(void) const
2035 {
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));
2039   return result;
2040 }
2041 
handles(void)2042 std::vector<stlplus::lm_library*> stlplus::library_manager::handles(void)
2043 {
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));
2047   return result;
2048 }
2049 
2050 //////////////////////////////////////////////////////////////////////////////
2051 // current library management
2052 
setwork(const std::string & name)2053 bool stlplus::library_manager::setwork(const std::string& name)
2054 {
2055   unsetwork();
2056   std::list<lm_library>::const_iterator found = local_find(name);
2057   if (found == m_libraries.end()) return false;
2058   m_work = found->name();
2059   return true;
2060 }
2061 
unsetwork(void)2062 bool stlplus::library_manager::unsetwork(void)
2063 {
2064   m_work = "";
2065   return true;
2066 }
2067 
work(void) const2068 const stlplus::lm_library* stlplus::library_manager::work(void) const
2069 {
2070   if (m_work.empty()) return 0;
2071   return find(m_work);
2072 }
2073 
work(void)2074 stlplus::lm_library* stlplus::library_manager::work(void)
2075 {
2076   if (m_work.empty()) return 0;
2077   return find(m_work);
2078 }
2079 
work_name(void) const2080 std::string stlplus::library_manager::work_name(void) const
2081 {
2082   return m_work;
2083 }
2084 
2085 //////////////////////////////////////////////////////////////////////////////
2086 // unit management within a library
2087 
exists(const std::string & name,const stlplus::lm_unit_name & unit) const2088 bool stlplus::library_manager::exists(const std::string& name, const stlplus::lm_unit_name& unit) const
2089 {
2090   std::list<lm_library>::const_iterator found = local_find(name);
2091   if (found == m_libraries.end()) return false;
2092   return found->exists(unit);
2093 }
2094 
create(const std::string & name,const stlplus::lm_unit_name & unit)2095 stlplus::lm_unit_ptr stlplus::library_manager::create(const std::string& name, const stlplus::lm_unit_name& unit)
2096 {
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);
2100 }
2101 
loaded(const std::string & name,const stlplus::lm_unit_name & unit) const2102 bool stlplus::library_manager::loaded(const std::string& name, const stlplus::lm_unit_name& unit) const
2103 {
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);
2107 }
2108 
load(const std::string & name,const stlplus::lm_unit_name & unit)2109 bool stlplus::library_manager::load(const std::string& name, const stlplus::lm_unit_name& unit)
2110 {
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);
2114 }
2115 
purge(const std::string & name,const stlplus::lm_unit_name & unit)2116 bool stlplus::library_manager::purge(const std::string& name, const stlplus::lm_unit_name& unit)
2117 {
2118   std::list<lm_library>::iterator found = local_find(name);
2119   if (found == m_libraries.end()) return false;
2120   return found->purge(unit);
2121 }
2122 
save(const std::string & name,const stlplus::lm_unit_name & unit)2123 bool stlplus::library_manager::save(const std::string& name, const stlplus::lm_unit_name& unit)
2124 {
2125   std::list<lm_library>::iterator found = local_find(name);
2126   if (found == m_libraries.end()) return false;
2127   return found->save(unit);
2128 }
2129 
erase(const std::string & name,const stlplus::lm_unit_name & unit)2130 bool stlplus::library_manager::erase(const std::string& name, const stlplus::lm_unit_name& unit)
2131 {
2132   std::list<lm_library>::iterator found = local_find(name);
2133   if (found == m_libraries.end()) return false;
2134   return found->erase(unit);
2135 }
2136 
mark(const std::string & name,const stlplus::lm_unit_name & unit)2137 bool stlplus::library_manager::mark(const std::string& name, const stlplus::lm_unit_name& unit)
2138 {
2139   std::list<lm_library>::iterator found = local_find(name);
2140   if (found == m_libraries.end()) return false;
2141   return found->mark(unit);
2142 }
2143 
modified(const std::string & name,const stlplus::lm_unit_name & unit) const2144 time_t stlplus::library_manager::modified(const std::string& name, const stlplus::lm_unit_name& unit) const
2145 {
2146   std::list<lm_library>::const_iterator found = local_find(name);
2147   if (found == m_libraries.end()) return 0;
2148   return found->modified(unit);
2149 }
2150 
erase_by_source(const std::string & source_file)2151 bool stlplus::library_manager::erase_by_source(const std::string& source_file)
2152 {
2153   bool result = true;
2154   for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)
2155     if (i->writable())
2156       result &= i->erase_by_source(source_file);
2157   return result;
2158 }
2159 
find(const std::string & name,const stlplus::lm_unit_name & unit) const2160 const stlplus::lm_unit_ptr stlplus::library_manager::find(const std::string& name, const stlplus::lm_unit_name& unit) const
2161 {
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);
2166 }
2167 
find(const std::string & name,const stlplus::lm_unit_name & unit)2168 stlplus::lm_unit_ptr stlplus::library_manager::find(const std::string& name, const stlplus::lm_unit_name& unit)
2169 {
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);
2173 }
2174 
names(const std::string & name) const2175 std::vector<stlplus::lm_unit_name> stlplus::library_manager::names(const std::string& name) const
2176 {
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();
2180 }
2181 
names(const std::string & name,const std::string & type) const2182 std::vector<std::string> stlplus::library_manager::names(const std::string& name, const std::string& type) const
2183 {
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);
2187 }
2188 
handles(const std::string & name) const2189 std::vector<stlplus::lm_unit_ptr> stlplus::library_manager::handles(const std::string& name) const
2190 {
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();
2194 }
2195 
handles(const std::string & name,const std::string & type) const2196 std::vector<stlplus::lm_unit_ptr> stlplus::library_manager::handles(const std::string& name, const std::string& type) const
2197 {
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);
2201 }
2202 
2203 //////////////////////////////////////////////////////////////////////////////
2204 // dependency checking
2205 // done at the top level because a global view of the libraries is required
2206 
out_of_date(const std::string & library,const stlplus::lm_unit_name & name) const2207 bool stlplus::library_manager::out_of_date(const std::string& library, const stlplus::lm_unit_name& name) const
2208 {
2209   return !up_to_date(library, name);
2210 }
2211 
up_to_date(const std::string & library,const stlplus::lm_unit_name & name) const2212 bool stlplus::library_manager::up_to_date(const std::string& library, const stlplus::lm_unit_name& name) const
2213 {
2214   lm_dependencies reason = out_of_date_reason(library, name);
2215   return reason.empty();
2216 }
2217 
out_of_date_reason(const std::string & library,const stlplus::lm_unit_name & name) const2218 stlplus::lm_dependencies stlplus::library_manager::out_of_date_reason(const std::string& library, const stlplus::lm_unit_name& name) const
2219 {
2220   std::map<std::pair<std::string,stlplus::lm_unit_name>,lm_dependencies> visited;
2221   return out_of_date_check(visited, this, library, name);
2222 }
2223 
tidy(const std::string & library)2224 std::pair<bool,unsigned> stlplus::library_manager::tidy(const std::string& library)
2225 {
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();
2229 }
2230 
tidy(void)2231 std::pair<bool,unsigned> stlplus::library_manager::tidy(void)
2232 {
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++)
2235   {
2236     if (i->writable())
2237     {
2238       std::pair<bool,unsigned> library_result = i->tidy();
2239       result.second += library_result.second;
2240       result.first &= library_result.first;
2241     }
2242   }
2243   return result;
2244 }
2245 
2246 //////////////////////////////////////////////////////////////////////////////
2247 // do-everything print routine!
2248 
pretty_print(std::ostream & str,bool print_units,const std::string & lib,const std::string & type) const2249 bool stlplus::library_manager::pretty_print(std::ostream& str,
2250                                             bool print_units,
2251                                             const std::string& lib,
2252                                             const std::string& type) const
2253 {
2254   bool library_found = false;
2255   for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)
2256   {
2257     // select the library
2258     if (lib.empty() || lib == l->name())
2259     {
2260       l->pretty_print(str, print_units, type);
2261       library_found = true;
2262     }
2263   }
2264   if (!library_found)
2265   {
2266     if (lib.empty())
2267       str << "there are no libraries in the library list" << std::endl;
2268     else
2269       str << "there is no library called " << lib << " in the library list" << std::endl;
2270     return false;
2271   }
2272   return true;
2273 }
2274 
2275 ////////////////////////////////////////////////////////////////////////////////
2276 // diagnostic print routines
2277 
print(std::ostream & str) const2278 bool stlplus::library_manager::print(std::ostream& str) const
2279 {
2280   for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)
2281     l->print(str);
2282   return !str.good();
2283 }
2284 
print_long(std::ostream & str) const2285 bool stlplus::library_manager::print_long(std::ostream& str) const
2286 {
2287   for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)
2288     l->print_long(str);
2289   return !str.good();
2290 }
2291 
2292 // find a library by name
2293 
local_find(const std::string & name)2294 std::list<stlplus::lm_library>::iterator stlplus::library_manager::local_find(const std::string& name)
2295 {
2296   for (std::list<stlplus::lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)
2297   {
2298     if (m_library_case)
2299     {
2300       if (i->name() == name) return i;
2301     }
2302     else
2303     {
2304       if (lowercase(i->name()) == lowercase(name)) return i;
2305     }
2306   }
2307   return m_libraries.end();
2308 }
2309 
local_find(const std::string & name) const2310 std::list<stlplus::lm_library>::const_iterator stlplus::library_manager::local_find(const std::string& name) const
2311 {
2312   for (std::list<stlplus::lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)
2313   {
2314     if (m_library_case)
2315     {
2316       if (i->name() == name) return i;
2317     }
2318     else
2319     {
2320       if (lowercase(i->name()) == lowercase(name)) return i;
2321     }
2322   }
2323   return m_libraries.end();
2324 }
2325 
operator <<(std::ostream & str,const stlplus::library_manager & manager)2326 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::library_manager& manager)
2327 {
2328   manager.print(str);
2329   return str;
2330 }
2331 
2332 ////////////////////////////////////////////////////////////////////////////////
2333