1329 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1329 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
//      $Id: relation.cpp,v 1.7 1994-09-07 17:00:16 guy Exp $
 | 
						|
// relation.cpp
 | 
						|
// fv 12/8/93
 | 
						|
// relation class for isam files
 | 
						|
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
#include <expr.h>
 | 
						|
#include <extcdecl.h>
 | 
						|
#include <relation.h>
 | 
						|
#include <tabutil.h>
 | 
						|
#include <utility.h>
 | 
						|
#include <xvtility.h>
 | 
						|
#include <config.h>
 | 
						|
#include <lffiles.h>
 | 
						|
 | 
						|
// *** check if not already defined
 | 
						|
#define NOTFOUND (-1)
 | 
						|
 | 
						|
// *** maximum number of elements in a cursor working page
 | 
						|
#define CMAXELPAGE 8000
 | 
						|
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TRelationdef
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
class TRelationdef : public TObject
 | 
						|
{
 | 
						|
  // @DPRIV
 | 
						|
  friend class TRelation;
 | 
						|
 | 
						|
  const TRelation* _rel; // Relazione padre
 | 
						|
  int        _num;               // Posizione file
 | 
						|
  int        _numto;     // Posizione padre
 | 
						|
  byte       _alias;         // Alias
 | 
						|
  byte       _key;               // Chiave
 | 
						|
  TArray     _fields;        // Campi di join
 | 
						|
  TArray     _exprs;         // Condizioni di uguaglianza
 | 
						|
  TBit_array _forced;
 | 
						|
  bool       _first_match;   // primo match (ed esiste)
 | 
						|
  bool       _allow_lock;   // ?????
 | 
						|
  bool       _write_enable;
 | 
						|
 | 
						|
protected:
 | 
						|
  virtual void print_on(ostream& out) const;
 | 
						|
 | 
						|
public:
 | 
						|
  // @FPUB
 | 
						|
  int num() const { return _num; }
 | 
						|
  int link() const { return _numto; }
 | 
						|
  byte alias() const { return _alias; }
 | 
						|
  bool& write_enable() { return _write_enable; }
 | 
						|
  TRectype& load_rec(TRectype& r, const TBaseisamfile* from) const;
 | 
						|
 | 
						|
  TRelationdef(const TRelation* rel, int file, byte key,
 | 
						|
               int linkto, const char* relexprs, byte alias,
 | 
						|
               bool allow_lock, bool write_enable = FALSE);
 | 
						|
  virtual ~TRelationdef() {}
 | 
						|
};
 | 
						|
// @END
 | 
						|
 | 
						|
 | 
						|
HIDDEN ostream& print_name(ostream& out, const TLocalisamfile* f)
 | 
						|
{
 | 
						|
  const int logicnum = f->num();
 | 
						|
  if (logicnum == LF_TABCOM || logicnum == LF_TAB)
 | 
						|
  {
 | 
						|
    if (logicnum == LF_TABCOM) out << '%';
 | 
						|
    out << ((TTable*)f)->name();
 | 
						|
  }
 | 
						|
  else
 | 
						|
    out << logicnum;
 | 
						|
  return out;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TRelationdef::TRelationdef(const TRelation* rel, int idx_file, byte key, 
 | 
						|
                           int idx_to, const char* relexprs, byte alias,
 | 
						|
                           bool allow_lock, bool write_enable)
 | 
						|
: _num(idx_file), _key(key), _numto(idx_to),
 | 
						|
  _rel(rel), _fields(4), _exprs(4), _alias(alias),
 | 
						|
  _first_match(FALSE), _allow_lock(allow_lock),
 | 
						|
  _write_enable(write_enable)
 | 
						|
{
 | 
						|
  TToken_string rels(relexprs);
 | 
						|
  int i = 0;
 | 
						|
  TString80 r,s;
 | 
						|
  
 | 
						|
  for (const char* g = rels.get(); g; g = rels.get(), i++)
 | 
						|
  {
 | 
						|
    r = g;
 | 
						|
    int   eq = r.find('=');
 | 
						|
 | 
						|
    CHECKS(eq > 0, "Ahoo! E l'uguale 'ndo sta'? ", (const char*)g);
 | 
						|
 | 
						|
    s = r.left(eq);     // Parte a sinistra dell' =
 | 
						|
 | 
						|
#ifdef DBG
 | 
						|
    TString80 n(s);
 | 
						|
    const int p = n.find('[');
 | 
						|
    if (p > 0) n.cut(p);
 | 
						|
    if (rel->file(_num)->curr().exist(n) == FALSE)
 | 
						|
    {
 | 
						|
      error_box("'%s' non e' un campo del file %d",
 | 
						|
                (const char*)n, rel->file(_num)->num());
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
#endif   
 | 
						|
 | 
						|
    if (r[eq+1] == '=')
 | 
						|
    {
 | 
						|
      _forced.set(i);
 | 
						|
      eq++;
 | 
						|
    }
 | 
						|
    
 | 
						|
    const TString80 xx(s);
 | 
						|
    _fields.add(new TFieldref(xx,0));
 | 
						|
 | 
						|
    _exprs.add(new TExpression(r.mid(eq+1), _strexpr));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void TRelationdef::print_on(ostream& out) const
 | 
						|
{
 | 
						|
  out << "JOIN "; print_name(out, _rel->file(_num));
 | 
						|
 | 
						|
  if (_numto > 0)
 | 
						|
  {
 | 
						|
    out << " TO ";
 | 
						|
    const int alias = _rel->reldef(_numto-1)->alias();
 | 
						|
    if (alias > 0) out << alias << '@';
 | 
						|
    else print_name(out, _rel->file(_numto));
 | 
						|
  }
 | 
						|
 | 
						|
  if (_key > 1) out << " KEY " << (int)_key;
 | 
						|
 | 
						|
  if (_alias > 0) out << " ALIAS " << (int)_alias;
 | 
						|
 | 
						|
  for (int i = 0; i < _fields.items(); i++)
 | 
						|
  {
 | 
						|
    if (i == 0) out << " INTO";
 | 
						|
    out << ' ' << _fields[i] << '=' << _exprs[i];
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TRelation
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
TRelation::TRelation(int logicnum, bool linkrecinst)
 | 
						|
: _files(4) , _reldefs(4), _errors(NOERR)
 | 
						|
{
 | 
						|
  TLocalisamfile* f = new TLocalisamfile(logicnum, linkrecinst);
 | 
						|
  _files.add(f);
 | 
						|
}
 | 
						|
 | 
						|
TRelation::TRelation(const char* tabname, bool linkrecinst)
 | 
						|
: _files(4) , _reldefs(4), _errors(NOERR)
 | 
						|
{
 | 
						|
  TTable* t = new TTable(tabname, linkrecinst);
 | 
						|
  _files.add(t);
 | 
						|
}
 | 
						|
 | 
						|
TRelation::~TRelation()
 | 
						|
{}
 | 
						|
 | 
						|
void TRelation::print_on(ostream& out) const
 | 
						|
{
 | 
						|
  const TLocalisamfile* f = file();
 | 
						|
 | 
						|
  out << "USE "; print_name(out, f);
 | 
						|
 | 
						|
  const int k = f->getkey();
 | 
						|
  if (k > 1) out << " KEY " << k;
 | 
						|
  out << endl;
 | 
						|
 | 
						|
  for (int r = 0; r < _reldefs.items(); r++)
 | 
						|
    out << _reldefs[r] << endl;
 | 
						|
}
 | 
						|
 | 
						|
void TRelation::restore_status()
 | 
						|
{
 | 
						|
  _status.restart();
 | 
						|
  for (int i = 0; i < _files.items(); i++)
 | 
						|
  {
 | 
						|
    int err   = _status.get_int();
 | 
						|
    int recno = _status.get_int();
 | 
						|
    if (recno >= 0l) file(i)->readat(recno);  
 | 
						|
    else file(i)->curr().zero();
 | 
						|
    file(i)->setstatus(err);
 | 
						|
  }
 | 
						|
  for (i = 0; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    bool first_match = _status.get_int ();
 | 
						|
    reldef(i)->_first_match = first_match;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TRelation::save_status()
 | 
						|
{
 | 
						|
  _status.cut(0);
 | 
						|
  for (int i = 0; i < _files.items(); i++)
 | 
						|
  {
 | 
						|
    int err   = file(i)->status();
 | 
						|
    TRecnotype recno = file(i)->eof() ? -1l : file(i)->recno();
 | 
						|
    _status.add (format ("%d",err));
 | 
						|
    _status.add (format ("%d",recno));
 | 
						|
  }
 | 
						|
  for (i = 0; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    bool first_match = reldef(i)->_first_match;
 | 
						|
    _status.add (format ("%d",first_match));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int TRelation::log2ind(int log) const
 | 
						|
{
 | 
						|
  // returns _files index of logical number or
 | 
						|
  // NOTFOUND if not present
 | 
						|
  // sets error status
 | 
						|
 | 
						|
  if (log < 0) return alias2ind(byte(-log));
 | 
						|
  
 | 
						|
  const int num = _files.items();
 | 
						|
  if (log > 0)
 | 
						|
  {
 | 
						|
    for (int i = 0; i < num; i++)
 | 
						|
      if (file(i)->num() == log) return i;
 | 
						|
  }
 | 
						|
  return num ? 0 : NOTFOUND;
 | 
						|
}
 | 
						|
 | 
						|
int TRelation::alias2ind(byte alias) const
 | 
						|
{
 | 
						|
  if (alias < 1) return 0;
 | 
						|
  
 | 
						|
  for (int i = 0; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    const TRelationdef& r = (const TRelationdef&)_reldefs[i];
 | 
						|
    if (r.alias() == alias) return r.num();
 | 
						|
  }
 | 
						|
  
 | 
						|
  return NOTFOUND;
 | 
						|
}
 | 
						|
 | 
						|
int TRelation::name2ind(const char* name) const
 | 
						|
{
 | 
						|
  const int num = name2log(name);
 | 
						|
  const int ind = log2ind(num);
 | 
						|
  return ind;
 | 
						|
}
 | 
						|
 | 
						|
TLocalisamfile* TRelation::lfile(int logicnum) const
 | 
						|
{
 | 
						|
  const int idx = log2ind(logicnum);
 | 
						|
  CHECKD(idx != NOTFOUND, "File not found n. ", logicnum);
 | 
						|
  return (TLocalisamfile*)_files.objptr(idx);
 | 
						|
}
 | 
						|
 | 
						|
TLocalisamfile* TRelation::lfile(const char* name) const
 | 
						|
{
 | 
						|
  const int idx = name2ind(name);
 | 
						|
  CHECKS(idx != NOTFOUND, "File or Table not found:", name);
 | 
						|
  return (TLocalisamfile*)_files.objptr(idx);
 | 
						|
}
 | 
						|
 | 
						|
void TRelation::write_enable(int logicnum, const bool on)
 | 
						|
 | 
						|
{
 | 
						|
  if (logicnum == - 1)     
 | 
						|
  {
 | 
						|
    for (int i = 0; i < _reldefs.items(); i++)
 | 
						|
      reldef(i)->write_enable() = on;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    const int idx = log2ind(logicnum);
 | 
						|
    CHECKD(idx != NOTFOUND, "File not found n. ", logicnum);
 | 
						|
    reldef(idx)->write_enable() = on;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TRelation::write_enable(const char* name, const bool on)
 | 
						|
 | 
						|
{
 | 
						|
  const int idx = name2ind(name);
 | 
						|
  CHECKS(idx != NOTFOUND, "File or Table not found:", name);
 | 
						|
  reldef(idx)->write_enable() = on;
 | 
						|
}
 | 
						|
 | 
						|
bool TRelation::add(int logicnum, const char* relexprs, int key,
 | 
						|
                    int linkto, byte alias, bool allow_lock)
 | 
						|
{
 | 
						|
  const int idxto = log2ind(linkto);
 | 
						|
  if (idxto == NOTFOUND)
 | 
						|
    fatal_box("Can't join file %d to %d", logicnum, linkto);
 | 
						|
  
 | 
						|
  int idx = log2ind(logicnum);
 | 
						|
  TLocalisamfile* f = new TLocalisamfile(logicnum, idx == NOTFOUND);
 | 
						|
  idx = _files.add(f);
 | 
						|
  
 | 
						|
  if (relexprs && *relexprs)
 | 
						|
  {
 | 
						|
    TRelationdef* r = new TRelationdef(this, idx, key, idxto,
 | 
						|
                                       relexprs, alias, allow_lock);
 | 
						|
    _reldefs.add(r);
 | 
						|
  }
 | 
						|
  return _errors;
 | 
						|
}
 | 
						|
 | 
						|
bool TRelation::add(const char* tabname, const char* relexprs, int key,
 | 
						|
                    int linkto, byte alias, bool allow_lock)
 | 
						|
  
 | 
						|
{
 | 
						|
  // look for <to> file
 | 
						|
  const int idxto = log2ind(linkto);
 | 
						|
  if (idxto == NOTFOUND)
 | 
						|
    fatal_box("Can't link to file no. %d", linkto);
 | 
						|
  
 | 
						|
  int idx = name2ind(tabname);
 | 
						|
  TTable* f = new TTable(tabname, idx == NOTFOUND);
 | 
						|
  idx = _files.add(f);
 | 
						|
  
 | 
						|
  if (relexprs && *relexprs)
 | 
						|
  {
 | 
						|
    TRelationdef* r = new TRelationdef(this, idx, key, idxto,
 | 
						|
                                       relexprs, alias, allow_lock);
 | 
						|
    _reldefs.add(r);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return _errors;
 | 
						|
}
 | 
						|
 | 
						|
TRectype& TRelationdef::load_rec(TRectype& r, const TBaseisamfile* from) const
 | 
						|
{
 | 
						|
  r.zero();
 | 
						|
 | 
						|
  for (int j = 0 ; j < _fields.items(); j++) // for each field
 | 
						|
  {
 | 
						|
    //  TString& s = (TString&) _fields[j];
 | 
						|
    //  r.put(s, from->get(s));
 | 
						|
    TFieldref& s = (TFieldref&) _fields[j];
 | 
						|
    s.write(s.read(from->curr()),r);
 | 
						|
    //                r.put(s.name(), s.read(from->curr()));
 | 
						|
  }
 | 
						|
 | 
						|
  return r;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void TRelation::zero()
 | 
						|
{
 | 
						|
  for (int i = 0; i < _files.items(); i++)
 | 
						|
    file(i)->zero();
 | 
						|
}
 | 
						|
 | 
						|
int TRelation::position_rels(TIsamop op, TReclock lockop,
 | 
						|
                             TDate& atdate, int first)
 | 
						|
{
 | 
						|
  _errors = NOERR;
 | 
						|
 | 
						|
  // workhorse: position files for each active relation
 | 
						|
  for (int i = first; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    TRelationdef& rd     = *reldef(i);
 | 
						|
    TLocalisamfile* from = file(rd.num());
 | 
						|
    TLocalisamfile* to   = file(rd.link());
 | 
						|
    TReclock lck = rd._allow_lock ? lockop : _nolock;
 | 
						|
 | 
						|
    if (to->curr().empty())
 | 
						|
    { from->zero(); continue; }
 | 
						|
 | 
						|
    from->setkey(rd._key);
 | 
						|
    from->curr().zero();
 | 
						|
 | 
						|
    // build record
 | 
						|
    if (rd._fields.items() && rd._exprs.items())
 | 
						|
    {
 | 
						|
      for (int j = 0 ; j < rd._fields.items(); j++) // for each field
 | 
						|
      {
 | 
						|
        TExpression& expr = (TExpression&)rd._exprs[j];
 | 
						|
 | 
						|
        // setvar for every variable
 | 
						|
        for (int k = 0; k < expr.numvar(); k++)
 | 
						|
          expr.setvar(k, to->get(expr.varname(k)));
 | 
						|
 | 
						|
        // eval expression and put result in field
 | 
						|
 | 
						|
        TFieldref& s = (TFieldref&) rd._fields[j];
 | 
						|
        s.write(expr, from->curr());
 | 
						|
        //      TString& s = (TString&) rd._fields[j];
 | 
						|
        //      from->put(s, (const char*)expr);
 | 
						|
      } // for each field
 | 
						|
    }
 | 
						|
 | 
						|
    // read record: if not found, empty current record
 | 
						|
    TRectype rec(from->curr());
 | 
						|
    from->read(op, lck, atdate);
 | 
						|
    if (from->bad())
 | 
						|
    {
 | 
						|
      rd._first_match = (from->curr() == rec);
 | 
						|
      if (rd._first_match)
 | 
						|
      {
 | 
						|
        bool eq = TRUE;
 | 
						|
 | 
						|
        for (int kk = 0; eq && kk < rd._fields.items(); kk++)
 | 
						|
        {
 | 
						|
          if (rd._forced[kk])
 | 
						|
          {
 | 
						|
            //  TString& fl = (TString&)rd._fields[kk];
 | 
						|
            //  const TString f_fr(from->curr().get(fl));
 | 
						|
 | 
						|
            TFieldref& fl = (TFieldref&)rd._fields[kk];
 | 
						|
            const TString f_fr(fl.read(from->curr()));
 | 
						|
 | 
						|
            //                  const TFixed_string f_to(to->curr().get(fl));
 | 
						|
            //                          eq = (f_fr == f_to);
 | 
						|
            TExpression& expr = (TExpression&)rd._exprs[kk];
 | 
						|
            for (int k = 0; k < expr.numvar(); k++)
 | 
						|
              expr.setvar(k, to->get(expr.varname(k)));
 | 
						|
            eq = (f_fr == (const char*)expr);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (eq) from->setstatus(NOERR);
 | 
						|
        else    { rd._first_match = FALSE; from->curr().zero(); }
 | 
						|
      }
 | 
						|
      else from->curr().zero();
 | 
						|
    }
 | 
						|
    else rd._first_match = TRUE;
 | 
						|
  } // for each relation
 | 
						|
  return _errors;
 | 
						|
}
 | 
						|
 | 
						|
bool TRelation::next_match(int logicnum, const char* fieldlist, int nkey)
 | 
						|
{
 | 
						|
  if (logicnum == file()->num())
 | 
						|
  {
 | 
						|
    next();
 | 
						|
    return file()->good();
 | 
						|
  }
 | 
						|
  
 | 
						|
  const int i = log2ind(logicnum);
 | 
						|
  CHECKD(i != NOTFOUND,"Nonexistent file referenced in relation ",logicnum);
 | 
						|
  
 | 
						|
  for (int j = 0; j < _reldefs.items(); j++)
 | 
						|
    if (reldef(j)->num() == i) break;
 | 
						|
  
 | 
						|
  TLocalisamfile* from = file(i);
 | 
						|
  TLocalisamfile* to = file(reldef(j)->link());
 | 
						|
 | 
						|
  reldef(j)->_first_match = FALSE;
 | 
						|
 | 
						|
  if (from->bad())
 | 
						|
    return FALSE; // && vaffanculo()
 | 
						|
 | 
						|
  const TRecnotype last = from->recno();
 | 
						|
  
 | 
						|
  bool ok = TRUE; // Corrispondenza trovata ?
 | 
						|
  
 | 
						|
  if (fieldlist == NULL)
 | 
						|
  {
 | 
						|
    TRectype rec(from->curr());
 | 
						|
    reldef(j)->load_rec(rec, from);
 | 
						|
    from->setkey(reldef(j)->_key);
 | 
						|
    from->next();
 | 
						|
    
 | 
						|
    ok = (from->good() && from->curr() == rec);     
 | 
						|
    for (int kk = 0; ok && kk < reldef(j)->_fields.items(); kk++)
 | 
						|
    {
 | 
						|
      if (reldef(j)->_forced[kk])
 | 
						|
      {
 | 
						|
        //            TString& fl = (TString&)reldef(j)->_fields[kk];
 | 
						|
        //            const TFixed_string f_fr(from->curr().get(fl));
 | 
						|
        //            const TFixed_string f_to(to->curr().get(fl));
 | 
						|
        TFieldref& fl = (TFieldref&)reldef(j)->_fields[kk];
 | 
						|
        const TFixed_string f_fr(fl.read(from->curr()));
 | 
						|
        const TFixed_string f_to(fl.read(to->curr()));
 | 
						|
        
 | 
						|
        ok = (f_fr == f_to);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (ok) from->setstatus(NOERR);
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if (nkey > 0)
 | 
						|
      from->setkey(nkey);
 | 
						|
    TToken_string fields(fieldlist);
 | 
						|
    TToken_string old(80);
 | 
						|
    for (const char* f = fields.get(0); f; f = fields.get())
 | 
						|
      old.add(from->curr().get(f));
 | 
						|
    
 | 
						|
    from->next();
 | 
						|
    
 | 
						|
    old.restart();
 | 
						|
 | 
						|
 | 
						|
    for (f = fields.get(0); f && ok; f = fields.get())
 | 
						|
    {
 | 
						|
      const TFixed_string v(from->curr().get(f));
 | 
						|
      const char* o = old.get();
 | 
						|
      if (v != o)
 | 
						|
        ok = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (!ok)
 | 
						|
  {
 | 
						|
    from->readat(last);
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  // Riposiziona gli eventuali files successivi
 | 
						|
  position_rels(_isequal, _nolock, (TDate&)botime, j+1);
 | 
						|
  reldef(j)->_first_match = FALSE;
 | 
						|
 | 
						|
  return ok;
 | 
						|
}
 | 
						|
 | 
						|
bool TRelation::is_first_match(int logicnum)
 | 
						|
  // TRUE se c'e' un record ed e' il primo match (non si e' mai fatta
 | 
						|
  // position_rels)
 | 
						|
{
 | 
						|
  const int i = log2ind(logicnum);
 | 
						|
  CHECKD(i != NOTFOUND,"Nonexistent file referenced in relation ",logicnum);
 | 
						|
  
 | 
						|
  for (int j = 0; j < _reldefs.items(); j++)
 | 
						|
    if (reldef(j)->num() == i) return reldef(j)->_first_match;
 | 
						|
  const int err = file()->status();
 | 
						|
  return err == NOERR;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef DBG
 | 
						|
 | 
						|
bool TRelation::isconsistent(bool reset)
 | 
						|
{
 | 
						|
  const int MAXREL = 24;
 | 
						|
  int bad = 0;
 | 
						|
  TRecnotype recnos[MAXREL];
 | 
						|
  
 | 
						|
  for (int i = 0; i < _files.items() && i < MAXREL; i++)
 | 
						|
  {
 | 
						|
    // must be file OK, non-empty record
 | 
						|
    bad |= file(i)->good() ||  file(i)->curr().empty();
 | 
						|
    recnos[i] = file(i)->recno();
 | 
						|
  }
 | 
						|
  
 | 
						|
  // if the above hold, check consistency
 | 
						|
  if (bad)
 | 
						|
    return _errors = bad;
 | 
						|
  
 | 
						|
  position_rels(_isequal, _nolock, (TDate&)botime);
 | 
						|
  for (i = 0; i < _files.items(); i++)
 | 
						|
    if (file(i)->recno() != recnos[i])
 | 
						|
    {
 | 
						|
      bad = -1;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (reset == FALSE)
 | 
						|
    // leave as before
 | 
						|
    for(i = 0; i < _files.items(); i++)
 | 
						|
      file(i)->readat(recnos[i]);
 | 
						|
  
 | 
						|
  return this->_errors = bad;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
int TRelation::write(bool force, TDate& atdate)
 | 
						|
{
 | 
						|
  _errors = NOERR;
 | 
						|
  
 | 
						|
  if (file(0)->curr().empty())
 | 
						|
    return _errors; // *** no error returned **
 | 
						|
  // programmer must be aware
 | 
						|
  
 | 
						|
  if ((_errors = file(0)->write(atdate)) != NOERR)
 | 
						|
    return _errors;
 | 
						|
  
 | 
						|
  
 | 
						|
  for (int i = 0; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    TRelationdef& rd     = *reldef(i);
 | 
						|
    const int log                        = rd.num();
 | 
						|
 | 
						|
    if (!rd.write_enable() ||
 | 
						|
        (file(log)->curr()).empty()) continue;
 | 
						|
 | 
						|
    int res = file(log)->write(atdate);
 | 
						|
    if (force && res == _isreinsert)
 | 
						|
      res = file(log)->rewrite(atdate);
 | 
						|
    if (_errors == NOERR) _errors = res;
 | 
						|
  }
 | 
						|
  return _errors;
 | 
						|
}
 | 
						|
 | 
						|
int TRelation::rewrite(bool force, TDate& atdate)
 | 
						|
{
 | 
						|
  _errors = file(0)->rewrite(atdate);                // Riscrive testata
 | 
						|
  if (force && _errors == _iskeynotfound)            // Se non la trova ...
 | 
						|
    _errors = file(0)->write(atdate);                // ... forza la scrittura
 | 
						|
 | 
						|
  for (int i = 0; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    TRelationdef& rd     = *reldef(i);
 | 
						|
    const int log                        = rd.num();
 | 
						|
 | 
						|
    if (!rd.write_enable() ||
 | 
						|
        (file(log)->curr()).empty()) continue;
 | 
						|
    
 | 
						|
    int res = file(log)->rewrite(atdate);
 | 
						|
    if (force && res == _iskeynotfound)
 | 
						|
      res = file(log)->write(atdate);
 | 
						|
    if (_errors == NOERR) _errors = res;
 | 
						|
  }
 | 
						|
 | 
						|
  return _errors;
 | 
						|
}
 | 
						|
 | 
						|
int TRelation::remove(TDate& atdate)
 | 
						|
{
 | 
						|
  const int res = file(0)->remove(atdate);
 | 
						|
  if (_errors == NOERR && res != _iskeynotfound) _errors = res;
 | 
						|
  for (int i = 0; i < _reldefs.items(); i++)
 | 
						|
  {
 | 
						|
    TRelationdef& rd     = *reldef(i);
 | 
						|
    const int log                        = rd.num();
 | 
						|
 | 
						|
    if (!rd.write_enable() ||
 | 
						|
        (file(log)->curr()).empty()) continue;
 | 
						|
 | 
						|
    const int res = file(log)->remove(atdate);
 | 
						|
    if (_errors == NOERR && res != _iskeynotfound) _errors = res;
 | 
						|
  }
 | 
						|
  return _errors;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TCursor
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
 | 
						|
HIDDEN bool __evalcondition(const TRectype& r,TExpression* cond)
 | 
						|
 | 
						|
{
 | 
						|
  for (int i = 0; i < cond->numvar(); i++)
 | 
						|
  {
 | 
						|
    const char* s = cond->varname(i);
 | 
						|
    //          if (cond->type() == _numexpr)
 | 
						|
    //          {
 | 
						|
    //                  real n(r.get(s));
 | 
						|
    //                  cond->setvar(i, n);
 | 
						|
    //          }
 | 
						|
    //          else
 | 
						|
    cond->setvar(i, r.get(s));
 | 
						|
  }
 | 
						|
  return (bool) *cond;
 | 
						|
}
 | 
						|
 | 
						|
FILE* TCursor::open_index(bool create) const
 | 
						|
{
 | 
						|
#if XVT_OS == XVT_OS_SCOUNIX
 | 
						|
  const char* const r = "r";
 | 
						|
  const char* const w = "w";
 | 
						|
#else
 | 
						|
  const char* const r = "rb";
 | 
						|
  const char* const w = "wb";
 | 
						|
#endif
 | 
						|
 | 
						|
  FILE* f = fopen(_indexname, create ? w : r);
 | 
						|
  if (f == NULL)
 | 
						|
    fatal_box("Can't use cursor index for file %d\n", file()->filehnd()->ln);
 | 
						|
 | 
						|
  return f;
 | 
						|
}
 | 
						|
 | 
						|
TRecnotype TCursor::buildcursor(TRecnotype rp)
 | 
						|
{
 | 
						|
  TRecnotype ap = 0, junkl;
 | 
						|
  char                   s[82];
 | 
						|
  int                            junk, l, pagecnt = 0;
 | 
						|
  Page                   p;
 | 
						|
  int                    pos;
 | 
						|
  const int  kl = file()->filehnd()->i.Base[file()->filehnd()->i.PN].KeyLen;
 | 
						|
  const bool filtered = has_filter();
 | 
						|
 | 
						|
  if (file()->filehnd()->i.Base[file()->filehnd()->i.PN].PEOD == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  FILE* _f = open_index(TRUE);
 | 
						|
  fseek(_f, 0L, SEEK_SET);
 | 
						|
 | 
						|
  l = strlen(to());
 | 
						|
  BTrRead(&file()->filehnd()->i, (char*)(const char*) from(), s, &junkl, &junk);
 | 
						|
  if (junk == _iseof) return 0;
 | 
						|
 | 
						|
  TRecnotype* page = new TRecnotype [CMAXELPAGE];
 | 
						|
 | 
						|
  if (GetAPage(&file()->filehnd()->i, &p, file()->filehnd()->i.CurPag, &junk) != NOERR)
 | 
						|
    fatal_box("Can't read index n. %d - file n. %d", file()->filehnd()->i.PN + 1, file()->filehnd()->ln);
 | 
						|
 | 
						|
  pos = file()->filehnd()->i.Pos - 1;
 | 
						|
  _pos = -1;
 | 
						|
  while (TRUE)
 | 
						|
  {
 | 
						|
    if (pos >= p.PA.PageHeader.NKey)
 | 
						|
    {
 | 
						|
      if (p.PA.PageHeader.Next == -1L) break;
 | 
						|
      file()->filehnd()->i.CurPag = p.PA.PageHeader.Next;
 | 
						|
      if (GetAPage(&file()->filehnd()->i, &p, file()->filehnd()->i.CurPag, &junk) != NOERR)
 | 
						|
        fatal_box("Can't read index n. %d - file n. %d", file()->filehnd()->i.PN + 1, file()->filehnd()->ln);
 | 
						|
      pos = 0;
 | 
						|
    }
 | 
						|
    const char* s0 = p.PA.AreaForKey + pos++ * (kl + 4);
 | 
						|
    if (l && (strncmp(to(), s0, l) < 0)) break;
 | 
						|
 | 
						|
    if (pagecnt == CMAXELPAGE)
 | 
						|
    {
 | 
						|
      if (filtered) pagecnt = filtercursor(pagecnt, page);
 | 
						|
      fwrite(page, sizeof(junkl), pagecnt, _f);
 | 
						|
      if (pos == -1)
 | 
						|
        for (int i = 0; i < pagecnt; i++)
 | 
						|
          if (page[i] == rp)
 | 
						|
          {
 | 
						|
            _pos = ap + i;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
      ap += pagecnt;
 | 
						|
      pagecnt = 0;
 | 
						|
    }
 | 
						|
    page[pagecnt++] = *((long *)(s0 + kl));
 | 
						|
  }
 | 
						|
  if (pagecnt)
 | 
						|
  {
 | 
						|
    if (filtered) pagecnt = filtercursor(pagecnt, page);
 | 
						|
    fwrite(page, sizeof(junkl), pagecnt, _f);
 | 
						|
    if (pos == -1)
 | 
						|
      for (int i = 0; i < pagecnt; i++)
 | 
						|
        if (page[i] == rp)
 | 
						|
        {
 | 
						|
          _pos = ap + i;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
    ap += pagecnt;
 | 
						|
  }
 | 
						|
  if (_pos == -1 ) pos = 0;
 | 
						|
  delete page;
 | 
						|
 | 
						|
  fclose(_f);
 | 
						|
  return ap;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int TCursor::filtercursor(int pagecnt, TRecnotype* page)
 | 
						|
 | 
						|
{
 | 
						|
  int np = 0;
 | 
						|
  TRectype& rec = file()->curr();
 | 
						|
  const bool tab = file()->tab();
 | 
						|
  if (tab)
 | 
						|
  {
 | 
						|
    file()->filehnd()->r->Fd[0].RecOff += 3;
 | 
						|
    file()->filehnd()->r->Fd[0].Len -= 3;
 | 
						|
  }
 | 
						|
  //      TRecfield*    codtab = tab ? new TRecfield(rec, "CODTAB") : NULL;
 | 
						|
  for (int i = 0; i < pagecnt; i++)
 | 
						|
  {
 | 
						|
    CRead(&file()->filehnd()->f, rec.string(), page[i], _nolock);
 | 
						|
    //  if (tab)                *codtab = (const char*)(*codtab) + 3;
 | 
						|
    if ((_filterfunction ? _filterfunction(_if) : TRUE ) &&
 | 
						|
        (_fexpr ? __evalcondition(rec, _fexpr) : TRUE))
 | 
						|
    {
 | 
						|
      if (np < i) page[np] = page[i];
 | 
						|
      np++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (tab)
 | 
						|
  {
 | 
						|
    file()->filehnd()->r->Fd[0].RecOff -= 3;
 | 
						|
    file()->filehnd()->r->Fd[0].Len += 3;
 | 
						|
  }
 | 
						|
  // if (tab) delete codtab;
 | 
						|
  return np;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool TCursor::ok() const
 | 
						|
 | 
						|
{
 | 
						|
  if (file()->bad()) return FALSE;
 | 
						|
 | 
						|
  const TRectype& rec = file()->curr();
 | 
						|
  TString       key(rec.key(_nkey)), kf(from()), kt(to());
 | 
						|
  if (file()->tab())
 | 
						|
  {
 | 
						|
    kf.ltrim(3);
 | 
						|
    kt.ltrim(3);
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (key < kf || (kt.not_empty() && kt < key.left(kt.len())))
 | 
						|
    return FALSE;
 | 
						|
  if ((_filterfunction ? _filterfunction(_if) : TRUE ) &&
 | 
						|
      (_fexpr ? __evalcondition(rec, _fexpr) : TRUE))
 | 
						|
    return TRUE;
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
bool TCursor::changed()
 | 
						|
 | 
						|
{
 | 
						|
  isdef* fh = file()->filehnd();
 | 
						|
 | 
						|
  if (_frozen && _lastrec != 0L) return _filename != fh->f.name;
 | 
						|
 | 
						|
#if XVT_OS==XVT_OS_SCOUNIX
 | 
						|
  const TRecnotype eod = file()->eod();
 | 
						|
#else
 | 
						|
  int   junk = 0;
 | 
						|
  const TRecnotype eod = cisgeteod(fh, &junk);
 | 
						|
  //    GetHead(&fh->i, _nolock, &junk);
 | 
						|
#endif
 | 
						|
 | 
						|
  if (_lastrec != eod ||
 | 
						|
      (_lastkrec != fh->i.Base[_nkey -1].PEOD) ||
 | 
						|
      (_filename != fh->f.name))
 | 
						|
  {
 | 
						|
    _lastrec = eod;
 | 
						|
    _lastkrec = fh->i.Base[_nkey -1].PEOD;
 | 
						|
    _filename = fh->f.name;
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
  else return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
TRecnotype TCursor::update()
 | 
						|
 | 
						|
{
 | 
						|
  file()->setkey(_nkey);
 | 
						|
  file()->read(_isgteq);
 | 
						|
 | 
						|
  const CURSOR old = get_cursor(TASK_WIN);
 | 
						|
  set_cursor(TASK_WIN, CURSOR_WAIT);
 | 
						|
 | 
						|
  TRecnotype totrec = buildcursor(file()->recno());
 | 
						|
  // if (has_filter()) totrec = filtercursor();
 | 
						|
 | 
						|
  set_cursor(TASK_WIN, old);
 | 
						|
 | 
						|
  return totrec;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void TCursor::filter(const char* filter, const TRectype *from,
 | 
						|
                     const TRectype* to)
 | 
						|
 | 
						|
{
 | 
						|
  CHECK(!_frozen, "Impossibile filtrare un cursore congelato");
 | 
						|
 | 
						|
  TString kf(_keyfrom), kto(_keyto), kfilter, tbpref;
 | 
						|
 | 
						|
  if (filter)
 | 
						|
    kfilter << filter;
 | 
						|
 | 
						|
  bool  filterchanged = (filter != NULL) && (_filter != kfilter);
 | 
						|
 | 
						|
  if (file()->tab())
 | 
						|
  {
 | 
						|
    TTable& f = (TTable&) *file();
 | 
						|
    tbpref = f.name();
 | 
						|
  }
 | 
						|
  if (from != NULL)
 | 
						|
  {
 | 
						|
    kf = tbpref;
 | 
						|
    kf << from->key(_nkey);
 | 
						|
    int p;
 | 
						|
    while ((p = kf.find('~')) != -1) kf[p] = ' ';
 | 
						|
  }
 | 
						|
  if (to != NULL)
 | 
						|
  {
 | 
						|
    kto = tbpref;
 | 
						|
    kto << to->key(_nkey);
 | 
						|
    int p;
 | 
						|
    while ((p = kto.find('~')) != -1) kto[p] = ' ';
 | 
						|
  }
 | 
						|
  if (filterchanged || (_keyfrom != kf) || (_keyto != kto))
 | 
						|
  {
 | 
						|
    _pos = 0;
 | 
						|
    _totrec = 0;
 | 
						|
    _lastrec = 0;
 | 
						|
    if (filterchanged)
 | 
						|
    {
 | 
						|
      _filter = kfilter;
 | 
						|
      if (_fexpr) delete _fexpr;
 | 
						|
      TTypeexp type = (_filter.find('"') != -1) ? _strexpr : _numexpr;
 | 
						|
      if (_filter.not_empty())
 | 
						|
      {
 | 
						|
        _fexpr = new TExpression(_filter, type);
 | 
						|
        if (_fexpr->type() == _numexpr)
 | 
						|
          for (int i = 0 ; i < _fexpr->numvar(); i++)
 | 
						|
            if (file()->curr().type(_fexpr->varname(i)) == _alfafld)
 | 
						|
            {
 | 
						|
              _fexpr->set_type(_strexpr);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
      }
 | 
						|
      else _fexpr = NULL;
 | 
						|
    }
 | 
						|
    file()->setkey(_nkey);
 | 
						|
    _keyfrom = kf;
 | 
						|
    _keyto = kto;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TCursor::setkey(int nkey)
 | 
						|
 | 
						|
{
 | 
						|
  if (nkey != _nkey)
 | 
						|
  {
 | 
						|
    _lastrec = 0L;
 | 
						|
    _nkey = nkey;
 | 
						|
    file()->setkey(_nkey);
 | 
						|
    filter(NULL);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TRecnotype TCursor::read(TIsamop op, TReclock lockop, TDate& atdate)
 | 
						|
{
 | 
						|
  TRecnotype *page;
 | 
						|
  int                            pagecnt;
 | 
						|
 | 
						|
  file()->setkey(_nkey);
 | 
						|
  _if->file()->read(op, lockop, atdate);
 | 
						|
  const TRecnotype curpos = file()->recno();
 | 
						|
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
 | 
						|
  FILE* _f = open_index();
 | 
						|
 | 
						|
  if (fseek(_f, 0L, SEEK_SET) != 0)
 | 
						|
    fatal_box("Can't repos cursor : File %d\n", file()->filehnd()->ln);
 | 
						|
 | 
						|
  page = new TRecnotype [CMAXELPAGE];
 | 
						|
  _pos = -1;
 | 
						|
 | 
						|
  for (TRecnotype max = _totrec; _pos == -1 && max > 0; max -= pagecnt)
 | 
						|
  {
 | 
						|
    pagecnt = (max < CMAXELPAGE) ? (int)max : CMAXELPAGE;
 | 
						|
    fread(page, sizeof(TRecnotype), pagecnt, _f);
 | 
						|
    for (int i = 0; i < pagecnt; i++)
 | 
						|
      if (page[i] == curpos)
 | 
						|
      {
 | 
						|
        _pos = _totrec - max + i;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
  }
 | 
						|
  if (_pos == -1) _pos = 0;
 | 
						|
  delete page;
 | 
						|
  fclose(_f);
 | 
						|
 | 
						|
  readrec();
 | 
						|
  return _pos;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TCursor::TCursor(TRelation* r, const char* filter, int nkey, TRectype *from, TRectype* to)
 | 
						|
: _frozen(FALSE), _filterfunction(NULL)
 | 
						|
 | 
						|
{
 | 
						|
  _if = r;
 | 
						|
  _nkey = nkey;
 | 
						|
  CHECKD(_nkey > 0 && _nkey <= file()->filehnd()->r->NKeys, "Bad key number : ", _nkey);
 | 
						|
  _indexname.temp("ci");
 | 
						|
 | 
						|
  /*
 | 
						|
     #if XVT_OS==XVT_OS_SCOUNIX
 | 
						|
     _f = fopen(_indexname, "w+");
 | 
						|
     #else
 | 
						|
     _f = fopen(_indexname, "wb+");
 | 
						|
     #endif
 | 
						|
     if (_f == NULL)
 | 
						|
     fatal_box("Can't create cursor index on file %d: %s",
 | 
						|
     file()->num(), strerror(errno));
 | 
						|
     */
 | 
						|
  FILE* _f = open_index(TRUE);
 | 
						|
  fclose(_f);
 | 
						|
 | 
						|
  _pos = 0;
 | 
						|
  _totrec = 0;
 | 
						|
  _lastrec = 0;
 | 
						|
  _lastkrec = 0;
 | 
						|
  _filter << filter;
 | 
						|
  TTypeexp type = (_filter.find('"') != -1) ? _strexpr : _numexpr;
 | 
						|
  if (_filter.not_empty())
 | 
						|
  {
 | 
						|
    _fexpr = new TExpression(_filter, type);
 | 
						|
    if (_fexpr->type() == _numexpr)
 | 
						|
      for (int i = 0 ; i < _fexpr->numvar(); i++)
 | 
						|
        if (file()->curr().type(_fexpr->varname(i)) == _alfafld)
 | 
						|
        {
 | 
						|
          _fexpr->set_type(_strexpr);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
  }
 | 
						|
  else _fexpr = NULL;
 | 
						|
  file()->setkey(_nkey);
 | 
						|
  if (file()->tab())
 | 
						|
  {
 | 
						|
    TTable& f = (TTable&) *file();
 | 
						|
    _keyfrom = _keyto = f.name();
 | 
						|
  }
 | 
						|
  if (from != NULL)
 | 
						|
  {
 | 
						|
    _keyfrom << from->key(_nkey);
 | 
						|
    int p;
 | 
						|
    while ((p = _keyfrom.find('~')) != -1) _keyfrom[p] = ' ';
 | 
						|
  }
 | 
						|
  if (to != NULL)
 | 
						|
  {
 | 
						|
    _keyto << to->key(_nkey);
 | 
						|
    int p;
 | 
						|
    while ((p = _keyto.find('~')) != -1) _keyto[p] = ' ';
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TCursor::~TCursor()
 | 
						|
 | 
						|
{
 | 
						|
  //    fclose(_f);
 | 
						|
  ::remove(_indexname);
 | 
						|
  if (_fexpr) delete _fexpr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TRecnotype TCursor::readrec()
 | 
						|
 | 
						|
{
 | 
						|
  TRecnotype& nrec = file()->filehnd()->RecNo;
 | 
						|
 | 
						|
  if (_pos == items())
 | 
						|
  {
 | 
						|
    file()->setstatus(_iseof);
 | 
						|
    curr().zero();
 | 
						|
    return nrec = 0L;
 | 
						|
  }
 | 
						|
  file()->setstatus(NOERR);
 | 
						|
 | 
						|
  FILE* _f = open_index();
 | 
						|
 | 
						|
  if ((fseek(_f, _pos * sizeof(TRecnotype), SEEK_SET) != 0) ||
 | 
						|
      (fread(&nrec, sizeof(TRecnotype), 1, _f) != 1))
 | 
						|
    fatal_box("Can't read record in file n. %d\n", file()->filehnd()->ln);
 | 
						|
 | 
						|
  fclose(_f);
 | 
						|
 | 
						|
  curr().setdirty();
 | 
						|
  CRead(&file()->filehnd()->f, curr().string(), nrec, _nolock);
 | 
						|
  if (file()->tab())
 | 
						|
  {
 | 
						|
    TRecfield   codtab(curr(), "CODTAB");
 | 
						|
    codtab = (const char*)codtab + 3;
 | 
						|
  }
 | 
						|
  repos();
 | 
						|
  return nrec;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TRecnotype TCursor::operator =(const TRecnotype pos)
 | 
						|
 | 
						|
{
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
  CHECKD(pos >= 0 && pos <= _totrec, "Bad cursor position : ", pos);
 | 
						|
  _pos = pos;
 | 
						|
  if (_pos > _totrec) _pos = _totrec;
 | 
						|
  readrec();
 | 
						|
  return _pos;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TCursor& TCursor::operator +=(const TRecnotype npos)
 | 
						|
 | 
						|
{
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
  _pos += npos;
 | 
						|
  if (_pos > _totrec) _pos = _totrec;
 | 
						|
  readrec();
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TCursor& TCursor::operator -=(const TRecnotype npos)
 | 
						|
 | 
						|
{
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
  _pos -= npos;
 | 
						|
  if (_pos < 0) _pos = 0;
 | 
						|
  readrec();
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TCursor& TCursor::operator ++()
 | 
						|
 | 
						|
{
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
  _pos++;
 | 
						|
  if (_pos > _totrec) _pos = _totrec;
 | 
						|
  readrec();
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TCursor& TCursor::operator --()
 | 
						|
 | 
						|
{
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
  if (_pos) _pos--;
 | 
						|
  readrec();
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TRecnotype TCursor::items()
 | 
						|
 | 
						|
{
 | 
						|
  if (changed())
 | 
						|
    _totrec = update();
 | 
						|
  return _totrec;
 | 
						|
}
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TFieldRef
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
int name2log(const char* name)
 | 
						|
{
 | 
						|
  int log = 0;
 | 
						|
 | 
						|
  if (name && *name)
 | 
						|
  {
 | 
						|
    if (isdigit(*name))
 | 
						|
    {
 | 
						|
      log = atoi(name);
 | 
						|
      if (strchr(name, '@'))    log = -log;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      const int len = strlen(name);
 | 
						|
      if (len == 3 || len == 4)
 | 
						|
        log = TTable::name2log(name);
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (log == 0)
 | 
						|
      fatal_box("'%s' non e' un file o una tabella", name);
 | 
						|
  }
 | 
						|
 | 
						|
  return log;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TFieldref::TFieldref() : _fileid(0), _name(0) {}
 | 
						|
 | 
						|
 | 
						|
TFieldref::TFieldref(const TString& s, short defid)
 | 
						|
{
 | 
						|
  operator=(s);
 | 
						|
  if (_fileid == 0) _fileid = defid;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// A Fieldref should have the following format (only NAME is mandatory):
 | 
						|
// FILE->NAME[FROM,TO]
 | 
						|
TFieldref& TFieldref::operator =(const TString& s)
 | 
						|
{
 | 
						|
  int pos = s.find("->");
 | 
						|
  if (pos > 0)
 | 
						|
  {
 | 
						|
    _id = s.left(pos); _id.strip(" ");
 | 
						|
    _fileid = name2log(_id);
 | 
						|
    pos += 2;
 | 
						|
  } else _fileid = pos = 0;
 | 
						|
  
 | 
						|
  int par = s.find('[', pos);
 | 
						|
  _name = s.sub(pos, par); _name.strip(" ");
 | 
						|
  
 | 
						|
  if (par > 0)
 | 
						|
  {
 | 
						|
    pos = par+1;
 | 
						|
    _from = atoi(&s[pos]);
 | 
						|
    if (_from > 0) _from--; else _from = 0;
 | 
						|
    par = s.find(',', pos);
 | 
						|
    if (par > 0) _to = atoi(&s[par+1]); else _to = -1;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    _from = 0;
 | 
						|
    _to = -1;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
void TFieldref::print_on(ostream& out) const
 | 
						|
{
 | 
						|
  if (_id.not_empty()) out << _id << "->";
 | 
						|
  out << _name;
 | 
						|
  if (_from > 0 || _to > 0)
 | 
						|
  {
 | 
						|
    out << '[' << (_from+1);
 | 
						|
    if (_to) out << ',' << _to;
 | 
						|
    out << ']';
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const char* TFieldref::read(const TRectype& rec) const
 | 
						|
{
 | 
						|
  static TString80 buffer;
 | 
						|
 | 
						|
  if (_fileid >= CNF_GENERAL)
 | 
						|
  {
 | 
						|
    TToken_string s(_name, '.');
 | 
						|
    TConfig c(_fileid - CNF_STUDIO, s.get());
 | 
						|
    buffer = c.get(s.get());
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    buffer = rec.get(_name);
 | 
						|
    if (_from > 0 || _to > 0)
 | 
						|
    {
 | 
						|
      const int l = buffer.len();
 | 
						|
      const int from = (_from > l) ? l : _from;
 | 
						|
      const int to = (_to > l || _to < 1) ? l : _to;
 | 
						|
      if (to < l) buffer.cut(to);
 | 
						|
      if (from > 0) buffer.ltrim(from);
 | 
						|
    } 
 | 
						|
  }
 | 
						|
  return buffer;
 | 
						|
}
 | 
						|
 | 
						|
const char* TFieldref::read(const TRelation* c) const
 | 
						|
{
 | 
						|
  const char * s;
 | 
						|
  
 | 
						|
  if (c == NULL)
 | 
						|
  {
 | 
						|
    TLocalisamfile f(_fileid);
 | 
						|
    s = read(f.curr());
 | 
						|
  }
 | 
						|
  else
 | 
						|
    s = read(c->lfile(_id)->curr());
 | 
						|
 | 
						|
  return s;
 | 
						|
}
 | 
						|
 | 
						|
void TFieldref::write(const char* val, TRelation* c) const
 | 
						|
{
 | 
						|
  TLocalisamfile* f = NULL;
 | 
						|
  TRectype* curr = NULL;
 | 
						|
 | 
						|
  if (c == NULL)
 | 
						|
  {
 | 
						|
    f = new TLocalisamfile(_fileid);
 | 
						|
    curr = &f->curr();
 | 
						|
  }
 | 
						|
  else
 | 
						|
    curr = &c->lfile(_id)->curr();
 | 
						|
 | 
						|
  write(val, *curr);
 | 
						|
  
 | 
						|
  if (f != NULL) delete f;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void TFieldref::write(const char* val, TRectype& rec) const
 | 
						|
{
 | 
						|
  if (_fileid >= CNF_GENERAL) return;
 | 
						|
  if (_from > 0)
 | 
						|
  {
 | 
						|
    TString80 campo(rec.get(_name));
 | 
						|
    campo.overwrite(val, _from);
 | 
						|
    rec.put(_name, campo);
 | 
						|
  }
 | 
						|
  else  
 | 
						|
    rec.put(_name, val);
 | 
						|
}
 | 
						|
 | 
						|
int TFieldref::len(TRectype &rec) const
 | 
						|
 | 
						|
{
 | 
						|
  if (_to >= 0) return _to - _from;
 | 
						|
  if (_fileid == 0) return rec.length(_name) - _from;
 | 
						|
  
 | 
						|
  TLocalisamfile f(_fileid);
 | 
						|
  const int len = f.curr().length(_name);
 | 
						|
  return  len - _from;
 | 
						|
}
 | 
						|
 | 
						|
bool TCursor::next_match(int lognum, const char* fl, int nk)
 | 
						|
{
 | 
						|
  if (lognum == 0 || lognum == file()->num())
 | 
						|
  {++(*this); return file()->good(); }
 | 
						|
  else return _if->next_match(lognum, fl, nk);
 | 
						|
}
 | 
						|
 | 
						|
bool TCursor::is_first_match(int ln)
 | 
						|
{
 | 
						|
  return (ln == 0 || ln == file()->num()) ?
 | 
						|
    (_pos == 0 && file()->good()) : (_if->is_first_match(ln));
 | 
						|
}
 | 
						|
 | 
						|
// *** EOF relation.cpp
 | 
						|
 |