library_manager.hpp
1: #ifndef LIBRARY_MANAGER_HPP
2: #define LIBRARY_MANAGER_HPP
3: /*------------------------------------------------------------------------------
4:
5: Author: Andy Rushton
6: Copyright: (c) Andy Rushton, 2004
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 "os_fixes.hpp"
23: #include "smart_ptr.hpp"
24: #include "textio.hpp"
25: #include "persistent.hpp"
26: #include "ini_manager.hpp"
27: #include <string>
28: #include <vector>
29: #include <list>
30: #include <map>
31: #include <time.h>
32:
33: ////////////////////////////////////////////////////////////////////////////////
34: // Internals
35: ////////////////////////////////////////////////////////////////////////////////
36:
37: class lm_library;
38: class library_manager;
39:
40: ////////////////////////////////////////////////////////////////////////////////
41: // unit names
42: ////////////////////////////////////////////////////////////////////////////////
43:
44: class lm_unit_name
45: {
46: public:
47: lm_unit_name(const std::string& name = std::string(), const std::string& type = std::string());
48: ~lm_unit_name(void);
49:
50: const std::string& name(void) const;
51: void set_name(const std::string& name);
52: void lowercase(void);
53:
54: const std::string& type(void) const;
55: void set_type(const std::string& type);
56:
57: friend void dump(dump_context& context, const lm_unit_name& name) throw(persistent_dump_failed);
58: friend void restore(restore_context& context, lm_unit_name& name) throw(persistent_restore_failed);
59:
60: friend std::string to_string(const lm_unit_name& name);
61: friend otext& print(otext&, const lm_unit_name&);
62: friend otext& operator << (otext&, const lm_unit_name&);
63:
64: friend bool operator == (const lm_unit_name& l, const lm_unit_name& r);
65: friend bool operator < (const lm_unit_name& l, const lm_unit_name& r);
66:
67: private:
68: std::string m_name;
69: std::string m_type;
70: };
71:
72: // redefine friends for gcc v4.1
73: void dump(dump_context& context, const lm_unit_name& name) throw(persistent_dump_failed);
74: void restore(restore_context& context, lm_unit_name& name) throw(persistent_restore_failed);
75: std::string to_string(const lm_unit_name& name);
76: otext& print(otext&, const lm_unit_name&);
77: otext& operator << (otext&, const lm_unit_name&);
78: bool operator == (const lm_unit_name& l, const lm_unit_name& r);
79: bool operator < (const lm_unit_name& l, const lm_unit_name& r);
80:
81: ////////////////////////////////////////////////////////////////////////////////
82: // dependencies
83: ////////////////////////////////////////////////////////////////////////////////
84:
85: // dependencies on external files
86:
87: class lm_file_dependency
88: {
89: public:
90: lm_file_dependency(void);
91: lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line = 0, unsigned column = 0);
92: ~lm_file_dependency(void);
93:
94: // a path can be retrieved as either a relative path to the library or as a full path by providing the library path as an argument
95: const std::string& path(void) const;
96: std::string path_full(const std::string& library_path) const;
97: void set_path(const std::string& library_path, const std::string& path);
98:
99: unsigned line(void) const;
100: void set_line(unsigned line = 0);
101:
102: unsigned column(void) const;
103: void set_column(unsigned column = 0);
104:
105: friend void dump(dump_context& context, const lm_file_dependency&) throw(persistent_dump_failed);
106: friend void restore(restore_context& context, lm_file_dependency&) throw(persistent_restore_failed);
107: friend otext& print(otext&, const lm_file_dependency&);
108: friend otext& print(otext&, const lm_file_dependency&, unsigned indent);
109: friend otext& operator <<(otext&, const lm_file_dependency&);
110:
111: private:
112: std::string m_path; // file dependencies are stored as paths relative to the containing library
113: unsigned m_line; // line - starts at 1, 0 means no line/column information
114: unsigned m_column; // column - starts at 0
115: };
116:
117: // redefine friends for gcc v4.1
118: void dump(dump_context& context, const lm_file_dependency&) throw(persistent_dump_failed);
119: void restore(restore_context& context, lm_file_dependency&) throw(persistent_restore_failed);
120: otext& print(otext&, const lm_file_dependency&);
121: otext& print(otext&, const lm_file_dependency&, unsigned indent);
122: otext& operator <<(otext&, const lm_file_dependency&);
123:
124: // dependencies on other units
125:
126: class lm_unit_dependency
127: {
128: public:
129: lm_unit_dependency(void);
130: lm_unit_dependency(const std::string& library, const lm_unit_name& name);
131: ~lm_unit_dependency(void);
132:
133: const std::string& library(void) const;
134: void set_library(const std::string& library);
135:
136: const lm_unit_name& unit_name(void) const;
137: void set_unit_name(const lm_unit_name& unit_name);
138:
139: const std::string& name(void) const;
140: void set_name(const std::string& name);
141:
142: const std::string& type(void) const;
143: void set_type(const std::string& type);
144:
145: friend void dump(dump_context& context, const lm_unit_dependency&) throw(persistent_dump_failed);
146: friend void restore(restore_context& context, lm_unit_dependency&) throw(persistent_restore_failed);
147: friend otext& print(otext&, const lm_unit_dependency&);
148: friend otext& print(otext&, const lm_unit_dependency&, unsigned indent);
149: friend otext& operator<<(otext&, const lm_unit_dependency&);
150:
151: private:
152: std::string m_library;
153: lm_unit_name m_name;
154: };
155:
156: // redefine friends for gcc v4.1
157: void dump(dump_context& context, const lm_unit_dependency&) throw(persistent_dump_failed);
158: void restore(restore_context& context, lm_unit_dependency&) throw(persistent_restore_failed);
159: otext& print(otext&, const lm_unit_dependency&);
160: otext& print(otext&, const lm_unit_dependency&, unsigned indent);
161: otext& operator<<(otext&, const lm_unit_dependency&);
162:
163: // the set of all dependencies
164:
165: class lm_dependencies
166: {
167: public:
168: lm_dependencies(void);
169: ~lm_dependencies(void);
170:
171: // source file dependency
172: void set_source_file(const lm_file_dependency&);
173: bool source_file_present(void) const;
174: const lm_file_dependency& source_file(void) const;
175:
176: // other file dependencies
177: unsigned file_add(const lm_file_dependency& dependency);
178: unsigned file_size(void) const;
179: const lm_file_dependency& file_dependency(unsigned) const;
180: void file_erase(unsigned);
181:
182: // unit dependencies
183: unsigned unit_add(const lm_unit_dependency& dependency);
184: unsigned unit_size(void) const;
185: const lm_unit_dependency& unit_dependency(unsigned) const;
186: void unit_erase(unsigned);
187:
188: void clear(void);
189: bool empty(void) const;
190:
191: // persistence
192: friend void dump(dump_context& context, const lm_dependencies&) throw(persistent_dump_failed);
193: friend void restore(restore_context& context, lm_dependencies&) throw(persistent_restore_failed);
194:
195: // diagnostic print routines
196: friend otext& print(otext&, const lm_dependencies&, unsigned indent = 0);
197: friend otext& operator << (otext&, const lm_dependencies&);
198:
199: private:
200: smart_ptr<lm_file_dependency> m_source; // source file dependency (optional)
201: std::vector<lm_file_dependency> m_files; // other file dependencies
202: std::vector<lm_unit_dependency> m_units; // unit dependencies
203: };
204:
205: // redefine friends for gcc v4.1
206: void dump(dump_context& context, const lm_dependencies&) throw(persistent_dump_failed);
207: void restore(restore_context& context, lm_dependencies&) throw(persistent_restore_failed);
208: otext& print(otext&, const lm_dependencies&, unsigned indent);
209: otext& operator << (otext&, const lm_dependencies&);
210:
211: ////////////////////////////////////////////////////////////////////////////////
212: // library unit superclass
213: // All units must be contained in an lm_library object
214:
215: class lm_unit
216: {
217: friend class lm_library;
218: public:
219: ////////////////////////////////////////
220: // constructor/destructor
221:
222: lm_unit(const lm_unit_name& name, lm_library* library);
223: virtual ~lm_unit(void);
224:
225: ////////////////////////////////////////
226: // Header data
227:
228: // unit name
229: const lm_unit_name& unit_name(void) const;
230: const std::string& name(void) const;
231: const std::string& type(void) const;
232:
233: // dependencies
234: // all file dependencies are converted for internal use to a path relative to the library
235: // they can be retrieved either in this form or as a full path
236:
237: // source file dependency
238: void set_source_file(const lm_file_dependency&);
239: bool source_file_present(void) const;
240: const lm_file_dependency& source_file(void) const;
241:
242: // other file dependencies
243: unsigned file_add(const lm_file_dependency& dependency);
244: unsigned file_size(void) const;
245: const lm_file_dependency& file_dependency(unsigned) const;
246: void file_erase(unsigned);
247:
248: // unit dependencies
249: unsigned unit_add(const lm_unit_dependency& dependency);
250: unsigned unit_size(void) const;
251: const lm_unit_dependency& unit_dependency(unsigned) const;
252: void unit_erase(unsigned);
253:
254: const lm_dependencies& dependencies(void) const;
255: void set_dependencies(const lm_dependencies&);
256: void clear_dependencies(void);
257: bool empty_dependencies(void) const;
258:
259: // dependency checking
260:
261: bool out_of_date(void) const;
262: bool up_to_date(void) const;
263: lm_dependencies out_of_date_reason(void) const;
264:
265: // supplementary data
266:
267: const std::string& supplementary_data(void) const;
268: void set_supplementary_data(const std::string& data);
269:
270: ////////////////////////////////////////
271: // unit data management
272:
273: bool load(void);
274: bool save(void);
275: bool loaded(void) const;
276: void mark(void);
277:
278: // file modified time - only changes after a save
279:
280: time_t modified(void) const;
281:
282: ////////////////////////////////////////
283: // containing library manager details
284:
285: // get the owning library
286: const lm_library* library(void) const;
287: lm_library* library(void);
288:
289: // owning library name and path
290: const std::string& library_name(void) const;
291: const std::string& library_path(void) const;
292:
293: ////////////////////////////////////////
294: // error handling - these apply to the last read/write operation
295:
296: bool error(void) const;
297: int error_number(void) const;
298: std::string error_string(void) const;
299:
300: ////////////////////////////////////////
301: // print diagnostics
302: // these call the print methods which may be overloaded for each subclass
303:
304: friend otext& print(otext& str, const lm_unit& u);
305: friend otext& print_long(otext& str, const lm_unit& u, unsigned indent);
306: friend otext& operator << (otext& str, const lm_unit& u);
307:
308: ////////////////////////////////////////
309: // functions that customise subclasses of this superclass
310: // You MUST provide at least:
311: // - read - either read operation can be overloaded
312: // - write - either write operation can be overloaded
313: // - clone
314:
315: // the default read(filename) calls read(itext) to actually read the file
316: // you can just overload read(itext) if you want to use TextIO, or you can overload read(filename) to use any I/O system
317: // the default read(itext) does nothing but fail by returning false so you must overload one or other
318: virtual bool read(const std::string& filename, void* type_data);
319: virtual bool read(itext& file, void* type_data);
320:
321: // as above, write(filename) calls write(otext) to actually write the file
322: // you can just overload write(otext) if you want to use TextIO, or you can overload write(filename) to use any I/O system
323: // the default write(otext) does nothing but fail by returning false so you must overload one or other
324: virtual bool write(const std::string& filename, void* type_data);
325: virtual bool write(otext& file, void* type_data);
326:
327: // purge clears any memory associated with the unit - makes the unit unloaded
328: // the default does nothing
329: virtual bool purge(void);
330:
331: // the clone function creates a copy of the subclass - see the docs on smart_ptr for an explanation
332: virtual lm_unit* clone(void) const;
333:
334: // the default print routines print header-only information
335: // you can overload these to provide a debug dump of the data structure
336: virtual otext& print(otext&) const;
337: virtual otext& print_long(otext&, unsigned indent = 0) const;
338:
339: protected:
340: // header file management
341: std::string filename(void) const;
342: std::string header_filename(void) const;
343: bool dump_header(void);
344: bool restore_header(void);
345:
346: private:
347: // header fields
348: lm_unit_name m_name; // name
349: lm_dependencies m_dependencies; // file and unit dependencies
350: std::string m_supplement; // supplementary data
351: bool m_header_modified; // header modified
352:
353: // internal fields
354: bool m_loaded; // loaded flag
355: bool m_marked; // mark - determines whether the unit needs saving
356:
357: // library manager fields
358: lm_library* m_library; // parent library
359:
360: // error handling fields
361: int m_error; // error code if load or save fails
362: std::string m_error_string; // string part of above error status
363: };
364:
365: // redefine friends for gcc v4.1
366: otext& print(otext& str, const lm_unit& u);
367: otext& print_long(otext& str, const lm_unit& u, unsigned indent);
368: otext& operator << (otext& str, const lm_unit& u);
369:
370: ////////////////////////////////////////////////////////////////////////////////
371: // other types used in the library manager
372: ////////////////////////////////////////////////////////////////////////////////
373:
374: // user types
375:
376: typedef smart_ptr_nocopy<lm_unit> lm_unit_ptr;
377: typedef lm_unit* (*lm_create_callback)(const lm_unit_name& unit_name, lm_library* parent_library, void* type_data);
378:
379: // internal types used in the library manager but made global because they are shared
380:
381: struct lm_callback_entry
382: {
383: lm_create_callback m_callback;
384: std::string m_description;
385: void* m_type_data;
386:
387: lm_callback_entry(lm_create_callback callback = 0, const std::string& description = std::string(), void* type_data = 0) :
388: m_callback(callback), m_description(description), m_type_data(type_data) {}
389: };
390:
391: typedef std::map<std::string,lm_callback_entry> lm_callback_map;
392:
393: typedef std::pair<bool,unsigned> lm_tidy_result;
394:
395: ////////////////////////////////////////////////////////////////////////////////
396: // Library
397: // Must be contained in a library_manager
398: // Manages objects of class lm_unit and its subclasses
399: ////////////////////////////////////////////////////////////////////////////////
400:
401: class lm_library
402: {
403: public:
404:
405: friend class library_manager;
406: friend class lm_unit;
407: typedef std::map<lm_unit_name,lm_unit_ptr> unit_map;
408:
409: //////////////////////////////////////////////////////////////////////////////
410: // library management
411:
412: lm_library(library_manager* manager);
413: ~lm_library(void);
414: lm_library(const lm_library&);
415: lm_library& operator = (const lm_library&);
416:
417: const library_manager* manager(void) const;
418: library_manager* manager(void);
419:
420: //////////////////////////////////////////////////////////////////////////////
421: // initialisers
422:
423: bool create(const std::string& name, const std::string& path, bool writable);
424: bool open(const std::string& path);
425:
426: //////////////////////////////////////////////////////////////////////////////
427: // management of types
428:
429: bool load_type(const std::string& type);
430: bool load_types(void);
431: bool remove_type(const std::string& type);
432:
433: //////////////////////////////////////////////////////////////////////////////
434: // whole library operations
435:
436: bool load(void);
437: bool save(void);
438: bool purge(void);
439: bool close(void);
440: bool erase(void);
441:
442: const std::string& name(void) const;
443: const std::string& path(void) const;
444:
445: //////////////////////////////////////////////////////////////////////////////
446: // managing read/write status
447:
448: bool set_read_write(bool writable);
449: bool set_writable(void);
450: bool set_read_only(void);
451: bool writable(void) const;
452: bool read_only(void) const;
453: bool os_writable(void) const;
454: bool os_read_only(void) const;
455: bool lm_writable(void) const;
456: bool lm_read_only(void) const;
457:
458: //////////////////////////////////////////////////////////////////////////////
459: // unit management
460:
461: private:
462: unit_map::iterator local_find(const lm_unit_name& name);
463: unit_map::const_iterator local_find(const lm_unit_name& name) const;
464:
465: public:
466: bool exists(const lm_unit_name& name) const;
467: lm_unit_ptr create(const lm_unit_name&);
468: bool loaded(const lm_unit_name& name) const;
469: bool load(const lm_unit_name& unit);
470: bool purge(const lm_unit_name& unit);
471: bool save(const lm_unit_name& unit);
472: bool erase(const lm_unit_name& name);
473: bool mark(const lm_unit_name& name);
474: time_t modified(const lm_unit_name& name) const;
475:
476: bool erase_by_source(const std::string& source_file);
477:
478: const lm_unit_ptr find(const lm_unit_name& name) const;
479: lm_unit_ptr find(const lm_unit_name& name);
480:
481: std::vector<lm_unit_name> names(void) const;
482: std::vector<std::string> names(const std::string& type) const;
483: std::vector<lm_unit_ptr> handles(void) const;
484: std::vector<lm_unit_ptr> handles(const std::string& type) const;
485:
486: //////////////////////////////////////////////////////////////////////////////
487: // dependency checking
488:
489: bool out_of_date(const lm_unit_name& name) const;
490: bool up_to_date(const lm_unit_name& name) const;
491: lm_dependencies out_of_date_reason(const lm_unit_name& name) const;
492:
493: lm_tidy_result tidy(void);
494:
495: //////////////////////////////////////////////////////////////////////////////
496: // I/O
497: // do-everything print routine!
498:
499: bool pretty_print(otext& str, unsigned indent, bool print_units, const std::string& type) const;
500:
501: ////////////////////////////////////////////////////////////////////////////////
502: // diagnostic print routines
503:
504: otext& print(otext& str, unsigned indent = 0)