/*-*- c++ -*-****************************************************************** * GraceTMPL Library * Copyright (C) 2001,2002 Andy Thaller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ #include "gracetmpl.h" #include #include #include extern "C" { #include #include #include #include #include } using namespace GraceTMPL; using namespace std; /* ******************************************************************** * * Global methods in namespace GraceTMPL * * *******************************************************************/ string GraceTMPL::smashVars(const string &from) { string to(from), param, cont; typedef string::size_type ST; ST p1=0,p2; while ((p1=to.find("$",p1))!=string::npos) { if (to[p1+1]=='{') { // this is ${PARAMNAME} if ((p2= to.find("}",p1+1))==string::npos) { fprintf(stderr,"no closing bracket in template <%s>\n",to.c_str()); return to; } param= to.substr(p1+2,p2-p1-2); ST pc=param.find("::",0); if (pc!=string::npos) { cont= param.substr(0,pc); param= param.substr(pc+2,param.length()); } } else { // this is $PARAMNAME p2= p1+1; while (isalnum(to[p2]) || to[p2]=='_') ++p2; --p2; param= to.substr(p1+1,p2-p1); } // smash the $NAME or ${CONTEXT::NAME} occurence: to.replace(p1,p2-p1+1,""); } return to; } string GraceTMPL::stringNum(double d, const char *fmt) { char tmp[1000]; snprintf(tmp,1000,fmt,d); return string(tmp); } string GraceTMPL::stringNum(float d, const char *fmt) { char tmp[1000]; snprintf(tmp,1000,fmt,d); return string(tmp); } string GraceTMPL::stringNum(long i, const char *fmt) { char tmp[1000]; snprintf(tmp,1000,fmt,i); return string(tmp); } string GraceTMPL::stringNum(int i, const char *fmt) { char tmp[1000]; snprintf(tmp,1000,fmt,i); return string(tmp); } /* ******************************************************************** * * some supplementary methods not exported by GraceTMPL * * *******************************************************************/ void appendStringVec(StringVec *a, StringVec *b) { if (!a||!b) return; if (a==b) return; StringVec::iterator daStr; for (daStr= b->begin(); daStr!= b->end(); ++daStr) { a->push_back(*daStr); } } string findString(StringVec *a, const char *first) { if (!a||!first) return string(""); StringVec::iterator daStr; for (daStr= a->begin(); daStr!= a->end(); ++daStr) { // fprintf(stderr,"checking <%s> against <%s>\n",daStr->c_str(),first); if (!strncmp(daStr->c_str(),first,strlen(first))) return *daStr; } return string(""); } int replaceString(StringVec *a, const char *first, const string &next) { if (!a||!first) return 0; StringVec::iterator daStr; for (daStr= a->begin(); daStr!= a->end(); ++daStr) { // fprintf(stderr,"checking <%s> against <%s>\n",daStr->c_str(),first); if (!strncmp(daStr->c_str(),first,strlen(first))) { *daStr= next; return 1; } } return 0; } int getScalar(StringVec *a, const char *first, double &x) { if (!a || !first) return 0; StringVec::iterator daStr; for (daStr= a->begin(); daStr!= a->end(); ++daStr) { if (!strncmp(daStr->c_str(),first,strlen(first))) if (sscanf(daStr->c_str()+strlen(first),"%lg",&x)==1) return 1; } return 0; } int getLoc(StringVec *a, const char *first, double &x, double &y) { if (!a || !first) return 0; StringVec::iterator daStr; for (daStr= a->begin(); daStr!= a->end(); ++daStr) { if (!strncmp(daStr->c_str(),first,strlen(first))) if (sscanf(daStr->c_str()+strlen(first),"%lg, %lg",&x,&y)==2) return 1; } return 0; } int replaceLoc(StringVec *a, const char *first, double x, double y) { double tx, ty; if (!a || !first) return 0; StringVec::iterator daStr; for (daStr= a->begin(); daStr!= a->end(); ++daStr) { if (!strncmp(daStr->c_str(),first,strlen(first))) if (sscanf(daStr->c_str()+strlen(first),"%lg, %lg",&tx,&ty)==2) { // fprintf(stderr,"replaciong loc <%s> with",daStr->c_str()); *daStr= string(first)+stringNum(x)+string(", ")+stringNum(y); // fprintf(stderr," <%s>\n",daStr->c_str()); return 1; } } return 0; } string Environment::expand(const string &from, int nests) { string to(from), param, cont, fallback, replacement; typedef string::size_type ST; ST p1=0,p2; if ((p1=to.find("$",p1))==string::npos) return from; while ((p1=to.find("$",p1))!=string::npos) { if (to[p1+1]=='{') { // this is ${PARAMNAME} if ((p2= to.find("}",p1+1))==string::npos) { fprintf(stderr,"no closing bracket in template <%s>\n",to.c_str()); return to; } fallback=string("${")+(param= to.substr(p1+2,p2-p1-2))+"}"; if (param.find("$",0)!=string::npos) { // nested params... p1++; continue; } // search from right to left to find whole context! ST pc=param.rfind("::",param.length()-1); if (pc!=string::npos) { cont= param.substr(0,pc); if (cont=="") cont= "std"; param= param.substr(pc+2,param.length()); } pc=param.find(":",0); if (pc!=string::npos) { fallback= param.substr(pc+1,param.length()); param= param.substr(0,pc); } } else { // this is $PARAMNAME p2= p1+1; while (isalnum(to[p2]) || to[p2]=='_') ++p2; --p2; param= to.substr(p1+1,p2-p1); fallback= string("$")+param; } replacement= substitute(cont,param,fallback); to.replace(p1,p2-p1+1,replacement); p1+= replacement.size(); } // cerr << "status("< "<second; } } if (context!="") { string tcontext(context), ncontext; string::size_type tc=tcontext.find("::",0); if (tc!=string::npos) { ncontext= tcontext.substr(tc+2,tcontext.length()); tcontext= tcontext.substr(0,tc); } /* if (mydebug) cerr << "** \""<::iterator daEnv= context_.find(tcontext); if (daEnv!=context_.end() && daEnv->second) { return daEnv->second->substitute(ncontext,variable,fallback); } /*else { if (mydebug) cerr << "** \""<substitute(context,variable,fallback); } //if (mydebug) cerr << "** \""<" Data::Data() : EnvironmentUser(), name_(DUMMY_NAME), n_(0), setnum_(0), x_(0), y_(0), dx_(0), dy_(0), xoffs_(0.0), yoffs_(0.0), scale_(1.0) { } Data::Data(const string &name, int n, const double *x, const double *y, const double *dx, const double *dy) : EnvironmentUser(), name_(name), n_(n), setnum_(0), x_(0), y_(0), dx_(0), dy_(0), xoffs_(0.0), yoffs_(0.0), scale_(1.0) { if (n) { if (x) { x_= new double[n]; memcpy(x_,x,sizeof(double)*n); } if (y) { y_= new double[n]; memcpy(y_,y,sizeof(double)*n); } if (dx) { dx_= new double[n]; memcpy(dx_,dx,sizeof(double)*n); } if (dy) { dy_= new double[n]; memcpy(dy_,dy,sizeof(double)*n); } } } #if 0 void Data::autoscale(double &xmin, double &xmax, double &ymin, double &ymax, double errorfac) { if (x_) for (int i= 0; i(x_[i]-xoffs_-fabs(xerr))) xmin= (x_[i]-xoffs_-fabs(xerr)); if (xmax<(x_[i]-xoffs_+fabs(xerr))) xmax= (x_[i]-xoffs_+fabs(xerr)); } if (y_) for (int i= 0; i(y_[i]-yoffs_-fabs(yerr))*scale_) ymin= (y_[i]-yoffs_-fabs(yerr))*scale_; if (ymax<(y_[i]-yoffs_+fabs(yerr))*scale_) ymax= (y_[i]-yoffs_+fabs(yerr))*scale_; } } #endif void Data::autoscale(double &xmin, double &xmax, double &ymin, double &ymax, double XMIN, double XMAX, double YMIN, double YMAX, double errorfac) { if (x_ && y_) for (int i= 0; iXMAX || yhYMAX) { continue; } if (xmin>xl) xmin= xl; if (xmaxyl) ymin= yl; if (ymaxpush_back(string("legend \"")+legend+string("\"")); } StringVec::iterator daStr; for (daStr= daSet->begin(); daStr!= daSet->end(); ++daStr) { fprintf(f,"@ s%d %s\n",setnum_,daStr->c_str()); } } void Data::savedata(FILE *f, int correctLog) { if (!x_ || !y_) return; fprintf(f,"@type xy%s%s\n",(dx_)?"dx":"",(dy_)?"dy":""); if (!correctLog) { for (int hi=0; hi 0) { fprintf(f,"%e\t%e",x_[hi]-xoffs_, (y_[hi]-yoffs_)*scale_); if (dx_) fprintf(f,"\t%e",dx_[hi]); fprintf(f,"\t%e",dy_[hi]*scale_); fprintf(f,"\n"); } } else { if ((y_[hi]-yoffs_)*scale_ > 0) { fprintf(f,"%e\t%e",x_[hi]-xoffs_,(y_[hi]-yoffs_)*scale_); if (dx_) fprintf(f,"\t%e",dx_[hi]); fprintf(f,"\n"); } } } } fprintf(f,"&\n"); } /************************************************************************/ /************************************************************************/ /************************************************************************/ /************************************************************************/ /************************************************************************/ Graph::Graph(Save *saver, int logplot) : EnvironmentUser(), graphnum_(0), saver_(saver), xoffs_(0.0), yoffs_(0.0), scale_(1.0), correctLog_(logplot) { } void Graph::addParam(const string &name,double value) { params_.push_back(name+string(" = ")+stringNum(value)); } int isNoscale(StringVec *a,const string &which) { string label= findString(a, string(which+string(" label")).c_str()); if (!label.length()) label= findString(a, string(which+string(" label")).c_str()); typedef string::size_type ST; ST p1,p2; p1=label.find("\"",0); if (p1==string::npos) return 0; p2=label.find("\"",p1+1); if (p2==string::npos) return 0; if ( /*p2-p1>5 && */ // we allow " " to be valid, too label[p1+1]==' ' && label[p1+2]==' ' /*&& label[p1+3]!=' '*/ && label[p2-1]==' ' && label[p2-2]==' ' /*&& label[p2-3]!=' '*/) return 1; return 0; } void Graph::saveprep(const StringVecMap *daSets0) { StringVecMap mySets(*daSets0); StringVecMap *daSets= &mySets; for (int i=0; isize()); i++) { // better than "<1000" !! string legend= findString(&((*daSets)[i]),"legend \""); if (!legend.length()) legend= findString(&((*daSets)[i]),"legend \""); /* new copydata fprintf(stderr,"blabla %d %d (%d) (%s) %d\n",graphnum_,i,dataVec_.size(), legend.c_str(),saver_->isCopydata(graphnum_,i)); */ if (legend.find("$!\"",0)!=string::npos) { /* if this method is called more than once, avoid inserting dummies * all over again */ if (iname()!=string(DUMMY_NAME)) { vector::iterator insPos(&(dataVec_[i])); dataVec_.insert(insPos,new Data()); } //new copydata fprintf(stderr," inserting literal data\n"); } else { dataVec_.push_back(new Data()); //new copydata fprintf(stderr," appending literal data\n"); } // set this graph's environment as parent for a dummy env in dummy set dataVec_[i]->setenv(new Environment(env())); literalData_[i]= 1; } else if (saver_->isCopydata(graphnum_,i)) { /* if this method is called more than once, avoid inserting dummies * all over again */ if (iname()!=string(DUMMY_NAME)) { vector::iterator insPos(&(dataVec_[i])); dataVec_.insert(insPos,new Data()); } //new copydata fprintf(stderr," inserting copy data\n"); } else { dataVec_.push_back(new Data()); //new copydata fprintf(stderr," appending copy data\n"); } // set this graph's environment as parent for a dummy env in dummy set dataVec_[i]->setenv(new Environment(env())); literalData_[i]= 2; } if (iregCopydata(graphnum_,i,dataVec_[i]); } std::vector::iterator daData; int snum= 0; for (daData=dataVec_.begin(); daData!=dataVec_.end(); ++daData, ++snum) { Data *d= *daData; d->setNum(snum); // is set in dummy sets for literal or copy data!! d->env()->setName(string("s")+stringNum(snum)); } } void Graph::saveinfo(FILE *f, const StringVec *daGraph0, const StringVecMap *daSets0, const StringVecMap *daStrings) { StringVec myGraph(*daGraph0); StringVec *daGraph= &myGraph; StringVecMap mySets(*daSets0); StringVecMap *daSets= &mySets; std::vector::iterator daData; double xmin= DBL_MAX, xmax=-DBL_MAX, ymin= DBL_MAX, ymax=-DBL_MAX; double XMIN=-DBL_MAX, XMAX= DBL_MAX, YMIN=-DBL_MAX, YMAX= DBL_MAX; if (isNoscale(daGraph,"xaxis")) { double lower,upper; if (getScalar(daGraph,"world xmin ",lower) && getScalar(daGraph,"world xmax ",upper)) { //cerr << "no autoscale on xaxis ("<