Index: app/src/lib/tfti.h
===================================================================
--- app/src/lib/tfti.h	(revision 25ae32e4c2354e0ed6756bbe1de83f39cd814652)
+++ app/src/lib/tfti.h	(revision 25ae32e4c2354e0ed6756bbe1de83f39cd814652)
@@ -0,0 +1,523 @@
+#ifndef TFTiH
+#define TFTiH
+//---------------------------------------------------------------------------
+#include <fstream.h>
+#include <math.h>
+#include <iomanip.h>
+//#include <typeinfo.h>
+
+#include "tft.h"
+//---------------------------------------------------------------------------
+
+template<class I, class Ipass, class O, class Opass>
+class TFTi : public TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >
+{
+public:
+  TFTi() : TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >() {};
+  TFTi(const char* filename)
+  : TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >() { load(filename); };
+
+  void read(const char* filename);
+  void read(istream& is=cin);
+  void write(const char* filename);
+  void write(ostream& os=cout);
+  void load(const char* filename);
+  void load(FILE* f=stdin);
+  void save(const char* filename);
+  void save(FILE* f=stdout);
+  void clear();
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::ttn;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::states;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::transitions;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::itype;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::ftTYPELEN;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::otype;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::tt;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::copy_default;
+  using TFT<I,Ipass,O,Opass,TTrans_i<I,Ipass,O,Opass> >::print_mode;
+
+
+//  friend istream& operator>>(istream&, TFTi<I,Ipass,O,Opass>&);
+//  friend ostream& operator<<(ostream&, const TFTi<I,Ipass,O,Opass>&);
+};
+
+//---------------------------------------------------------------------------
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::read(const char* filename)
+{
+  ifstream is(filename);
+  if(!is) { fprintf(stderr,"Failed to open input file."); exit(1); }
+  read(is);
+}
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::read(istream& is)
+{
+  long *si;                             // state-index relation
+  long ci=0;                            // current index
+  char ch;                              // character read;
+  int empty=0;                          // no of states with 0 trans?
+  char intype[FT::ftTYPELEN];
+  char outtype[FT::ftTYPELEN];
+
+  clear();
+
+  is >> states >> transitions >> intype >> outtype;
+
+//  if(strcmp(intype,itype)!=0 ||
+//     strcmp(outtype,otype)!=0 && strcmp(outtype,"void")!=0)
+//    { is.clear(ios::badbit); goto end; };
+
+  while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+  while(is.peek()!='\n')
+  {
+    char s[20];
+    is >> s;
+    if(strcmp(s,"COPY")==0 && strcmp(intype,outtype)==0) copy_default=true;
+    else if(strcmp(s,"NOCOPY")==0) copy_default=false;
+    else if(strcmp(s,"II")==0) print_mode=FT::II;
+    else if(strcmp(s,"OO")==0) print_mode=FT::OO;
+    else if(strcmp(s,"IOIO")==0) print_mode=FT::IOIO;
+    else if(strcmp(s,"OIOI")==0) print_mode=FT::OIOI;
+    else if(strcmp(s,"IIOO")==0) print_mode=FT::IIOO;
+    else if(strcmp(s,"OIOI")==0) print_mode=FT::OIOI;
+    while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+  }
+
+  ttn=transitions+2;      // 1 state without trans., 1 additional
+  si=new long[states];
+  tt=new TTrans_i<I,Ipass,O,Opass>[ttn];
+
+  for(long cs=0;cs<states;cs++)
+  {
+    long tc;                             // transition counter
+    si[cs]=ci;
+    long cscheck;
+
+    if(!is) goto end;
+    while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+    is >> cscheck;
+    if(cs!=cscheck) goto end;
+
+    while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+
+    is.get(ch);
+    if(!is) goto end;
+    switch(ch)
+    {
+      case '-': tt[ci].final(false); break;
+      case '+': tt[ci].final(true); break;
+      default: goto end;
+    }
+    tc=0, tt[ci].continued(false);
+
+    while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+    while(is && is.peek()!='\n')
+    {
+      switch(is.peek())
+      {
+        case '~': tt[ci].epsi(true); tt[ci].defi(true); is.get(ch);
+                  break;
+        case '@': tt[ci].epsi(false); tt[ci].defi(true); is.get(ch);
+                  break;
+        default : tt[ci].geti(is);
+      }
+      if(!is) goto end;
+      if(is.peek()=='/')
+      {
+        is.get(ch);
+        switch(is.peek())
+        {
+          case '~': tt[ci].epso(true); tt[ci].defo(true); is.get(ch);
+                    break;
+          case '@': tt[ci].epso(false); tt[ci].defo(true); is.get(ch);
+                    break;
+          default : tt[ci].geto(is);
+        }
+      }
+      else
+      {
+        tt[ci].defo(true);
+        if(copy_default) tt[ci].epso(false); else tt[ci].epso(true);
+      }
+      if(!is) goto end;
+
+      unsigned long transition;
+      is >> transition;
+      tt[ci].next(transition);
+
+      tt[ci].continued(false);
+      tt[ci].empty(false);
+
+      if(tc>0) tt[ci-1].continued(true);
+      tc++,ci++;
+    }
+    if(tc==0)
+    {
+      if(++empty>2) { fprintf(stderr, "Nondeterministic automaton."); exit(1); }
+      tt[ci].empty(true);
+      ci++;
+    }
+    is.get(ch);
+    if(ch!='\n') { is.clear(ios::badbit); goto end; }
+  }
+
+  ttn=transitions+empty;
+  if(ttn!=ci) { is.clear(ios::badbit); goto end; };
+  for(long i=0;i<ttn;i++)
+    tt[i].next(si[tt[i].next()]);
+  delete[] si;
+  sort();
+
+end:
+  if(is.bad()) { fprintf(stderr,"Input error."); exit(1); }
+}
+
+//---------------------------------------------------------------------------
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::write(const char* filename)
+{
+  ofstream os(filename);
+  if(!os) err("Failed to open output file.");
+  write(os);
+}
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::write(ostream& os)
+{
+  os << states << ' ' << transitions << ' ';
+//  os << itype << ' ' << otype << ' ';
+  os << "char void";
+//  os << (copy_default ? "COPY" : "NOCOPY") << ' ';
+//  switch(print_mode)
+//  {
+//    case FT::II  : os << "II"; break;
+//    case FT::OO  : os << "OO"; break;
+//    case FT::IOIO: os << "IOIO"; break;
+//    case FT::OIOI: os << "OIOI"; break;
+//    case FT::IIOO: os << "IIOO"; break;
+//    case FT::OOII: os << "OOII";
+//  }
+  os << '\n';
+
+  long* si=new long[ttn];
+  long cs=0;
+  for(long i=0;i<ttn;i++)
+  {
+    si[i]=cs;
+    if(continued(i)==false) cs++;
+  }
+
+  int statefieldwidth=log10(cs+1);
+
+  bool first=true;
+  for(long i=0;i<ttn;i++)
+  {
+    if(first)
+    {
+      os << setw(statefieldwidth) << si[i] << " ";
+      if(final(i)) os << '+'; else os << '-';
+    }
+
+
+    if(!empty(i))
+    {
+      os << ' ';
+      if(epsi(i))
+        os << FT::ftEPSILON;
+      else
+      if(defi(i))
+        os << FT::ftDEFAULT;
+      else
+        os << input(i);
+
+      if(epso(i))
+      { if(copy_default) os << '/' << FT::ftEPSILON; }
+      else
+      if(defo(i))
+      { if(!copy_default) os << '/' << FT::ftDEFAULT; }
+      else
+      { os << '/' << output(i); }
+
+      if(strcmp(itype,"char")!=0 || strcmp(otype,"char")!=0)
+        os << ' ';
+      os << si[next(i)];
+    }
+    if(continued(i))
+      first=false;
+    else
+    { os << '\n'; first=true; }
+  }
+}
+
+//---------------------------------------------------------------------------
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::load(const char* filename)
+{
+  FILE* f;
+  if(*filename)
+    f=fopen(filename,"rb");
+  else
+    f=stdin;
+  if(!f) { fprintf(stderr, "Cannot open automaton file."); return; }
+  load(f);
+}
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::load(FILE* f)
+{
+
+  clear();
+
+  if(fread(&ttn,sizeof(ttn),1,f)!=1) { fprintf(stderr, "Binary input error."); return;}
+  if(fread(&states,sizeof(states),1,f)!=1) { fprintf(stderr, "Binary input error."); return;}
+  if(fread(&transitions,sizeof(transitions),1,f)!=1) { fprintf(stderr, "Binary input error."); return;}
+  if(fread(itype,sizeof(char),ftTYPELEN,f)!=ftTYPELEN) { fprintf(stderr, "Binary input error."); return;}
+  if(fread(otype,sizeof(char),ftTYPELEN,f)!=ftTYPELEN) { fprintf(stderr, "Binary input error."); return;}
+  if(fread(&copy_default,sizeof(copy_default),1,f)!=1) { fprintf(stderr, "Binary input error."); return;}
+  if(fread(&print_mode,sizeof(print_mode),1,f)!=1) { fprintf(stderr, "Binary input error."); return;}
+  if((tt=new TTrans_i<I,Ipass,O,Opass>[ttn])==NULL) { fprintf(stderr, "Cannot allocate memory for tt."); return;}
+  if(fread(tt,sizeof(TTrans_i<I,Ipass,O,Opass>),ttn,f)!=ttn) { fprintf(stderr, "Binary input error."); return; }
+  fclose(f);
+
+
+}
+
+//---------------------------------------------------------------------------
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::save(const char* filename)
+{
+  FILE* f;
+  if(*filename)
+    f=fopen(filename,"wb");
+  else
+    f=stdout;
+  if(!f) err("Cannot open file.");
+  save(f);
+}
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::save(FILE* f)
+{
+  if(fwrite(&ttn,sizeof(ttn),1,f)!=1) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(&states,sizeof(states),1,f)!=1) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(&transitions,sizeof(transitions),1,f)!=1) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(itype,sizeof(char),ftTYPELEN,f)!=ftTYPELEN) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(otype,sizeof(char),ftTYPELEN,f)!=ftTYPELEN) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(&copy_default,sizeof(copy_default),1,f)!=1) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(&print_mode,sizeof(print_mode),1,f)!=1) { fprintf(stderr,"Binary output error."); exit(1); }
+  if(fwrite(tt,sizeof(TTrans_i<I,Ipass,O,Opass>),ttn,f)!=ttn) { fprintf(stderr,"Binary output error."); exit(1); }
+  fclose(f);
+}
+
+//---------------------------------------------------------------------------
+
+template<class I, class Ipass, class O, class Opass>
+void TFTi<I,Ipass,O,Opass>::clear()
+{
+  if(tt) delete[] tt;
+  ttn=0;
+}
+
+//---------------------------------------------------------------------------
+/*
+template<class I, class Ipass, class O, class Opass>
+istream& operator>>(istream& is, TFTi<I,Ipass,O,Opass>& ft)
+{
+  long *si;                             // state-index relation
+  long ci=0;                            // current index
+  char ch;                              // character read;
+  int empty=0;                          // no of states with 0 trans?
+  char intype[FT::ftTYPELEN];
+  char outtype[FT::ftTYPELEN];
+
+  ft.clear();
+
+  is >> ft.states >> ft.transitions >> intype >> outtype;
+
+  if(strcmp(intype,ft.itype)!=0 ||
+     strcmp(outtype,ft.otype)!=0 && strcmp(outtype,"void")!=0)
+    { is.clear(ios::badbit); return is; };
+
+  while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+  while(is.peek()!='\n')
+  {
+    char s[20];
+    is >> s;
+    if(strcmp(s,"COPY")==0 && strcmp(intype,outtype)==0) ft.copy_default=true;
+    else if(strcmp(s,"NOCOPY")==0) ft.copy_default=false;
+    else if(strcmp(s,"II")==0) ft.print_mode=FT::II;
+    else if(strcmp(s,"OO")==0) ft.print_mode=FT::OO;
+    else if(strcmp(s,"IOIO")==0) ft.print_mode=FT::IOIO;
+    else if(strcmp(s,"OIOI")==0) ft.print_mode=FT::OIOI;
+    else if(strcmp(s,"IIOO")==0) ft.print_mode=FT::IIOO;
+    else if(strcmp(s,"OIOI")==0) ft.print_mode=FT::OIOI;
+    while(is.peek()==' ' || is.peek()=='\t') is.get(ch);
+  }
+
+  ft.ttn=ft.transitions+2;      // 1 state without trans., 1 additional
+  si=new long[ft.states];
+  ft.tt=new TTrans_i<I,Ipass,O,Opass>[ft.ttn];
+
+  for(long cs=0;cs<ft.states;cs++)
+  {
+    long tc;                             // transition counter
+    si[cs]=ci;
+    do is >> ch; while(ch!='+' && ch!='-');
+    switch(ch)
+    {
+      case '-': ft.tt[ci].final(false); break;
+      case '+': ft.tt[ci].final(true); break;
+      default: return is;
+    }
+    tc=0, ft.tt[ci].continued(false);
+    while((is.get(ch),ch==' '))
+    {
+      if(!is) return is;
+      switch(is.peek())
+      {
+        case '~': ft.tt[ci].epsi(true); ft.tt[ci].defi(true); is.get(ch);
+                  break;
+        case '@': ft.tt[ci].epsi(false); ft.tt[ci].defi(true); is.get(ch);
+                  break;
+        default : ft.tt[ci].geti(is);
+      }
+      if(!is) return is;
+      if(is.peek()=='/')
+      {
+        is.get(ch);
+        switch(is.peek())
+        {
+          case '~': ft.tt[ci].epso(true); ft.tt[ci].defo(true); is.get(ch);
+                    break;
+          case '@': ft.tt[ci].epso(false); ft.tt[ci].defo(true); is.get(ch);
+                    break;
+          default : ft.tt[ci].geto(is);
+        }
+      }
+      else
+      {
+        ft.tt[ci].defo(true);
+        if(ft.copy_default) ft.tt[ci].epso(false); else ft.tt[ci].epso(true);
+      }
+      if(!is) return is;
+
+      unsigned long transition;
+      is >> transition;
+      ft.tt[ci].next(transition);
+
+      ft.tt[ci].continued(false);
+
+      ft.tt[ci].empty(false);
+      if(tc>0) ft.tt[ci-1].continued(true);
+      tc++,ci++;
+    }
+    if(tc==0)
+    {
+      if(++empty>2) err("Nondeterministic automaton.");
+      ft.tt[ci].empty(true);
+      ci++;
+    }
+    if(ch!='\n') { is.clear(ios::badbit); return is; }
+  }
+
+  ft.ttn=ft.transitions+empty;
+  if(ft.ttn!=ci) { is.clear(ios::badbit); return is; };
+  for(long i=0;i<ft.ttn;i++)
+    ft.tt[i].next(si[ft.tt[i].next()]);
+  delete[] si;
+  ft.sort();
+  return is;
+}
+*/
+//---------------------------------------------------------------------------
+/*
+template<class I, class Ipass, class O, class Opass>
+ostream& operator<<(ostream& os, const TFTi<I,Ipass,O,Opass>& ft)
+{
+  os << ft.states << ' ' << ft.transitions << ' '
+     << ft.itype << ' ' << ft.otype << ' ';
+  os << (ft.copy_default ? "COPY" : "NOCOPY") << ' ';
+  switch(ft.print_mode)
+  {
+    case FT::II  : os << "II"; break;
+    case FT::OO  : os << "OO"; break;
+    case FT::IOIO: os << "IOIO"; break;
+    case FT::OIOI: os << "OIOI"; break;
+    case FT::IIOO: os << "IIOO"; break;
+    case FT::OOII: os << "OOII";
+  }
+  os << ' ' << '\n';
+
+  long* si=new long[ft.ttn];
+  long cs=0;
+  for(long i=0;i<ft.ttn;i++)
+  {
+    si[i]=cs;
+    if(ft.continued(i)==false) cs++;
+  }
+
+  bool first=true;
+  for(long i=0;i<ft.ttn;i++)
+  {
+    if(first)
+      if(ft.final(i)) os << '+'; else os << '-';
+
+    if(!ft.empty(i))
+    {
+      os << ' ';
+      if(ft.epsi(i))
+        os << FT::ftEPSILON;
+      else
+      if(ft.defi(i))
+        os << FT::ftDEFAULT;
+      else
+        os << ft.input(i);
+
+      if(ft.epso(i))
+      { if(ft.copy_default) os << '/' << FT::ftEPSILON; }
+      else
+      if(ft.defo(i))
+      { if(!ft.copy_default) os << '/' << FT::ftDEFAULT; }
+      else
+      { os << '/' << ft.output(i); }
+
+      if(strcmp(ft.itype,"char")!=0 || strcmp(ft.otype,"char")!=0)
+
+        os << ' ';
+      os << si[ft.next(i)];
+    }
+    if(ft.continued(i))
+      first=false;
+    else
+    { os << '\n'; first=true; }
+  }
+  return os;
+}
+*/
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+template<class I, class O>
+class TFTiv : public TFTi<I,I,O,O>
+{
+public:
+  TFTiv() : TFTi<I,I,O,O>() {};
+  TFTiv(const char* filename) : TFTi<I,I,O,O>(filename) {};
+};
+
+//---------------------------------------------------------------------------
+
+template<class I, class O>
+class TFTir : public TFTi<I,I&,O,O&>
+{
+public:
+  TFTir() : TFTi<I,I,O,O>() {};
+};
+
+//---------------------------------------------------------------------------
+#endif
