extern "C" {
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
}
#include <iostream>
#include <string>
#include <vector>
#include <map>

#include "gracetmpl.h"

int debug= 0;

using namespace GraceTMPL;
using namespace std;

void loadXYdY(FILE *f, GraceTMPL::Graph *graph, const char *name=0) 
{
  std::vector<double> dataX, dataY, dataDY;  
  unsigned int numDY= 0, cmtCNT=0;

  char line[3000];
  fgets(line,3000,f);

  while (fgets(line,3000,f)) {
    double x,y,dy;
    // eat comments (anything beginning with '#')
    // and store the comment for use in the template
    char *cmt= index(line,'#');
    if (cmt) {
      cmt++;
      char comment[20];
      snprintf(comment,20,"comment%d",cmtCNT++);
      char *eol= index(cmt,'\n'); if (eol) *eol= 0;
      graph->setenv(comment,cmt+1);
      cmt=0;
    }
    
    switch(sscanf(line,"%lg %lg %lg",&x,&y,&dy)) {
    case 3: 
      dataDY.push_back(dy);
      dataY.push_back(y);
      dataX.push_back(x);
      numDY++;
      break;
    case 2: 
      dataDY.push_back(0);
      dataY.push_back(y);
      dataX.push_back(x);
      break;
    case 1: 
      dataDY.push_back(0);
      dataY.push_back(0);
      dataX.push_back(x);
      break;
    default:
      break;
    }
  }
  if (!dataX.size()) return;
  
  double *daX= new double[dataX.size()];
  double *daY= new double[dataY.size()];
  double *daDY= new double[dataDY.size()];
  
  for (unsigned int i=0; i<dataX.size(); i++) {
    daX[i]= dataX[i];
    daY[i]= dataY[i];
    daDY[i]= dataDY[i];
  }
  
  // insert data with or without errorbars, depending on data in file:
  if (numDY==dataX.size()) 
    graph->addData(new GraceTMPL::Data((name)?name:"data",dataX.size(),daX,daY,0,daDY));
  else
    graph->addData(new GraceTMPL::Data((name)?name:"data",dataX.size(),daX,daY,0,0));
  
  delete[] daX;
  delete[] daY;
  delete[] daDY;
}

void loadBlockData(FILE *f, GraceTMPL::Graph *graph, int nxy, const char *name= 0, int err= 0) 
{
  typedef std::vector<double> DVec;
  DVec dataX, dataY[nxy], dataDY[nxy];
  unsigned int cmtCNT=0;
  int ycnt= 0;

  fprintf(stderr,"trying to get %d values %sfrom %s\n",nxy,err?"with errors ":"",name?name:"");

  char line[3000];
  fgets(line,3000,f);

  while (fgets(line,3000,f)) {
    double x;
    char *optr= line, *nptr;
    // eat comments (anything beginning with '#')
    // and store the comment for use in the template
    char *cmt= index(line,'#');
    if (cmt) {
      cmt++;
      char comment[20];
      snprintf(comment,20,"comment%d",cmtCNT++);
      char *eol= index(cmt,'\n'); if (eol) *eol= 0;
      graph->setenv(comment,cmt+1);
      cmt=0;
    }
    x= strtod(optr,&nptr);
    if (nptr!=optr) {
      optr= nptr;
      dataX.push_back(x);
      for (int i=0; i<nxy; i++) {
	dataY[i].push_back(strtod(optr,&nptr));
	if (err) { optr= nptr; dataDY[i].push_back(strtod(optr,&nptr));	}
	if (optr!=nptr && i>=ycnt) ycnt= i+1;
	optr= nptr;
      }
    }
  }
  if (!dataX.size()) return;
  
  double *daX= new double[dataX.size()];
  double *daY= new double[dataX.size()];
  double *daDY= new double[dataX.size()];
  
  for (unsigned int i=0; i<dataX.size(); i++) {
    daX[i]= dataX[i];
  }

  for (int j=0; j<ycnt; j++) {
    for (unsigned int i=0; i<dataX.size(); i++) {
      daY[i]= dataY[j][i];
      if (err) daDY[i]= dataDY[j][i];
    }
    if (err)
      graph->addData(new GraceTMPL::Data((name)?name:"data",dataX.size(),daX,daY,0,daDY));
    else
      graph->addData(new GraceTMPL::Data((name)?name:"data",dataX.size(),daX,daY,0,0));
  }      
  delete[] daX;
  delete[] daY;
  delete[] daDY;
}

void loadFile(const string &name, GraceTMPL::Save *xmgr) 
{
  if (!xmgr) return;
  int nxy= 0,nxyerr=0;
  
  FILE *f= fopen(name.c_str(),"r");
  if (!f) {
    cerr << "could not open file \""<<name<<"\" !\n";
    return;
  }

  // get a new graph to store the data in:
  GraceTMPL::Graph *graph= xmgr->newGraph();

  // split filename into path and rest:
  string file(name);
  string path;
  string fname(name);
  typedef string::size_type ST;
  ST p1= file.rfind("/");
  if (p1!=string::npos) {
    path= file.substr(0,p1);
    fname= file.substr(p1+1,file.length());
  }
  if (path[0]!='/') {
    path= string(getenv("PWD"))+string("/")+path;
  }
  char rpath[PATH_MAX];
  if (realpath(path.c_str(),rpath)) path= rpath;

  // set path, filename and the original name in the environment:
  graph->setenv("path",path);
  graph->setenv("file",fname);
  graph->setenv("filename",name);

  char line[3000];
  fgets(line,3000,f);

  if (!strncmp(line,"# NXYDY",7)) {
    nxy= atoi(line+8);
    nxyerr= 1;
  } else if (!strncmp(line,"# NXY",5)) {
    nxy= atoi(line+6);
    nxyerr= 0;
  } else {
    fseek(f,0,SEEK_SET);
  }
  
  if (nxy) 
    loadBlockData(f,graph,nxy,fname.c_str(),nxyerr);
  else
    loadXYdY(f,graph,fname.c_str());
  
  fclose(f);
}



int main(int argc, char **argv)
{
  // default template for the destination filename:
  string outname("${template}-${pz}.agr");
  string tmpl;
  vector<string> files;
  map<string,string> defines;

  int oc, spg;
  int simple=0;

  while (1) {
    int option_index = 0;
    static struct option long_options[] =
    {
      {"help",    0, 0, 'h'},
      {"output",  1, 0, 'o'},
      {"simple",  0, 0, 's'},
      {"spg",     1, 0, 'S'},
      {"template",1, 0, 't'},
      {0, 0, 0, 0}
    };

    oc = getopt_long (argc, argv, "-?D:ho:t:S:sV",
		     long_options, &option_index);
    if (oc == -1)
      break;
   
    switch (oc) {
    case '?': 
    case 'h': 
      cerr <<"gracetmpldemo (C) 1999,2000 by Andy Thaller " 
	   <<"<thaller@ph.tum.de>\n"
	   <<"\n"
	   <<"Usage: gracetmpldemo [-h] [options] file [..]\n"
	   <<"\n"
	   <<"Options:\n"
	   <<"  -h, --help    : show this help and exit\n"
	   <<"  -t, --template: use xmgrace template for outputting data\n"
	   <<"  -s, --simple  : use set formats from 'g0' for all graphs\n"
	   <<"  -S, --spg     : number of Sets Per Graph\n"
	   <<"  -o, --output  : specify an alternative destination filename\n"
	   <<"  -D name=value : set a variable in the sheet's environment\n"
	   <<"\n";
      exit(-1);
      break;
      
    case 'd': debug++; break;
    case 't': tmpl = string(optarg); break;
    case 's': simple = 1; break;
    case 'S': spg = atoi(optarg); break;
    case 'o': outname = string(optarg); break;
    case 'D': {
      string oa(optarg),name,value;
      string::size_type pos=oa.find("=");
      if (pos!=string::npos) {
	name= oa.substr(0,pos);
	value= oa.substr(pos+1,oa.length());
	defines[name]= value;
      } else {
	cerr << "Warning: option '-D' needs an argument in the form "
	     << "'name=value'\n";
      }
      break;
    }
    case 1:
      /* see getopt_long(3): generated by "-" in optstring to denote non-opt */
      files.push_back(string(optarg));
      break;
      
    }
  }
  
  if (!files.size()) {
    cerr << "no files given on command line, bailing out.\n";
    exit(1);
  }
  /* One and only one template (if any) for all the stuff to follow: 
   * We search for a template "TMPL" both in "./" and "~/.grace/"
   */
  GraceTMPL::Save *xmgr= 0;
  if (tmpl.length()) {
    if (!(xmgr= new GraceTMPL::Save())) {
      cerr << "Could not produce GraceTMPL::Save\n"; exit(1);
    }
    const char *homedir= getenv("HOME");
    int l= tmpl.length()+strlen(homedir)+9;
    char *tmpl2= new char[l];
    snprintf(tmpl2,l,"%s/.grace/%s",homedir,tmpl.c_str());
    if (xmgr->loadTemplate(tmpl.c_str(),simple) || 
	xmgr->loadTemplate(tmpl2,simple)) {
      /* set the filename of the template in the environment
       * regardless of where we found it:
       */
      xmgr->setenv("template",tmpl);
      xmgr->setOutputName(outname);
      map<string,string>::iterator daDef;
      for (daDef=defines.begin(); daDef!=defines.end(); ++daDef) {
	xmgr->setenv(daDef->first,daDef->second);
      }
    } 
  }
  
  for (unsigned int i=0; i < files.size(); i++) {
    loadFile(files[i],xmgr);
  }
  
  if (xmgr) { 
    xmgr->save();
    delete xmgr;
  }
  
  exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1