source: cpp/frams/param/multiparamload.cpp @ 1304

Last change on this file since 1304 was 998, checked in by Maciej Komosinski, 4 years ago

Report the error status just once so that while(go()) does not have to always check the error condition to stop (prevents endless loop on permanent errors)

  • Property svn:eol-style set to native
File size: 6.1 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "multiparamload.h"
6#include <frams/util/sstringutils.h>
7#include "common/log.h"
8#include <ctype.h>
9
10void MultiParamLoader::init()
11{
12        file = 0; ownfile = 0;
13        status = 0;
14        reset();
15}
16
17void MultiParamLoader::reset()
18{
19        status = 0;
20        breakcond = OnError;
21        aborting = false;
22        emptyparam.setParamTab(empty_paramtab);
23        linenum = 0;
24}
25
26int MultiParamLoader::findObject(const ExtObject &o)
27{
28        for (int i = 0; i < objects.size(); i++)
29                if ((*objects(i)) == o)
30                        return i;
31        return -1;
32}
33
34void MultiParamLoader::removeObject(const ExtObject &o)
35{
36        int i = findObject(o);
37        if (i >= 0)
38        {
39                delete objects(i);
40                objects -= i;
41        }
42}
43
44void MultiParamLoader::clearObjects()
45{
46        FOREACH(ExtObject*, o, objects)
47                delete o;
48        objects.clear();
49}
50
51void MultiParamLoader::load()
52{
53        clearstack();
54        if (!file)
55        {
56                lasterror = "can't open file";
57                status = OnError;
58                return;
59        }
60        status = Loading;
61        aborting = false;
62}
63
64void MultiParamLoader::abort()
65{
66        if (file && ownfile)
67        {
68                delete file;
69                file = 0;
70        }
71        clearstack();
72        status = Finished;
73        aborting = true;
74}
75
76void MultiParamLoader::load(VirtFILE *f)
77{
78        abort();
79        ownfile = 0;
80        file = f;
81        load();
82}
83
84void MultiParamLoader::load(const char* filename)
85{
86        abort();
87        ownfile = 1;
88        file = Vfopen(filename, FOPEN_READ_BINARY);
89        load();
90}
91
92int MultiParamLoader::go()
93{
94        SString buf;
95        if (status == OnError) return getStatusClearError();
96        int unexpected_line = 0;
97        while (!finished())
98        {
99                if ((status == BeforeObject) || ((status == BeforeUnknown) && !lastobject.isEmpty()))
100                {
101                        Param tmp_param;
102                        ParamInterface *pi = lastobject.getParamInterface(tmp_param);
103                        ParamInterface::LoadOptions opts;
104                        opts.abortable = &aborting;
105                        opts.warn_unknown_fields = true;
106                        opts.linenum = &linenum;
107                        pi->load(ParamInterface::FormatMultiLine, file, &opts);
108                        if ((status != Finished) && maybeBreak(AfterObject))
109                                break;
110                        unexpected_line = 0;
111                        continue;
112                }
113                else if (status == BeforeUnknown)
114                {
115                        logPrintf("MultiParamLoader", "go", LOG_WARN, "Skipping object '%s'", lastunknown.c_str());
116                        loadObjectNow(&emptyparam, false);
117                        continue;
118                }
119                if (!loadSStringLine(file, buf))
120                {
121                        unexpected_line = 0;
122                        if (!returnFromIncluded())
123                        {
124                                abort();
125                                break;
126                        }
127                        else
128                                continue;
129                }
130                linenum++;
131                if (buf[0] == '#')
132                {
133                        unexpected_line = 0;
134                        if (buf.startsWith("#include"))
135                        {
136                                const char* t = strchr(buf.c_str(), '\"'), *t2 = 0;
137                                if (t)
138                                        t2 = strchr(t + 1, '\"');
139                                if (t2)
140                                {
141                                        SString filename(t + 1, t2 - t - 1);
142                                        includeFile(filename);
143                                }
144                                else
145                                {
146                                        const char* thisfilename = file->VgetPath();
147                                        logPrintf("MultiParamLoader", "go", LOG_WARN, "invalid \"%s\"%s%s", buf.c_str(),
148                                                (thisfilename ? " in " : ""), (thisfilename ? thisfilename : ""));
149                                }
150                                continue;
151                        }
152                        else if ((status != Finished) && maybeBreak(OnComment))
153                        {
154                                lastcomment = buf.substr(1);
155                                break;
156                        }
157                        continue;
158                }
159                buf = trim(buf);
160                if (buf.length() == 0)
161                        unexpected_line = 0;
162                else if ((buf.length() > 1) && (buf[buf.length() - 1] == ':'))
163                {
164                        unexpected_line = 0;
165                        lastunknown = 0;
166                        lastunknown = buf.substr(0, buf.length() - 1);
167                        lastobject.setEmpty();
168                        FOREACH(ExtObject*, o, objects)
169                        {
170                                if (!strcmp(o->interfaceName(), lastunknown.c_str())) { lastobject = *o; break; }
171                        }
172                        if (!lastobject.isEmpty())
173                        {
174                                if (maybeBreak(BeforeObject))
175                                        break;
176                        }
177                        else
178                        {
179                                if (maybeBreak(BeforeUnknown))
180                                        break;
181                        }
182
183                }
184                else
185                {
186                        switch (unexpected_line)
187                        {
188                        case 0:
189                        {
190                                const char* thisfilename = file->VgetPath();
191                                logPrintf("MultiParamLoader", "go", LOG_WARN, "Ignored unexpected line %d%s",
192                                        linenum,
193                                        thisfilename ? SString::sprintf(" while reading '%s'", thisfilename).c_str() : "");
194                        }
195                        break;
196
197                        case 1:
198                                logPrintf("MultiParamLoader", "go", LOG_WARN, "The following line(s) were also unexpected and were ignored");
199                                break;
200                        }
201                        unexpected_line++;
202                }
203        }
204        return getStatusClearError();
205}
206
207bool MultiParamLoader::alreadyIncluded(const char* filename)
208{
209        int i;
210        const char* t;
211        for (i = 0; i < filestack.size(); i++)
212        {
213                t = filestack(i)->VgetPath();
214                if (!t) continue;
215                if (!strcmp(filename, t)) return true;
216        }
217        return false;
218}
219
220void MultiParamLoader::includeFile(SString& filename)
221{
222        const char* thisfilename = file->VgetPath();
223        SString newfilename;
224        const char* t = thisfilename ? strrchr(thisfilename, PATH_SEPARATOR_CHAR) : 0;
225
226        if (thisfilename && t)
227        {
228                newfilename.append(thisfilename, t - thisfilename + 1);
229                newfilename += filename;
230        }
231        else
232                newfilename = filename;
233
234        if (alreadyIncluded(newfilename.c_str()))
235        {
236                logPrintf("MultiParamLoader", "include", LOG_WARN, "circular reference ignored (\"%s\")",
237                        filename.c_str());
238                return;
239        }
240
241        VirtFILE *f = Vfopen(newfilename.c_str(), FOPEN_READ_BINARY);
242        if (!f)
243        {
244                logPrintf("MultiParamLoader", "include", LOG_WARN, "\"%s\" not found", newfilename.c_str());
245        }
246        else
247        {
248                filestack += file;
249                file = f;
250        }
251}
252
253VirtFILE* MultiParamLoader::popstack()
254{
255        if (!filestack.size()) return 0;
256        VirtFILE* f = filestack(filestack.size() - 1);
257        filestack.remove(filestack.size() - 1);
258        return f;
259}
260
261void MultiParamLoader::clearstack()
262{
263        VirtFILE *f;
264        while (f = popstack()) delete f;
265}
266
267bool MultiParamLoader::returnFromIncluded()
268{
269        if (!filestack.size()) return false;
270        if (file) delete file;
271        file = popstack();
272        return true;
273}
274
275int MultiParamLoader::loadObjectNow(const ExtObject& o, bool warn_unknown_fields)
276{
277        Param tmp_param;
278        ParamInterface *pi = o.getParamInterface(tmp_param);
279        ParamInterface::LoadOptions opts;
280        opts.abortable = &aborting;
281        opts.warn_unknown_fields = warn_unknown_fields;
282        opts.linenum = &linenum;
283        pi->load(ParamInterface::FormatMultiLine, file, &opts);
284        status = AfterObject;
285        return 0;
286}
287
288int MultiParamLoader::run()
289{
290        int stat;
291        breakOn(OnError);
292        while (stat = go())
293                if (stat == OnError)
294                {
295                        abort();
296                        return 0;
297                }
298        return 1;
299}
300
301SString MultiParamLoader::currentFilePathForErrorMessage()
302{
303        const char* filename = getFile()->VgetPath();
304        if (filename)
305                return SString::sprintf(" in '%s'", filename);
306        return SString::empty();
307}
Note: See TracBrowser for help on using the repository browser.