source: cpp/frams/param/multiparamload.h @ 241

Last change on this file since 241 was 197, checked in by Maciej Komosinski, 11 years ago

GDK used by developers since 1999, distributed on the web since 2002

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 1999-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#ifndef _MULTIPARAMLOAD_H_
6#define _MULTIPARAMLOAD_H_
7
8#include <stdio.h>
9#include "param.h"
10#include <frams/virtfile/virtfile.h>
11#include <frams/util/extvalue.h>
12
13/** This is the general "framsticks-format" file parser for loading multiple objects.
14    The loader can be configured to recognize multiple object types from object headers
15    and automatically call ParamInterface::load for the matching class.
16   
17    Your code should repeatedly call MultiParamLoader::go() method and check the status after each call, until the end of file.
18    The loader pauses before and/or after each object giving you a chance to perform your application-specific actions (see MultiParamLoader::breakOn()).
19    If your application does not require any special actions, then the simple MultiParamLoader:run() can be used.
20    The word "record" (and "record type") used in this description refer to the textual form of a serialized object - this is to avoid confusion with 'live' objects passed to the loader methods. "Record type" can be the same as the class name, but it does not have to be the same. For example, the most common record type for storing the Genotype object is called "org" (think: organism) instead of "Genotype".
21
22    Typical usage scenarios:
23    1. Loading a file that contains at most one object of any given class:
24    - declare the object class(es) - MultiParamLoader::addClass()
25    - call MultiParamLoader::run()
26    - and that's all, the records from the file will be loaded into the corresponding objects
27
28    2. Loading multiple objects and adding them to a list (see loadtest.cpp for a sample code that demonstrates this scenario)
29    - declare the object class giving the empty "template" object - MultiParamLoader::addClass()
30    - set breakOn(AfterObject)
31    - call MultiParamLoader::go() in a loop
32    - the returned status will be equal to AfterObject each time an object is loaded. One can detect this condition and create the real object from our template object
33    (alternatively, one could breakOn(BeforeObject) and use MultiParamLoader::loadObjectNow(ParamInterface*) to load the incoming object into a newly created object).   
34 */
35class MultiParamLoader
36{
37VirtFILE *file;
38SListTempl<VirtFILE*> filestack;
39char ownfile;
40PtrListTempl<ExtObject*> objects;
41int status;
42SString lasterror, lastcomment, lastunknown;
43ExtObject lastobject;
44int breakcond;
45Param emptyparam;
46
47void init();
48
49int maybeBreak(int cond)
50{ status=cond; return breakcond & cond; }
51
52VirtFILE* popstack();
53void clearstack();
54
55  public:
56MultiParamLoader() {init();}
57MultiParamLoader(VirtFILE *f) {init(); load(f);}
58MultiParamLoader(const char* filename) {init(); load(filename);}
59
60~MultiParamLoader() {abort();clearObjects();}
61
62void reset();
63
64void load(); //< use previously opened file
65void load(VirtFILE *f);
66void load(const char* filename);
67
68/** Register the object class. Class names will be matched with object headers ("xxx:" in the input file).
69    Used with breakOn(BeforeObject) and/or breakOn(AfterObject).
70    Note that registered classes will only work when the record name matches the class name, otherwise breakOn(BeforeUnknown) must be used and then getClassName() to check for the expected record.
71 */
72void addObject(ParamInterface *pi) {objects+=new ExtObject(pi);}
73void removeObject(ParamInterface *pi) {removeObject(ExtObject(pi));}
74void addObject(const ExtObject &o) {objects+=new ExtObject(o);}
75void removeObject(const ExtObject &o);
76int findObject(const ExtObject &o);
77void clearObjects();
78
79/** To be used in the main loop: while(event=loader.go()) { ... }
80    loader.go() will return on specified events (@see breakOn(), noBreakOn()),
81    then you can handle the event and resume loading.
82 */
83virtual int go();
84/** same value as 'go()' */
85int getStatus() {return status;}
86int finished() {return (status==Finished);}
87
88VirtFILE *getFile() {return file;}
89
90/** Abort immediately and close the file if needed */
91void abort();
92/** @param conditions can be combined bitwise, eg. MultiParamLoader::BeforeObject |  MultiParamLoader::OnComment
93    @see BreakConfitions
94*/
95void breakOn(int conditions) {breakcond|=conditions;}
96void noBreakOn(int conditions) {breakcond&=~conditions;}
97/**
98   These constants are used as arguments in breakOn(), and as status values from go() and getStatus().
99   The user code can define some classes for automatic recognition (using addClass()); such records can be read without performing any additional actions.
100   
101   - BeforeObject: found an object with recognized classname (addClass()). Application code can choose to skip the incoming record (skipObject()), redirect the incoming data into a different object (loadObjectNow(ParamInterface*)), or do nothing for default behavior (loading into previously registered object).
102
103   - AfterObject: the object was loaded into the registered class interface (addClass()). This is to allow for additional actions after loading the object (e.g. data validation).
104
105   - BeforeUnknown: unknown (not registered) object header detected. Like in BeforeObject, the application can skipObject() or loadObjectNow().
106
107@see getClass(), GetClassName()
108 */
109enum BreakConditions { Finished=0, BeforeObject=1, AfterObject=2,
110                       BeforeUnknown=4, OnComment=8, OnError=16, Loading=32 };
111
112/** Can be used BeforeObject and AfterObject */
113ExtObject &getObject() {return lastobject;}
114/** Can be used BeforeUnknown, BeforeObject, AfterObject */
115const SString& getObjectName() {return lastunknown;}
116void setObjectName(SString n) {lastunknown=n;}
117/** Unknown object will be loaded if you set its class BeforeUnknown */
118void setObject(ParamInterface *pi) {lastobject=ExtObject(pi);}
119void setObject(const ExtObject& o) {lastobject=o;}
120/** Can be used OnComment */
121const SString& getComment() {return lastcomment;}
122/** Can be used OnError */
123const SString& getError() {return lasterror;}
124/** Can be used BeforeObject and BeforeUnknown */
125int loadObjectNow(ParamInterface *pi) {return loadObjectNow(ExtObject(pi));}
126int loadObjectNow(const ExtObject &o);
127/** Can be used BeforeObject */
128int loadObjectNow() {return loadObjectNow(getObject());}
129/** Can be used BeforeObject and BeforeUnknown.
130    Object data will not be loaded. */
131int skipObject() {return loadObjectNow(&emptyparam);}
132/** @return 1 if no errors */
133int run();
134
135void includeFile(SString& filename);
136bool returnFromIncluded();
137bool alreadyIncluded(const char* filename);
138
139};
140
141#endif
142
Note: See TracBrowser for help on using the repository browser.