// This file is a part of Framsticks GDK library. // Copyright (C) 2002-2006 Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.frams.alife.pl/ for further information. #include "multiparamload.h" #include "framsg.h" #include void MultiParamLoader::init() { file=0; ownfile=0; status=0; reset(); } void MultiParamLoader::reset() { status=0; breakcond=OnError; emptyparam.setParamTab(empty_paramtab); } void MultiParamLoader::load() { clearstack(); if (!file) { lasterror="can't open file"; status=OnError; return; } status=Loading; } void MultiParamLoader::abort() { if (file && ownfile) { fclose(file); file=0; } clearstack(); status=Finished; } void MultiParamLoader::load(VirtFILE *f) { abort(); ownfile=0; file=f; load(); } void MultiParamLoader::load(const char* filename) { abort(); ownfile=1; file=Vfopen(filename,FOPEN_READ); load(); } static int isEOL(char ch) { return (ch=='\n')||(ch=='\r'); } static char* fgets0(char*t,int d,VirtFILE *f,int &linlen) { char *r=fgets(t,d,f); if (r) { int d=strlen(r); if (d && isEOL(r[d-1])) { d--; if (d && isEOL(r[d-1])) d--; } linlen=d; r[d]=0; } else linlen=0; return r; } static char* trim(char*t,int &linlen) { char *x=t; while(isspace(*x)) x++; linlen-=(x-t); t=x; if (!linlen) return t; x=t+linlen-1; while(isspace(*x)) x--; x[1]=0; linlen=x-t+1; return t; } int MultiParamLoader::go() { char buf[100]; char *t; int linlen; if (status==OnError) return status; while (!finished()) { if ((status==BeforeObject) || ((status==BeforeUnknown)&&lastclass)) { lastclass->load(file); if (maybeBreak(AfterObject)) break; continue; } else if (status==BeforeUnknown) { loadObjectNow(&emptyparam); continue; } t=fgets0(buf,100,file,linlen); if (!t) { if (!returnFromIncluded()) { abort(); break; } else continue; } if (buf[0]=='#') { if (!strncmp(buf+1,"include",7)) { const char* t=strchr(buf,'\"'),*t2=0; if (t) t2=strchr(t+1,'\"'); if (t2) { SString filename(t+1,t2-t-1); include(filename); } else { const char* thisfilename=file->VgetPath(); FMprintf("MultiParamLoader","go",FMLV_WARN,"invalid \"%s\"%s%s",buf, (thisfilename?" in ":""),(thisfilename?thisfilename:"")); } continue; } else if (maybeBreak(OnComment)) { lastcomment=t+1; break; } } t=trim(buf,linlen); if ((linlen>1)&&(t[linlen-1]==':')) { lastunknown=0; lastunknown.append(t,linlen-1); lastclass=0; FOREACH(ParamInterface*,pi,params) { if (!strcmp(pi->getName(),lastunknown)) { lastclass=pi; break; } } if (lastclass) { if (maybeBreak(BeforeObject)) break; } else { if (maybeBreak(BeforeUnknown)) break; } } } return status; } bool MultiParamLoader::alreadyIncluded(const char* filename) { int i; const char* t; for(i=0;iVgetPath(); if (!t) continue; if (!strcmp(filename,t)) return true; } return false; } void MultiParamLoader::include(SString& filename) { const char* thisfilename=file->VgetPath(); SString newfilename; const char* t=thisfilename?strrchr(thisfilename,PATHSEPARATORCHAR):0; if (thisfilename && t) { newfilename.append(thisfilename,t-thisfilename+1); newfilename+=filename; } else newfilename=filename; if (alreadyIncluded(newfilename)) { FMprintf("MultiParamLoader","include",FMLV_WARN,"circular reference ignored (\"%s\")", (const char*)filename); return; } VirtFILE *f=Vfopen(newfilename,FOPEN_READ); if (!f) { FMprintf("MultiParamLoader","include",FMLV_WARN,"\"%s\" not found",(const char*)newfilename); } else { filestack+=file; file=f; } } VirtFILE* MultiParamLoader::popstack() { if (!filestack.size()) return 0; VirtFILE* f=filestack(filestack.size()-1); filestack.remove(filestack.size()-1); return f; } void MultiParamLoader::clearstack() { VirtFILE *f; while(f=popstack()) fclose(f); } bool MultiParamLoader::returnFromIncluded() { if (!filestack.size()) return false; if (file) fclose(file); file=popstack(); return true; } int MultiParamLoader::loadObjectNow(ParamInterface *pi) { pi->load(file); status=AfterObject; return 0; } int MultiParamLoader::run() { int stat; breakOn(OnError); while(stat=go()) if (stat==OnError) { abort(); return 0; } return 1; }