]> Dogcows Code - chaz/yoink/blob - src/stlplus/subsystems/library_manager.cpp
archiving support for releases
[chaz/yoink] / src / stlplus / subsystems / library_manager.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2
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
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
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
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
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
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
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
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
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
189 stlplus::lm_unit_name::~lm_unit_name(void)
190 {
191 }
192
193 const std::string& stlplus::lm_unit_name::name(void) const
194 {
195 return m_name;
196 }
197
198 void stlplus::lm_unit_name::set_name(const std::string& name)
199 {
200 m_name = name;
201 }
202
203 void stlplus::lm_unit_name::lowercase(void)
204 {
205 m_name = ::lowercase(m_name);
206 }
207
208 const std::string& stlplus::lm_unit_name::type(void) const
209 {
210 return m_type;
211 }
212
213 void stlplus::lm_unit_name::set_type(const std::string& type)
214 {
215 m_type = type;
216 }
217
218 bool stlplus::lm_unit_name::write(std::ostream& context) const
219 {
220 context << m_name << " " << m_type;
221 return !context.fail();
222 }
223
224 bool stlplus::lm_unit_name::read(std::istream& context)
225 {
226 context >> m_name >> m_type;
227 return !context.fail();
228 }
229
230 std::string stlplus::lm_unit_name::to_string(void) const
231 {
232 return m_name + ":" + m_type;
233 }
234
235 bool stlplus::lm_unit_name::print(std::ostream& str) const
236 {
237 str << to_string();
238 return !str.fail();
239 }
240
241 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_name& name)
242 {
243 name.print(str);
244 return str;
245 }
246
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
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
263 stlplus::lm_file_dependency::lm_file_dependency(void) : m_line(0), m_column(0)
264 {
265 }
266
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
274 stlplus::lm_file_dependency::~lm_file_dependency(void)
275 {
276 }
277
278 const std::string& stlplus::lm_file_dependency::path(void) const
279 {
280 return m_path;
281 }
282
283 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
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
293 unsigned stlplus::lm_file_dependency::line(void) const
294 {
295 return m_line;
296 }
297
298 void stlplus::lm_file_dependency::set_line(unsigned line)
299 {
300 m_line = line;
301 }
302
303 unsigned stlplus::lm_file_dependency::column(void) const
304 {
305 return m_column;
306 }
307
308 void stlplus::lm_file_dependency::set_column(unsigned column)
309 {
310 m_column = column;
311 }
312
313 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
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
325 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
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
341 stlplus::lm_unit_dependency::lm_unit_dependency(void)
342 {
343 }
344
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
350 stlplus::lm_unit_dependency::~lm_unit_dependency(void)
351 {
352 }
353
354 const std::string& stlplus::lm_unit_dependency::library(void) const
355 {
356 return m_library;
357 }
358
359 void stlplus::lm_unit_dependency::set_library(const std::string& library)
360 {
361 m_library = library;
362 }
363
364 const stlplus::lm_unit_name& stlplus::lm_unit_dependency::unit_name(void) const
365 {
366 return m_name;
367 }
368
369 void stlplus::lm_unit_dependency::set_unit_name(const lm_unit_name& unit_name)
370 {
371 m_name = unit_name;
372 }
373
374 const std::string& stlplus::lm_unit_dependency::name(void) const
375 {
376 return m_name.name();
377 }
378
379 void stlplus::lm_unit_dependency::set_name(const std::string& name)
380 {
381 m_name.set_name(name);
382 }
383
384 const std::string& stlplus::lm_unit_dependency::type(void) const
385 {
386 return m_name.type();
387 }
388
389 void stlplus::lm_unit_dependency::set_type(const std::string& type)
390 {
391 m_name.set_type(type);
392 }
393
394 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
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
408 bool stlplus::lm_unit_dependency::print(std::ostream& str) const
409 {
410 str << "unit: " << m_library << "." << m_name;
411 return !str.fail();
412 }
413
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
422 stlplus::lm_dependencies::lm_dependencies(void) : m_source(0)
423 {
424 }
425
426 stlplus::lm_dependencies::lm_dependencies(const lm_dependencies& r) : m_source(0)
427 {
428 *this = r;
429 }
430
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
443 stlplus::lm_dependencies::~lm_dependencies(void)
444 {
445 if (m_source)
446 delete m_source;
447 }
448
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
456 bool stlplus::lm_dependencies::source_file_present(void) const
457 {
458 return (m_source != 0);
459 }
460
461 const stlplus::lm_file_dependency& stlplus::lm_dependencies::source_file(void) const
462 {
463 return *m_source;
464 }
465
466 unsigned stlplus::lm_dependencies::file_add(const lm_file_dependency& dependency)
467 {
468 m_files.push_back(dependency);
469 return m_files.size()-1;
470 }
471
472 unsigned stlplus::lm_dependencies::file_size(void) const
473 {
474 return m_files.size();
475 }
476
477 const stlplus::lm_file_dependency& stlplus::lm_dependencies::file_dependency(unsigned i) const
478 {
479 return m_files[i];
480 }
481
482 void stlplus::lm_dependencies::file_erase(unsigned i)
483 {
484 m_files.erase(m_files.begin()+i);
485 }
486
487 unsigned stlplus::lm_dependencies::unit_add(const lm_unit_dependency& dependency)
488 {
489 m_units.push_back(dependency);
490 return m_units.size()-1;
491 }
492
493 unsigned stlplus::lm_dependencies::unit_size(void) const
494 {
495 return m_units.size();
496 }
497
498 const stlplus::lm_unit_dependency& stlplus::lm_dependencies::unit_dependency(unsigned i) const
499 {
500 return m_units[i];
501 }
502
503 void stlplus::lm_dependencies::unit_erase(unsigned i)
504 {
505 m_units.erase(m_units.begin()+i);
506 }
507
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
517 bool stlplus::lm_dependencies::empty(void) const
518 {
519 return (m_source == 0) && m_files.empty() && m_units.empty();
520 }
521
522 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
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
569 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
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
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
596 stlplus::lm_unit::~lm_unit(void)
597 {
598 write_header();
599 }
600
601 ////////////////////////////////////////
602 // Header data
603
604 const stlplus::lm_unit_name& stlplus::lm_unit::unit_name(void) const
605 {
606 return m_name;
607 }
608
609 const std::string& stlplus::lm_unit::name(void) const
610 {
611 return m_name.name();
612 }
613
614 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
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
629 bool stlplus::lm_unit::source_file_present(void) const
630 {
631 return m_dependencies.source_file_present();
632 }
633
634 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
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
647 unsigned stlplus::lm_unit::file_size(void) const
648 {
649 return m_dependencies.file_size();
650 }
651
652 const stlplus::lm_file_dependency& stlplus::lm_unit::file_dependency(unsigned i) const
653 {
654 return m_dependencies.file_dependency(i);
655 }
656
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
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
671 unsigned stlplus::lm_unit::unit_size(void) const
672 {
673 return m_dependencies.unit_size();
674 }
675
676 const stlplus::lm_unit_dependency& stlplus::lm_unit::unit_dependency(unsigned i) const
677 {
678 return m_dependencies.unit_dependency(i);
679 }
680
681 void stlplus::lm_unit::unit_erase(unsigned i)
682 {
683 m_header_modified = true;
684 m_dependencies.unit_erase(i);
685 }
686
687 const stlplus::lm_dependencies& stlplus::lm_unit::dependencies(void) const
688 {
689 return m_dependencies;
690 }
691
692 void stlplus::lm_unit::set_dependencies(const lm_dependencies& dependencies)
693 {
694 m_header_modified = true;
695 m_dependencies = dependencies;
696 }
697
698 void stlplus::lm_unit::clear_dependencies(void)
699 {
700 m_header_modified = true;
701 m_dependencies.clear();
702 }
703
704 bool stlplus::lm_unit::empty_dependencies(void) const
705 {
706 return m_dependencies.empty();
707 }
708
709 // dependency checking
710
711 bool stlplus::lm_unit::out_of_date(void) const
712 {
713 return m_library->out_of_date(m_name);
714 }
715
716 bool stlplus::lm_unit::up_to_date(void) const
717 {
718 return m_library->up_to_date(m_name);
719 }
720
721 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
728 const std::string& stlplus::lm_unit::supplementary_data(void) const
729 {
730 return m_supplement;
731 }
732
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
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
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
768 bool stlplus::lm_unit::loaded(void) const
769 {
770 return m_loaded;
771 }
772
773 void stlplus::lm_unit::mark(void)
774 {
775 m_marked = true;
776 }
777
778 time_t stlplus::lm_unit::modified(void) const
779 {
780 return file_modified(filename());
781 }
782
783 ////////////////////////////////////////
784 // containing library manager details
785
786 const stlplus::lm_library* stlplus::lm_unit::library(void) const
787 {
788 return m_library;
789 }
790
791 stlplus::lm_library* stlplus::lm_unit::library(void)
792 {
793 return m_library;
794 }
795
796 const std::string& stlplus::lm_unit::library_name(void) const
797 {
798 return m_library->name();
799 }
800
801 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
808 bool stlplus::lm_unit::error(void) const
809 {
810 return m_error;
811 }
812
813 // functions that customise subclasses of this superclass
814
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
827 bool stlplus::lm_unit::read(std::istream&, void*)
828 {
829 return false;
830 }
831
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
844 bool stlplus::lm_unit::write(std::ostream&, void*)
845 {
846 return false;
847 }
848
849 bool stlplus::lm_unit::purge(void)
850 {
851 return true;
852 }
853
854 stlplus::lm_unit* stlplus::lm_unit::clone(void) const
855 {
856 return new lm_unit(*this);
857 }
858
859 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
865 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
910 std::string stlplus::lm_unit::filename(void) const
911 {
912 return stlplus::create_filespec(library_path(), m_name.name(), m_name.type());
913 }
914
915 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
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
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
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
959 stlplus::lm_library::lm_library(library_manager* manager) : m_writable(false), m_manager(manager)
960 {
961 }
962
963 stlplus::lm_library::lm_library(const lm_library& library) : m_writable(library.m_writable), m_manager(library.m_manager)
964 {
965 }
966
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
974 stlplus::lm_library::~lm_library(void)
975 {
976 close();
977 }
978
979 const stlplus::library_manager* stlplus::lm_library::manager(void) const
980 {
981 return m_manager;
982 }
983
984 stlplus::library_manager* stlplus::lm_library::manager(void)
985 {
986 return m_manager;
987 }
988
989 //////////////////////////////////////////////////////////////////////////////
990 // initialisers
991
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
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
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
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
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
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
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
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
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
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
1102 const std::string& stlplus::lm_library::name(void) const
1103 {
1104 return m_name;
1105 }
1106
1107 const std::string& stlplus::lm_library::path(void) const
1108 {
1109 return m_path;
1110 }
1111
1112 //////////////////////////////////////////////////////////////////////////////
1113 // managing read/write status
1114
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
1125 bool stlplus::lm_library::set_writable(void)
1126 {
1127 return set_read_write(true);
1128 }
1129
1130 bool stlplus::lm_library::set_read_only(void)
1131 {
1132 return set_read_write(false);
1133 }
1134
1135 bool stlplus::lm_library::writable(void) const
1136 {
1137 return os_writable() && lm_writable();
1138 }
1139
1140 bool stlplus::lm_library::read_only(void) const
1141 {
1142 return os_read_only() || lm_read_only();
1143 }
1144
1145 bool stlplus::lm_library::os_writable(void) const
1146 {
1147 return folder_writable(path());
1148 }
1149
1150 bool stlplus::lm_library::os_read_only(void) const
1151 {
1152 return !folder_writable(path());
1153 }
1154
1155 bool stlplus::lm_library::lm_writable(void) const
1156 {
1157 return m_writable;
1158 }
1159
1160 bool stlplus::lm_library::lm_read_only(void) const
1161 {
1162 return !m_writable;
1163 }
1164
1165 //////////////////////////////////////////////////////////////////////////////
1166 // unit management
1167
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
1176 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
1184 bool stlplus::lm_library::exists(const lm_unit_name& name) const
1185 {
1186 return find(name).present();
1187 }
1188
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
1208 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
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
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
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
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
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
1261 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
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
1291 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
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
1305 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
1313 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
1322 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
1330 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
1342 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
1347 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
1352 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
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
1386 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
1448 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
1456 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
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
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
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
1492 bool stlplus::library_manager::is_library(const std::string& path)
1493 {
1494 return is_library(path, m_owner);
1495 }
1496
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
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
1510 stlplus::library_manager::~library_manager(void)
1511 {
1512 close();
1513 }
1514
1515 //////////////////////////////////////////////////////////////////////////////
1516 // case sensitivity
1517
1518 bool stlplus::library_manager::library_case(void) const
1519 {
1520 return m_library_case;
1521 }
1522
1523 void stlplus::library_manager::set_library_case(bool library_case)
1524 {
1525 m_library_case = library_case;
1526 }
1527
1528 bool stlplus::library_manager::unit_case(void) const
1529 {
1530 return m_unit_case;
1531 }
1532
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
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
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
1562 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
1570 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
1577 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
1584 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
1594 void stlplus::library_manager::set_mapping_file(const std::string& mapping_file)
1595 {
1596 m_mapping_file = mapping_file;
1597 }
1598
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
1634 std::string stlplus::library_manager::mapping_file()
1635 {
1636 return m_mapping_file;
1637 }
1638
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
1694 stlplus::ini_manager* stlplus::library_manager::get_ini_manager(void) const
1695 {
1696 return m_ini_files;
1697 }
1698
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
1806 bool stlplus::library_manager::exists(const std::string& name) const
1807 {
1808 return find(name) != 0;
1809 }
1810
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
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
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
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
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
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
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
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
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
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
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
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
1934 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
1941 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
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
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
1964 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
1971 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
1978 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
1985 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
1992 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
1999 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
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
2015 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
2024 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
2034 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
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
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
2062 bool stlplus::library_manager::unsetwork(void)
2063 {
2064 m_work = "";
2065 return true;
2066 }
2067
2068 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
2074 stlplus::lm_library* stlplus::library_manager::work(void)
2075 {
2076 if (m_work.empty()) return 0;
2077 return find(m_work);
2078 }
2079
2080 std::string stlplus::library_manager::work_name(void) const
2081 {
2082 return m_work;
2083 }
2084
2085 //////////////////////////////////////////////////////////////////////////////
2086 // unit management within a library
2087
2088 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
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
2102 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
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
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
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
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
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
2144 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
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
2160 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
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
2175 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
2182 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
2189 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
2196 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
2207 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
2212 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
2218 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
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
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
2249 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
2278 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;
2283 }
2284
2285 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;
2290 }
2291
2292 // find a library by name
2293
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
2310 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
2326 std::ostream& stlplus::operator << (std::ostream& str, const stlplus::library_manager& manager)
2327 {
2328 manager.print(str);
2329 return str;
2330 }
2331
2332 ////////////////////////////////////////////////////////////////////////////////
This page took 0.137247 seconds and 4 git commands to generate.