subsystems/library_manager.hpp
1: #ifndef STLPLUS_LIBRARY_MANAGER
2: #define STLPLUS_LIBRARY_MANAGER
3: ////////////////////////////////////////////////////////////////////////////////
4:
5: // Author: Andy Rushton
6: // Copyright: (c) Andy Rushton, 2007
7: // License: BSD License, see ../docs/license.html
8:
9: // Generalised library manager.
10:
11: // Manages library units in a set of library directories. A unit is both a file
12: // on-disk and a data-structure in memory. To use the library manager, you need
13: // to:
14:
15: // - design a type based on lm_unit with serialising functions read/write
16: // - decide on a file extension for the type
17: // - decide on a description of the type
18: // - write a create callback for this type
19: // - register the file extension, description and callback with the library manager
20:
21: ////////////////////////////////////////////////////////////////////////////////
22: #include "subsystems_fixes.hpp"
23: #include "ini_manager.hpp"
24: #include "smart_ptr.hpp"
25: #include <iostream>
26: #include <string>
27: #include <vector>
28: #include <list>
29: #include <map>
30: #include <time.h>
31:
32: namespace stlplus
33: {
34:
35: ////////////////////////////////////////////////////////////////////////////////
36: // Internals
37: ////////////////////////////////////////////////////////////////////////////////
38:
39: class lm_library;
40: class library_manager;
41:
42: ////////////////////////////////////////////////////////////////////////////////
43: // unit names
44: ////////////////////////////////////////////////////////////////////////////////
45:
46: class lm_unit_name
47: {
48: public:
49: lm_unit_name(const std::string& name = std::string(), const std::string& type = std::string());
50: ~lm_unit_name(void);
51:
52: const std::string& name(void) const;
53: void set_name(const std::string& name);
54: void lowercase(void);
55:
56: const std::string& type(void) const;
57: void set_type(const std::string& type);
58:
59: bool write(std::ostream& context) const;
60: bool read(std::istream& context);
61:
62: std::string to_string(void) const;
63: bool print(std::ostream&) const;
64:
65: private:
66: std::string m_name;
67: std::string m_type;
68: };
69:
70: std::ostream& operator << (std::ostream&, const lm_unit_name&);
71: bool operator == (const lm_unit_name& l, const lm_unit_name& r);
72: bool operator < (const lm_unit_name& l, const lm_unit_name& r);
73:
74: ////////////////////////////////////////////////////////////////////////////////
75: // dependencies
76: ////////////////////////////////////////////////////////////////////////////////
77:
78: // dependencies on external files
79:
80: class lm_file_dependency
81: {
82: public:
83: lm_file_dependency(void);
84: lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line = 0, unsigned column = 0);
85: ~lm_file_dependency(void);
86:
87: // a path can be retrieved as either a relative path to the library or as a
88: // full path by providing the library path as an argument
89: const std::string& path(void) const;
90: std::string path_full(const std::string& library_path) const;
91: void set_path(const std::string& library_path, const std::string& path);
92:
93: unsigned line(void) const;
94: void set_line(unsigned line = 0);
95:
96: unsigned column(void) const;
97: void set_column(unsigned column = 0);
98:
99: bool write(std::ostream& context) const;
100: bool read(std::istream& context);
101:
102: bool print(std::ostream&) const;
103:
104: private:
105: std::string m_path; // file dependencies are stored as paths relative to the containing library
106: unsigned m_line; // line - starts at 1, 0 means no line/column information
107: unsigned m_column; // column - starts at 0
108: };
109:
110: std::ostream& operator <<(std::ostream&, const lm_file_dependency&);
111:
112: // dependencies on other units
113:
114: class lm_unit_dependency
115: {
116: public:
117: lm_unit_dependency(void);
118: lm_unit_dependency(const std::string& library, const lm_unit_name& name);
119: ~lm_unit_dependency(void);
120:
121: const std::string& library(void) const;
122: void set_library(const std::string& library);
123:
124: const lm_unit_name& unit_name(void) const;
125: void set_unit_name(const lm_unit_name& unit_name);
126:
127: const std::string& name(void) const;
128: void set_name(const std::string& name);
129:
130: const std::string& type(void) const;
131: void set_type(const std::string& type);
132:
133: bool write(std::ostream& context) const;
134: bool read(std::istream& context);
135:
136: bool print(std::ostream&) const;
137:
138: private:
139: std::string m_library;
140: lm_unit_name m_name;
141: };
142:
143: std::ostream& operator<<(std::ostream&, const lm_unit_dependency&);
144:
145: // the set of all dependencies
146:
147: class lm_dependencies
148: {
149: public:
150: lm_dependencies(void);
151: lm_dependencies(const lm_dependencies&);
152: lm_dependencies& operator=(const lm_dependencies&);
153: ~lm_dependencies(void);
154:
155: // source file dependency
156: void set_source_file(const lm_file_dependency&);
157: bool source_file_present(void) const;
158: const lm_file_dependency& source_file(void) const;
159:
160: // other file dependencies
161: unsigned file_add(const lm_file_dependency& dependency);
162: unsigned file_size(void) const;
163: const lm_file_dependency& file_dependency(unsigned) const;
164: void file_erase(unsigned);
165:
166: // unit dependencies
167: unsigned unit_add(const lm_unit_dependency& dependency);
168: unsigned unit_size(void) const;
169: const lm_unit_dependency& unit_dependency(unsigned) const;
170: void unit_erase(unsigned);
171:
172: void clear(void);
173: bool empty(void) const;
174:
175: bool write(std::ostream& context) const;
176: bool read(std::istream& context);
177:
178: bool print(std::ostream&) const;
179:
180: private:
181: lm_file_dependency* m_source; // source file dependency (optional)
182: std::vector<lm_file_dependency> m_files; // other file dependencies
183: std::vector<lm_unit_dependency> m_units; // unit dependencies
184: };
185:
186: std::ostream& operator << (std::ostream&, const lm_dependencies&);
187:
188: ////////////////////////////////////////////////////////////////////////////////
189: // library unit superclass
190: // user's units must be derivatives of lm_unit and overload all the virtuals
191:
192: class lm_unit
193: {
194: friend class lm_library;
195: public:
196: ////////////////////////////////////////
197: // constructor/destructor
198:
199: lm_unit(const lm_unit_name& name, lm_library* library);
200: virtual ~lm_unit(void);
201:
202: ////////////////////////////////////////
203: // Header data
204:
205: // unit name
206: const lm_unit_name& unit_name(void) const;
207: const std::string& name(void) const;
208: const std::string& type(void) const;
209:
210: // dependencies
211: // all file dependencies are converted for internal use to a path relative to the library
212: // they can be retrieved either in this form or as a full path
213:
214: // source file dependency
215: void set_source_file(const lm_file_dependency&);
216: bool source_file_present(void) const;
217: const lm_file_dependency& source_file(void) const;
218:
219: // other file dependencies
220: unsigned file_add(const lm_file_dependency& dependency);
221: unsigned file_size(void) const;
222: const lm_file_dependency& file_dependency(unsigned) const;
223: void file_erase(unsigned);
224:
225: // unit dependencies
226: unsigned unit_add(const lm_unit_dependency& dependency);
227: unsigned unit_size(void) const;
228: const lm_unit_dependency& unit_dependency(unsigned) const;
229: void unit_erase(unsigned);
230:
231: const lm_dependencies& dependencies(void) const;
232: void set_dependencies(const lm_dependencies&);
233: void clear_dependencies(void);
234: bool empty_dependencies(void) const;
235:
236: // dependency checking
237:
238: bool out_of_date(void) const;
239: bool up_to_date(void) const;
240: lm_dependencies out_of_date_reason(void) const;
241:
242: // supplementary data
243:
244: const std::string& supplementary_data(void) const;
245: void set_supplementary_data(const std::string& data);
246:
247: ////////////////////////////////////////
248: // unit data management
249:
250: bool load(void);
251: bool save(void);
252: bool loaded(void) const;
253: void mark(void);
254:
255: // file modified time - only changes after a save
256:
257: time_t modified(void) const;
258:
259: ////////////////////////////////////////
260: // containing library manager details
261:
262: // get the owning library
263: const lm_library* library(void) const;
264: lm_library* library(void);
265:
266: // owning library name and path
267: const std::string& library_name(void) const;
268: const std::string& library_path(void) const;
269:
270: ////////////////////////////////////////
271: // error handling - these apply to the last read/write operation
272:
273: bool error(void) const;
274:
275: ////////////////////////////////////////
276: // functions that customise subclasses of this superclass
277: // You MUST provide at least:
278: // - read - either read operation can be overloaded
279: // - write - either write operation can be overloaded
280: // - clone
281:
282: // read(filename) is the one actually called to read your data
283: // the default read(filename) simply calls read(istream) to actually read the file
284: // the default read(istream) does nothing but fail by returning false so you must overload one or other
285:
286: // you can just overload read(istream) if you want to use IOstream, or you
287: // can overload read(filename) to use any I/O system
288:
289: virtual bool read(const std::string& filename, void* type_data);
290: virtual bool read(std::istream& file, void* type_data);
291:
292: // as above, but for writing the data type
293:
294: // write(filename) is the one actually called to write your data
295: // the default write(filename) simply calls write(ostream) to actually write the file
296: // the default write(ostream) does nothing but fail by returning false so you must overload one or other
297:
298: // you can just overload write(ostream) if you want to use IOstream, or you
299: // can overload write(filename) to use any I/O system
300:
301: virtual bool write(const std::string& filename, void* type_data);
302: virtual bool write(std::ostream& file, void* type_data);
303:
304: // purge clears any memory associated with the unit - makes the unit unloaded
305: // the default does nothing
306: virtual bool purge(void);
307:
308: // the clone function creates a new-ed copy of the subclass
309: virtual lm_unit* clone(void) const;
310:
311: // the default print routines print header-only information
312: // you can overload these to provide a debug printout of the data structure
313: virtual bool print(std::ostream&) const;
314: virtual bool print_long(std::ostream&) const;
315:
316: protected:
317: // header file management
318: std::string filename(void) const;
319: std::string header_filename(void) const;
320: bool write_header(void);
321: bool read_header(void);
322:
323: private:
324: // header fields
325: lm_unit_name m_name; // name
326: lm_dependencies m_dependencies; // file and unit dependencies
327: std::string m_supplement; // supplementary data
328: bool m_header_modified; // header modified
329:
330: // internal fields
331: bool m_loaded; // loaded flag
332: bool m_marked; // mark - determines whether the unit needs saving
333:
334: // library manager fields
335: lm_library* m_library; // parent library
336:
337: // error handling fields
338: bool m_error; // error flag if load or save fails - from IOstream
339: };
340:
341: // Iostream print calls the short print method
342: std::ostream& operator << (std::ostream& str, const lm_unit& u);
343:
344: ////////////////////////////////////////////////////////////////////////////////
345: // other types used in the library manager
346: ////////////////////////////////////////////////////////////////////////////////
347:
348: // user types
349:
350: typedef smart_ptr_nocopy<lm_unit> lm_unit_ptr;
351: typedef lm_unit* (*lm_create_callback)(const lm_unit_name& unit_name, lm_library* parent_library, void* type_data);
352:
353: // internal types used in the library manager but made global because they are shared
354:
355: struct lm_callback_entry
356: {
357: lm_create_callback m_callback;
358: std::string m_description;
359: void* m_type_data;
360:
361: lm_callback_entry(lm_create_callback callback = 0, const std::string& description = std::string(), void* type_data = 0) :
362: m_callback(callback), m_description(description), m_type_data(type_data) {}
363: };
364:
365: ////////////////////////////////////////////////////////////////////////////////
366: // Library
367: // Must be contained in a library_manager
368: // Manages objects of class lm_unit and its subclasses
369: ////////////////////////////////////////////////////////////////////////////////
370:
371: class lm_library
372: {
373: public:
374: friend class library_manager;
375: friend class lm_unit;
376:
377: //////////////////////////////////////////////////////////////////////////////
378: // constructors/destructor - lm_library should only ever be constructed by library_manager
379:
380: lm_library(library_manager* manager);
381: lm_library(const lm_library&);
382: lm_library& operator = (const lm_library&);
383: ~lm_library(void);
384:
385: public:
386:
387: const library_manager* manager(void) const;
388: library_manager* manager(void);
389:
390: //////////////////////////////////////////////////////////////////////////////
391: // initialisers
392:
393: bool create(const std::string& name, const std::string& path, bool writable);
394: bool open(const std::string& path);
395:
396: //////////////////////////////////////////////////////////////////////////////
397: // management of types
398:
399: bool load_type(const std::string& type);
400: bool load_types(void);
401: bool remove_type(const std::string& type);
402:
403: //////////////////////////////////////////////////////////////////////////////
404: // whole library operations
405:
406: bool load(void);
407: bool save(void);
408: bool purge(void);
409: bool close(void);
410: bool erase(void);
411:
412: const std::string& name(void) const;
413: const std::string& path(void) const;
414:
415: //////////////////////////////////////////////////////////////////////////////
416: // managing read/write status
417:
418: bool set_read_write(bool writable);
419: bool set_writable(void);
420: bool set_read_only(void);
421: bool writable(void) const;
422: bool read_only(void) const;
423: bool os_writable(void) const;
424: bool os_read_only(void) const;
425: bool lm_writable(void) const;
426: bool lm_read_only(void) const;
427:
428: //////////////////////////////////////////////////////////////////////////////
429: // unit management
430:
431: bool exists(const lm_unit_name& name) const;
432: lm_unit_ptr create(const lm_unit_name&);
433: bool loaded(const lm_unit_name& name) const;
434: bool load(const lm_unit_name& unit);
435: bool purge(const lm_unit_name& unit);
436: bool save(const lm_unit_name& unit);
437: bool erase(const lm_unit_name& name);
438: bool mark(const lm_unit_name& name);
439: time_t modified(const lm_unit_name& name) const;
440:
441: bool erase_by_source(const std::string& source_file);
442:
443: const lm_unit_ptr find(const lm_unit_name& name) const;
444: lm_unit_ptr find(const lm_unit_name& name);
445:
446: std::vector<lm_unit_name> names(void) const;
447: std::vector<std::string> names(const std::string& type) const;
448: std::vector<lm_unit_ptr> handles(void) const;
449: std::vector<lm_unit_ptr> handles(const std::string& type) const;
450:
451: //////////////////////////////////////////////////////////////////////////////
452: // dependency checking
453:
454: bool out_of_date(const lm_unit_name& name) const;
455: bool up_to_date(const lm_unit_name& name) const;
456: lm_dependencies out_of_date_reason(const lm_unit_name& name) const;
457:
458: std::pair<bool,unsigned> tidy(void);
459:
460: //////////////////////////////////////////////////////////////////////////////
461: // do-everything print function
462:
463: bool pretty_print(std::ostream& str,
464: bool print_units = false, // print the unit names not just the library names
465: const std::string& type = std::string()) const; // print just this type ("" means all)
466:
467: ////////////////////////////////////////////////////////////////////////////////
468: // diagnostic print routines
469:
470: bool print(std::ostream& str) const;
471: bool print_long(std::ostream& str) const;
472:
473: private:
474:
475: std::map<lm_unit_name,lm_unit_ptr>::iterator local_find(const lm_unit_name& name);
476: std::map<lm_unit_name,lm_unit_ptr>::const_iterator local_find(const lm_unit_name& name) const;
477:
478: std::string m_name; // name
479: std::string m_path; // path
480: bool m_writable; // writable
481: std::map<lm_unit_name,lm_unit_ptr> m_units; // units
482: library_manager* m_manager; // parent library manager
483: };
484:
485: std::ostream& operator << (std::ostream& str, const lm_library& lib);
486:
487: ////////////////////////////////////////////////////////////////////////////////
488: // Library Manager
489: ////////////////////////////////////////////////////////////////////////////////
490:
491: class library_manager
492: {
493: public:
494: friend class lm_library;
495: friend class lm_unit;
496:
497: ////////////////////////////////////////////////////////////////////////////////
498: // static functions allow you to test whether a directory is a library before opening it
499: // you can also find the library's name without opening it
500:
501: static bool is_library(const std::string& path, const std::string& owner);
502: static std::string library_name(const std::string& path, const std::string& owner);
503:
504: // non-static forms test for libraries with the same owner as the library manager
505:
506: bool is_library(const std::string& path);
507: std::string library_name(const std::string& path);
508:
509: //////////////////////////////////////////////////////////////////////////////
510: // tructors
511:
512: explicit library_manager(const std::string& owner, bool library_case = false, bool unit_case = false);
513: ~library_manager(void);
514:
515: //////////////////////////////////////////////////////////////////////////////
516: // case sensitivity
517:
518: bool library_case(void) const;
519: void set_library_case(bool library_case);
520:
521: bool unit_case(void) const;
522: void set_unit_case(bool library_case);
523:
524: //////////////////////////////////////////////////////////////////////////////
525: // type handling
526: // only units of types added in this way will be recognised
527:
528: bool add_type(const std::string& type,
529: const std::string& description,
530: lm_create_callback fn = 0,
531: void* type_data = 0);
532: bool remove_type(const std::string& type);
533: std::vector<std::string> types(void) const;
534:
535: std::string description(const std::string& type) const;
536: lm_create_callback callback(const std::string& type) const;
537: void* type_data(const std::string& type) const;
538:
539: //////////////////////////////////////////////////////////////////////////////
540: // Library mappings
541: // The library manager implements two different styles of library mappings
542: // - mapping file
543: // - ini file
544: // mapping file handling uses a simple text file to store the mappings in an internally-defined format
545: // ini file handling stores library mappings using the ini_manager component
546: // These modes are switched on by simply specifying a mapping file or an ini file to hold the mappings
547:
548: // mapping file methods
549:
550: // set but do not load - use this when you want to create a new mapping file
551: void set_mapping_file(const std::string& mapping_file);
552: // set and load - use this with an existing mapping file
553: bool load_mappings (const std::string& mapping_file);
554: // return the mapping file string
555: std::string mapping_file();
556:
557: // ini file methods - the ini manager must be pre-loaded with the list of ini files to manage
558:
559: // set and load - this will create the relevant sections in the local ini file if not present already
560: bool set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_section);
561: ini_manager* get_ini_manager(void) const;
562: