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

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