campo-sirio/include/isam.cpp
guy 904dffc045 Cambiati leggermente i menu di default
Migliorata gestione variabili insestenti nel TConfig
Segato via _isatab dai TLocalisamfile
Cambiata la finestra di F_11 nelle maschere
Corretto errore nella TPrintrow::encoded_row() (resa pure const)
Aggiunto bottone di global un/check negli sheet


git-svn-id: svn://10.65.10.50/trunk@832 c028cbd2-c16b-5b4b-a496-9718f37d4682
1995-01-05 17:50:40 +00:00

2171 lines
42 KiB
C++
Executable File

#include <stdio.h>
#include <stdlib.h>
#define __ISAM_CPP
#ifndef FOXPRO
#include <applicat.h>
#include <expr.h>
#include <execp.h>
#include <progind.h>
#endif
#include <config.h>
#include <extcdecl.h>
#include <mailbox.h>
#include <prefix.h>
#include <relation.h>
#include <scanner.h>
#include <utility.h>
#if XVT_OS==XVT_OS_SCOUNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#else
#include <direct.h>
#include <process.h>
#endif
#define NOT_LINKED(i,f) CHECKS(i != NULL, "Record senza tracciato: impossibile eseguire ", f)
#define NOT_OPEN(f) CHECKS(_isamfile != NULL, "File chiuso: ", f)
HIDDEN void UNKNOWN_FIELD(int num, const char* name)
{ yesnofatal_box("Il campo '%s' non appartiene al file %d", name, num); }
#define NOALLOC (char **) -1
HIDDEN bool __autoload = TRUE;
void set_autoload_new_files(bool on)
{
__autoload = on;
}
class TExtrectype : public TRectype
{
public:
// FPUB
TExtrectype(const TTrec& r); // Costruisce il record a partire da r
virtual ~TExtrectype();
};
TExtrectype::TExtrectype(const TTrec& r) : TRectype(6)
{
delete _rec;
_length = r.len();
_rec = new char [ _length ];
_i = new isdef;
_i->r = r.rec();
zero();
}
TExtrectype::~TExtrectype()
{
delete _rec;
delete _i;
}
TBaseisamfile::TBaseisamfile(int logicnum, bool linkrecinst)
{
TTrec r;
_isamfile = NULL;
_logicnum = logicnum;
_lasterr = NOERR;
_delopenrec = FALSE;
if ((openrec[_logicnum - 1] == NULL) || (!linkrecinst))
{
_current = new TRectype(this);
if (openrec[_logicnum - 1] == NULL)
{
openrec[_logicnum - 1] = _current;
_delopenrec = TRUE;
}
_delrec = TRUE;
}
else
{
_current = openrec[_logicnum - 1];
_delrec = FALSE;
}
r.get(logicnum);
/*
_historicfile = ((r.field(RFLD_SYS_DATE) != FIELDERR) &&
(r.field(RFLD_SYS_FIRST) != FIELDERR) &&
(r.field(RFLD_SYS_LAST) != FIELDERR));
*/
_historicfile = FALSE;
}
TBaseisamfile::~TBaseisamfile()
{
if (_delrec)
{
if (_delopenrec)
openrec[_logicnum - 1] = NULL;
delete _current;
}
if (_isamfile != NULL)
delete _isamfile;
}
int TBaseisamfile::gethr(TRectype& rec, TDate& atdate)
{
TRecfield fd0(rec, RFLD_SYS_DATE);
TDate d0((const TDate&) fd0);
if (d0 < atdate)
{
atdate = eotime;
return NOERR;
}
TRectype wr(rec);
TRecfield flf(wr, RFLD_SYS_FIRST),
fll(wr, RFLD_SYS_LAST),
fd1(wr, RFLD_SYS_DATE);
TDate d1;
TRecnotype wr0 = -1L, wr1 = -1L;
if ((wr0 == flf.ptr()) == -1L) return _iskeynotfound;
_hf.read(wr.string(), wr0);
if ((d1 = (const TDate&) fd1) > atdate)
{
rec = wr;
atdate = d0 - 1L;
return _iskeynotfound;
}
while ((d1 < atdate) && (wr0 > 0))
{
rec = wr;
wr1 = wr0;
if ((wr0 = fll.ptr()) > 0)
{
_hf.read(wr.string(), wr0);
d1 = (const TDate&) fd1;
}
}
if (wr0 <= 0)
atdate = d0 - 1L;
else
atdate = d1 - 1L;
return NOERR;
}
int TBaseisamfile::addhr(const TRectype& rec, TDate& atdate)
{
return NOERR;
}
int TBaseisamfile::rewhr(const TRectype& rec, TDate& atdate)
{
return NOERR;
}
int TBaseisamfile::delhr(const TRectype& rec, TDate& atdate)
{
return NOERR;
}
long TBaseisamfile::items() const
{
return filehnd()->i.Base[filehnd()->i.PN].PEOD;
}
const char* TBaseisamfile::name() const
{
sprintf(__tmp_string, "%d", num());
return __tmp_string;
}
const char* TBaseisamfile::filename() const
{
if (_isamfile == NULL)
{
TDir d;
d.get(num());
return strcpy(__tmp_string, d.name());
}
return _isamfile->d->SysName;
}
const char* TBaseisamfile::description() const
{
if (_isamfile == NULL)
{
TDir d;
d.get(num());
return strcpy(__tmp_string, d.des());
}
return _isamfile->d->Des;
}
void TBaseisamfile::setkey(int nkey)
{
CHECKD(nkey > 0 && nkey - 1 <= _isamfile->r->NKeys, "Chiave non valida n.ro ", nkey);
NOT_OPEN(name());
_isamfile->i.PN = nkey - 1;
}
int TBaseisamfile::getkey() const
{
NOT_OPEN(name());
return _isamfile->i.PN + 1;
}
int TBaseisamfile::first(word lockop)
{
NOT_OPEN(name());
curr().setdirty();
cisread(_isamfile, curr().string(), _isfirst + lockop, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::last(word lockop)
{
NOT_OPEN(name());
curr().setdirty();
cisread(_isamfile, curr().string(), _islast + lockop, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::next(word lockop)
{
NOT_OPEN(name());
curr().setdirty();
cisread(_isamfile, curr().string(), _isnext + lockop, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::next(TDate& atdate)
{
TRectype wr(curr());
TRecfield fll(curr(), RFLD_SYS_LAST),
fd(wr, RFLD_SYS_DATE);
TRecnotype wrn;
NOT_OPEN(name());
if (!_historicfile)
error_box("%s not historic file", filename());
if (_lasthf == -1L) return _iseof;
curr().setdirty();
_hf.read(curr().string(), _lasthf);
wrn = fll.ptr();
if (wrn < 0L)
{
readat(-wrn);
atdate = eotime;
_lasthf = -1L;
}
else
{
_hf.read(curr().string(), wrn);
_lasthf = wrn;
wrn = fll.ptr();
if (wrn < 0) readat(wr, -wrn);
else _hf.read(wr.string(), wrn);
atdate = (const TDate&)fd - 1L;
}
return NOERR;
}
int TBaseisamfile::prev(word lockop)
{
NOT_OPEN(name());
curr().setdirty();
cisread(_isamfile, curr().string(), _isprev + lockop, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::prev(TDate& atdate)
{
TRecfield flf(curr(), RFLD_SYS_LAST),
fd(curr(), RFLD_SYS_DATE);
TRecnotype wrn;
NOT_OPEN(name());
if (!_historicfile)
error_box("%s not historic file", filename());
if (_lasthf == -1L) return _isbof;
curr().setdirty();
_hf.read(curr().string(), _lasthf);
wrn = flf.ptr();
atdate = (const TDate&) fd - 1L;
if (wrn < 0L) _lasthf = -1L;
else
{
_hf.read(curr().string(), wrn);
_lasthf = wrn;
}
return NOERR;
}
int TBaseisamfile::reread(word lockop, TDate& atdate)
{
NOT_OPEN(name());
curr().setdirty();
if ((!_historicfile) || (atdate == botime))
return cisread(_isamfile, curr().string(), _iscurr + lockop, &_lasterr);
else
{
if (cisread(_isamfile, curr().string(), _iscurr + lockop, &_lasterr) == NOERR)
_lasterr = gethr(curr(), atdate);
}
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::reread(TRectype& rec, word lockop, TDate& atdate)
{
NOT_OPEN(name());
rec.setdirty();
if ((!_historicfile) || (atdate == botime))
cisread(_isamfile, rec.string(), _iscurr + lockop, &_lasterr);
else
{
if (cisread(_isamfile, rec.string(), _iscurr + lockop, &_lasterr) == NOERR)
_lasterr = gethr(rec, atdate);
}
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::skip(TRecnotype nrec, word lockop)
{
NOT_OPEN(name());
if (!nrec) return NOERR;
curr().setdirty();
if (nrec >0)
cisread(_isamfile, curr().string(), _isnextn + lockop + (UINT16) nrec, &_lasterr);
else
cisread(_isamfile, curr().string(), _isprevn + lockop - (UINT16) nrec, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::read(word op, word lockop, TDate& atdate)
{
CHECKD(op >= _iscurr && op <= _isgteq, "Invalid read operation : ", op);
NOT_OPEN(name());
curr().setdirty();
if ((!_historicfile) || (atdate == botime))
cisread(_isamfile, curr().string(), op + lockop, &_lasterr);
else
{
if (cisread(_isamfile, curr().string(), op + lockop, &_lasterr) == NOERR)
_lasterr = gethr(curr(), atdate);
}
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::read(TRectype& rec, word op, word lockop, TDate& atdate)
{
CHECKD(op >= _iscurr && op <= _isgteq, "Invalid read operation : ", op);
NOT_OPEN(name());
rec.setdirty();
if ((!_historicfile) || (atdate == botime))
cisread(_isamfile, rec.string(), op + lockop, &_lasterr);
else
{
if (cisread(_isamfile, rec.string(), op + lockop, &_lasterr) == NOERR)
_lasterr = gethr(rec, atdate);
}
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::readat(TRecnotype nrec, word lockop)
{
NOT_OPEN(name());
curr().setdirty();
cisreadrec(_isamfile, nrec, curr().string(), lockop, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::readat(TRectype& rec, TRecnotype nrec, word lockop)
{
NOT_OPEN(name());
rec.setdirty();
cisreadrec(_isamfile, nrec, rec.string(), lockop, &_lasterr);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::write(TDate& atdate)
{
NOT_OPEN(name());
if ((!_historicfile) || (atdate == botime))
ciswrite(_isamfile, curr().string(), &_lasterr);
else
_lasterr = addhr(curr(), atdate);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::write(const TRectype& rec, TDate& atdate)
{
NOT_OPEN(_isamfile->d->SysName);
if ((!_historicfile) || (atdate == botime))
ciswrite(_isamfile, rec.string(), &_lasterr);
else
_lasterr = addhr(rec, atdate);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::rewrite(TDate& atdate)
{
NOT_OPEN(name());
if ((!_historicfile) || (atdate == botime))
cisrewrite(_isamfile, curr().string(), &_lasterr);
else
_lasterr = rewhr(curr(), atdate);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::rewrite(const TRectype& rec, TDate& atdate)
{
NOT_OPEN(name());
if ((!_historicfile) || (atdate == botime))
cisrewrite(_isamfile, rec.string(), &_lasterr);
else
_lasterr = rewhr(rec, atdate);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::rewriteat(TRecnotype nrec)
{
NOT_OPEN(name());
return cisrewrec(_isamfile, nrec, curr().string(), &_lasterr);
}
int TBaseisamfile::rewriteat(const TRectype& rec, TRecnotype nrec)
{
NOT_OPEN(name());
return cisrewrec(_isamfile, nrec, curr().string(), &_lasterr);
}
int TBaseisamfile::remove(TDate& atdate)
{
NOT_OPEN(name());
if ((!_historicfile) || (atdate == botime))
cisdelete(_isamfile, curr().string(), &_lasterr);
else
_lasterr = delhr(curr(), atdate);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::remove(const TRectype& rec, TDate& atdate)
{
NOT_OPEN(name());
if ((!_historicfile) || (atdate == botime))
cisdelete(_isamfile, rec.string(), &_lasterr);
else
_lasterr = delhr(rec, atdate);
_recno = _isamfile->RecNo;
return _lasterr;
}
int TBaseisamfile::lock()
{
NOT_OPEN(name());
return cislock(_isamfile, &_lasterr);
}
int TBaseisamfile::unlock()
{
NOT_OPEN(name());
return cisunlock(_isamfile, &_lasterr);
}
void TBaseisamfile::indexon()
{
IndexOn();
}
bool TBaseisamfile::empty()
{
return _isamfile->i.Base[_isamfile->i.PN].PEOD == 0;
}
void TBaseisamfile::indexoff()
{
IndexOff();
}
int TBaseisamfile::_open(unsigned int mode)
{
int err;
if (filehnd() != NULL)
fatal_box("Il file %d e' gia' aperto", _logicnum);
if ((cisopen(&_isamfile, _logicnum, NOALLOC, mode, &err) == NOERR) &&
(_historicfile))
{
TFilename s(filename());
s.ext("hst");
_hf.len() = filehnd()->d->LenR;
_hf.base() = 1;
_hf.open(s);
if (_hf.status() == 2)
{
_hf.create(s);
_hf.open(s);
}
if (_hf.error()) return err = _hf.status();
_lasthf = -1L;
_hfhd = _hf;
_hfhd.len() = sizeof(TRecnotype);
_hfhd.base() = 0;
}
if (err == NOERR)
{
isdef * fh = filehnd();
const TRecnotype nitems = fh->i.Base[0].PEOX;
if (fh->d->EOX != nitems)
recover();
}
_recno = -1L;
_current->_i = filehnd();
setstatus(err);
return err;
}
int TBaseisamfile::_close()
{
int err = NOERR;
if (filehnd() != NULL)
{
cisclose(ptrfilehnd(), NULL, &err);
clearfilehnd();
}
_current->_i = NULL;
setstatus(err);
return err;
}
TLocalisamfile::TLocalisamfile(int logicnum, bool linkrecinst)
: TBaseisamfile(logicnum, linkrecinst)
{
open();
if (_was_open)
_oldkey = getkey();
setkey(1);
}
TLocalisamfile::~TLocalisamfile()
{
if (_was_open)
setkey(_oldkey);
close();
}
int TLocalisamfile::close()
{
int err = NOERR;
if (!_was_open)
{
clearfilehnd();
}
else
{
if (_isamfile)
{
cisclose(&_isamfile, NULL, &err);
_isamfile = NULL;
}
}
setstatus(err);
return err;
}
int TLocalisamfile::open(unsigned int mode)
{
int err = NOERR;
const int logicnum = num();
if (openf[logicnum - 1] != NULL)
{
_was_open = FALSE;
_isamfile = openf[logicnum - 1];
_current->_i = filehnd();
}
else
{
err = _open();
_was_open = TRUE;
}
_isatab = FALSE;
setstatus(err);
return err;
}
int TLocalisamfile::operator +=(const TRecnotype npos)
{
skip(npos);
return status();
}
int TLocalisamfile::operator -=(const TRecnotype npos)
{
skip(-npos);
return status();
}
int TLocalisamfile::operator ++()
{
next();
return status();
}
int TLocalisamfile::operator --()
{
prev();
return status();
}
TIsamfile::TIsamfile(int logicnum, bool linkrecinst) : TBaseisamfile(logicnum, linkrecinst) {}
TIsamfile::~TIsamfile()
{
close();
}
int TIsamfile::flags(bool updateeod)
{
int err;
NOT_OPEN(name());
setstatus(err);
return cisupdflags(filehnd(), &err, updateeod);
}
TIsamtempfile::TIsamtempfile(int logicnum, bool linkrecinst) : TBaseisamfile(logicnum, linkrecinst) {}
TIsamtempfile::~TIsamtempfile()
{
close();
}
int TIsamtempfile::open(char* radix, bool create, TRecnotype eod, TRecnotype eox)
{
int err;
if (filehnd() != NULL)
fatal_box("File %s already open", filename());
if ((cisopentemp(ptrfilehnd(), _logicnum, radix, NOALLOC, create, eod, eox, &err) == NOERR) &&
(_historicfile))
{
TFilename s(filename());
s.ext("hst");
_hf.len() = filehnd()->d->LenR;
_hf.base() = 1;
_hf.open(s);
if (_hf.status() == 2)
{
_hf.create(s);
_hf.open(s);
}
if (_hf.error()) return err = _hf.status();
_lasthf = -1L;
_hfhd = _hf;
_hfhd.len() = sizeof(TRecnotype);
_hfhd.base() = 0;
}
_current->_i = filehnd();
_recno = -1L;
setstatus(err);
return err;
}
int TIsamtempfile::close(bool flagdel)
{
int err;
if (filehnd() != NULL)
{
cisclosetemp(ptrfilehnd(), NULL, flagdel, &err);
clearfilehnd();
}
_current->_i = NULL;
setstatus(err);
return err;
}
int TSystemisamfile::build(TRecnotype eox)
{
int err;
if(filehnd() != NULL)
fatal_box("Can't recreate open file %s", filename());
TDir d;
d.get(num());
TFilename f(d.name());
f = f.path();
if (!fexist(f))
#if XVT_OS==XVT_OS_SCOUNIX
mkdir(f, 0777);
#else
mkdir(f);
#endif
cisbuild(filehnd(), num(), eox, &err);
setstatus(err);
clearfilehnd();
#ifndef FOXPRO
if (err == NOERR && __autoload)
{
TFilename lf;
lf.format("%sstd/lf%04d.txt", __ptprf, num());
if (fexist(lf))
load(lf, '|', '\0', '\n', TRUE, TRUE);
}
#endif
return err;
}
int TSystemisamfile::extend(TRecnotype eox)
{
int err;
if (filehnd() != NULL)
fatal_box("Can't extend open file %s", filename());
cisextend(filehnd(), num(), eox, &err);
setstatus(err);
clearfilehnd();
return err;
}
long TSystemisamfile::size(TRecnotype eox)
{
int err;
const long size = cisextension(num(), eox, &err);
if (err != NOERR) setstatus(err);
return size;
}
#ifndef FOXPRO
bool TSystemisamfile::exec_convapp(long flev, const bool before)
{
const char * const v = before ? "BCNV" : "ACNV";
if (flev == 0) flev = 199401;
else flev++;
for (long l = flev; l <= stdlevel; l++)
{
TString16 paragraph(format("%06ld", l));
TConfig conv(CONFIG_FCONV, paragraph);
if (!conv.new_paragraph() && conv.exist(v, num()))
{
int err = 0;
TString80 s(conv.get(v, NULL, num())); s << " " << main_app().get_firm();
TExternal_app app(s);
if (app.can_run())
{
app.run();
err = app.error();
TMailbox mail;
TMessage* msg = mail.next(TRUE);
if (err == 0 && msg != NULL)
err = atoi(msg->body());
}
else err = 16;
if (err)
return error_box("Non posso eseguire il programma di %sconversione\ndel livello %ld/%ld\nErrore n.ro %d", before ? "pre" : "post", l / 100, l % 100, err);
}
}
return TRUE;
}
bool TSystemisamfile::getlcf(long flev)
{
_flds.destroy();
_exps.destroy();
if (flev == 0) flev = 199401;
else flev++;
for (long l = flev; l <= stdlevel; l++)
{
TString16 paragraph(format("%06ld", l));
TConfig conv(CONFIG_FCONV, paragraph);
if (!conv.new_paragraph() && conv.exist("F", num()))
{
TToken_string exprline(conv.get("F", NULL, num()));
if (exprline.empty()) return FALSE;
TToken_string w("", '=');
const char * wexprs = exprline.get();
while (wexprs != NULL)
{
w = wexprs;
TFixed_string fld(w.get());
_flds.add(new TFieldref(fld, 0));
_exps.add(new TExpression(w.get(), _strexpr));
wexprs = exprline.get();
}
}
}
return _flds.items() > 0;
}
void TSystemisamfile::makelc(TRectype& rec)
{
for (int i = 0 ; i < _flds.items(); i++)
{
TFieldref& f = (TFieldref&) _flds[i];
TExpression& e = (TExpression & )_exps[i];
for (int k = 0; k < e.numvar(); k++)
e.setvar(k, get(e.varname(k)));
f.write(e, rec);
}
}
int TSystemisamfile::update(TTrec& newrec, bool vis)
{
if (filehnd() != NULL)
fatal_box("Can't update description for open file %s", filename());
TDir dir;
dir.get(num(), _lock, _nordir, _sysdirop);
const char p = *dir.name();
const bool incom = strcmp(prefhndl->name(), "com") == 0;
const bool toconvert = (incom ? p == '%' : p != '%');
int err = NOERR;
TTrec oldrec;
oldrec.get(num());
const long lev = prefhndl->filelevel();
const bool lcf = getlcf(lev);
exec_convapp(lev, TRUE);
if (!lcf && newrec == oldrec)
{
exec_convapp(lev, FALSE);
return NOERR;
}
const TRecnotype nitems = dir.eod();
const unsigned int lenr = newrec.len();
if (!toconvert && dir.eox() > 0L)
{
dir.eod() = 0L;
dir.eox() = 0L;
}
if (toconvert && dir.eox() > 0L)
{
TRecnotype ni = 0L;
TFilename tmpfname;
tmpfname.temp(NULL);
FILE* f = fopen(tmpfname, "w");
err = ferror(f);
if (f == NULL)
{
clearerr(f);
setstatus(err);
return err;
}
open(_excllock);
TFilename fname(filename());
TString s(80);
s.format("Aggiornamento archivio %s", (const char*) fname);
TProgind p(nitems ? nitems : 1, s, TRUE, TRUE, 70);
int nflds = curr().items();
TArray fld(nflds);
TExtrectype nrec(newrec);
TRecnotype i;
for (int j = 0; j < nflds; j++)
fld.add(TString(curr().fieldname(j)), j);
for (i = 1; i <= nitems && !p.iscancelled(); i++)
{
if ((i % 50) == 0) p.setstatus(i + 1);
readat(i);
if (curr().valid())
{
nrec.zero();
ni++;
for (j = 0; j < nflds; j++)
if (nrec.exist((const TString&) fld[j]))
nrec.put((const TString&) fld[j], get((const TString&) fld[j]));
if (lcf)
makelc((TRectype &)nrec);
fwrite(nrec.string(), lenr, 1, f);
}
}
p.setstatus(nitems);
close();
fclose(f);
fcopy(tmpfname, fname);
::remove(tmpfname);
dir.eod() = ni;
}
// aggiornare il log file
dir.set_len(lenr);
dir.put(num(), _nordir, _sysdirop);
newrec.put(num());
if (toconvert && dir.eox() > 0L) packindex();
exec_convapp(lev, FALSE);
return err;
}
int TSystemisamfile::packfile(bool vis)
{
int err;
if (filehnd() != NULL)
fatal_box("Can't pack open file %s", filename());
setstatus(creorgfile(num(), vis, &err));
return err;
}
int TSystemisamfile::packindex(bool vis)
{
int err;
if (filehnd() != NULL)
fatal_box("Can't pack open file %s", filename());
setstatus(creorgindex(num(), vis, &err));
return err;
}
int TSystemisamfile::load(const char* from, char fs, char fd, char rs, bool vis, bool extended)
{
FILE* fl = fopen(from, "r+");
int err = ferror(fl);
TRecnotype r = 0, e = 0, nitems = 0, nread = 0;
TString16 firm, year, attprev("00000");
if (extended)
{
TDate d(TODAY);
TLocalisamfile ditte(LF_NDITTE);
firm.format("%05ld", main_app().get_firm());
year.format("%04d", d.year());
ditte.zero();
ditte.put("CODDITTA", firm);
if (ditte.read() == NOERR)
attprev = ditte.get("CODATTPREV");
}
if (fl == NULL)
{
clearerr(fl);
setstatus(err);
return err;
}
char w[80];
while ((fgets(w, 80, fl) != NULL))
{
if (strncmp(w, "[Data]", 6) == 0)
{
nitems = ftell(fl);
break;
}
}
fseek(fl, 0L, SEEK_END);
nitems = ftell(fl) - nitems;
fclose(fl);
TScanner f(from);
open();
TToken_string s(1024, fs);
bool fixedlen = (fs == '\0');
int nflds = curr().items();
TArray fld(nflds);
int len[MaxFields];
TString sfd(3);
TString s1(64);
bool lcf = FALSE;
if (f.paragraph("Header"))
{
f.equal();
const long level = atol(f.line());
if (level > stdlevel)
error_box("L' archivio %s e' stato generato con gli archivi di livello %ld%/%ld.\n Il livello attuale e' %ld/%ld.\n Convertire gli archivi e ripetere l' operazione.", from, level / 100, level % 100, stdlevel / 100, stdlevel % 100);
lcf = getlcf(level);
nflds = 0;
TToken_string s2(f.line());
int p = s2.find('=');
if (p > 0)
{
s1 = s2.left(p);
s2.ltrim(p+1);
}
else s1.cut(0);
while (s1 == "Fields")
{
for (const char * fd = s2.get(); fd != NULL; fd = s2.get())
{
TToken_string wfd(fd, ',');
fld.add(new TString(wfd.get()));
len[nflds] = wfd.get_int();
nflds++;
}
s2 = f.line();
p = s2.find('=');
if (p > 0)
{
s1 = s2.left(p);
s2.ltrim(p+1);
}
else s1.cut(0);
}
}
else
{
for (int j = 0; j < nflds; j++)
{
fld.add(TString(curr().fieldname(j)), j);
const TString & wfld = (const TString & ) fld[j];
len[j] = (curr().type(wfld) == _datefld) ? 10 : curr().length(wfld);
}
}
if (!f.paragraph("Data"))
{
error_box("Formato dei dati non valido");
close();
err = 1;
setstatus(err);
return err;
}
if (fd) sfd << fd;
int last = NOERR;
s1.format("Imp. archivio %s\n%6ld records %6ld errori - %3d", filename(), r, e, last);
TProgind p(nitems, s1, TRUE, TRUE, 70);
s = f.line();
while (s.not_empty() && !p.iscancelled())
{
if (extended)
{
int p, i;
while ((p = s.find("%yr%")) >= 0)
for (i = 0; i < 4; i++) s[p + i] = year[i];
while ((p = s.find("%frm%")) >= 0)
for (i = 0; i < 5; i++) s[p + i] = firm[i];
while ((p = s.find("%att%")) >= 0)
for (i = 0; i < 5; i++) s[p + i] = attprev[i];
}
if ((r + e) % 50 == 0)
{
s1.format("Imp. archivio %s\n%6ld records %6ld errori - %3d", filename(), r, e, last);
p.set_text(s1);
}
p.setstatus(nread + 1);
nread += s.len() + 1;
zero();
if (fixedlen)
{
int pos = 0;
for (int j = 0; j < nflds; j++)
{
s1 = s.mid(pos,len[j]);
s1.rtrim();
put((const TString&) fld[j], s1);
pos += len[j];
}
}
else
{
s.restart();
for (int j = 0; j < nflds; j++)
{
char* s2 = (char*) s.get();
if (fd)
{
s2++;
s2[strlen(s2) - 1] = '\0';
}
put((const TString&) fld[j], s2);
}
}
if (write() == NOERR) r++;
else
{
e++;
last = status();
}
s = f.line();
}
s1.format("Imp. archivio %s\n%6ld records %6ld errori - %3d", filename(), r, e, last);
p.set_text(s1);
close();
setstatus(err);
return err;
}
int TSystemisamfile::dump(const char* to, int nkey, char fs, char fd, char rs, bool vis, bool withdeleted)
{
FILE* f = fopen(to, "w");
int err = ferror(f);
if (withdeleted) nkey = 0;
if (f == NULL)
{
clearerr(f);
setstatus(err);
return err;
}
open();
TString s(512);
bool fixedlen = (fs == '\0');
int nflds = curr().items();
TArray fld(nflds);
TBit_array rjust(nflds);
int len[MaxFields];
for (int j = 0; j < nflds; j++)
{
fld.add(TString(curr().fieldname(j)), j);
const TString & wfld = (const TString&) fld[j];
const TFieldtypes t = curr().type(wfld);
rjust.set(j, t == _intfld || t == _longfld || t == _realfld ||
t == _wordfld || t == _intzerofld || t == _longzerofld);
len[j] = (t == _datefld) ? 10 : curr().length(wfld);
}
TRecnotype i = 0;
const TRecnotype nitems = nkey ? items() : filehnd()->d->EOD;
s.format("Esportazione archivio %s", filename());
TProgind p(nitems, s, TRUE, TRUE, 70);
TString s1;
fprintf(f, "[Header]\nVersion=%ld", prefhndl->filelevel());
for (int k = 0; k < nflds; k++)
{
if ((k % 10) == 0) fprintf(f, "\nFields=");
else fprintf(f, "|");
fprintf(f, "%s,%d", (const char *) (const TString&) fld[k], len[k]);
}
fprintf(f, "\n\n[Data]\n");
if (nkey)
{
setkey(nkey);
for ( first(); status() == NOERR && !p.iscancelled(); next(), i++)
{
p.setstatus(i + 1);
s = "";
for (j = 0; j < nflds; j++)
{
if (fixedlen)
{
s1 = get((const TString&)fld[j]);
if (rjust[j]) s1.right_just(len[j]);
else s1.left_just(len[j]);
}
else
{
s1 = "";
if (j && fs) s1 << fs;
if (fd) s1 << fd;
s1 << get((const TString&)fld[j]);
if (fd) s1 << fd;
}
s << s1;
}
fprintf(f, "%s%c", (const char*) s, rs);
}
}
else
{
for (i = 0; i < nitems && !p.iscancelled(); i++)
{
zero();
p.setstatus(i + 1);
readat(i + 1);
s="";
if (withdeleted || curr().valid())
{
for (j = 0; j < nflds; j++)
{
if (fixedlen)
{
s1 = get((const TString&)fld[j]);
if (rjust[j]) s1.right_just(len[j]);
else s1.left_just(len[j]);
}
else
{
s1 = "";
if (j && fs) s1 << fs;
if (fd) s1 << fd;
s1 << get((const TString&)fld[j]);
if (fd) s1 << fd;
}
s << s1;
}
fprintf(f, "%s%c", (const char*) s, rs);
}
}
}
p.setstatus(nitems);
close();
fclose(f);
setstatus(err);
return err;
}
#endif // FOXPRO
void TBaseisamfile::recover()
{
isdef * fh = filehnd();
const TRecnotype nitems = fh->i.Base[0].PEOX;
CHECKD(getkey() == 1, "La chiave corrente non e' 1 ma ", getkey());
TFilename fn = filename();
fn = fn.name();
#ifndef FOXPRO
if (yesno_box("La dimensione dell'archivio %s e' errata. Cerco di recuperarlo?", (const char *)fn))
{
TDir d;
TString mess(80);
mess.format("Ricostruzione archivio %s : I Fase", (const char*) fn);
TProgind p(nitems ? nitems : 1, mess, TRUE, TRUE, 70);
const TDirtype dir = (fh->ft == 0) ? _nordir : _comdir;
d.get(num(), _lock, dir, _sysdirop);
d.eod() = fh->d->EOD = nitems;
d.eox() = fh->d->EOX = nitems;
d.put(num(), dir, _sysdirop);
for (TRecnotype r = 1; r <= nitems; r++)
{
p.addstatus(1);
CRead(&fh->f, curr().string(), r, _nolock);
curr().discard();
CWrite(&fh->f, curr().string(), r, _nolock);
}
p.close_modal();
mess.format("Ricostruzione archivio %s : II Fase", (const char*) fn);
TProgind pi(items() ? items() : 1, mess, TRUE, TRUE, 70);
for (first(); good(); next())
{
pi.addstatus(1);
curr().recall();
rewrite();
}
message_box("L'archivio %s deve essere compattato", (const char *) fn);
}
else
#endif
fatal_box("L'archivio %s e' incosistente e deve essere corretto prima di utilizzarlo", (const char *)fn);
}
////////////////////////////////////////////////////////////
// TRectype
////////////////////////////////////////////////////////////
TRectype::TRectype(int logicnum)
: _cod(NULL)
{
TDir wdir;
_logicnum = logicnum;
wdir.get(_logicnum, _nolock, _nordir, _sysdirop);
if (wdir.name()[0] == '%')
wdir.get(_logicnum, _nolock, _comdir, _sysdirop);
_length = wdir.len();
_rec = new char [ _length ];
_i = openf[_logicnum - 1];
*_tab = '\0';
setempty(TRUE);
}
TRectype::TRectype(const TBaseisamfile* i)
: _cod(NULL)
{
_logicnum = i->num();
if (i->filehnd() != NULL)
_length = i->filehnd()->d->LenR;
else
{
TDir wdir;
wdir.get(_logicnum, _nolock, _nordir, _sysdirop);
if (wdir.name()[0] == '%')
wdir.get(_logicnum, _nolock, _comdir, _sysdirop);
_length = wdir.len();
}
*_tab = '\0';
_rec = new char [ _length ];
_i = i->filehnd();
setempty(TRUE);
}
TRectype::TRectype(const TRectype& r)
: _cod(NULL)
{
_logicnum = r._logicnum;
_length = r.len();
_rec = new char [ _length ];
_rec[0] = r._rec[0];
memcpy(_rec + 1, r._rec + 1, _length - 1);
_i = r._i;
strcpy(_tab, r._tab);
if (r._cod != NULL)
_cod = new TRecfield(*this, "COD");
setempty(r.empty());
}
TRectype::~TRectype()
{
if (_cod != NULL) delete _cod;
delete _rec;
}
void TRectype::settab(const char *tab)
{
if (_cod != NULL)
{
delete _cod;
_cod = NULL;
}
strcpy(_tab, tab);
if (*_tab != '\0')
_cod = new TRecfield(*this, "COD");
zero();
}
TObject* TRectype::dup() const
{
TRectype* o = new TRectype(*this);
return o;
}
HIDDEN bool fld_empty(const char* s, int len, bool number)
{
/*if (number)
{
for (; len; s++, len--)
if (strchr(" 0.", *s) == NULL) return FALSE;
}
else */
if (*s)
{
for (; len; s++, len--)
if (*s != ' ') return FALSE;
}
return TRUE;
}
HIDDEN int fld_cmp(const char* a, const char* b, int len, bool number)
{
for (int i = 0; i < len && *a == *b; b++, a++, i++);
if (i == len) return 0;
int res = *a - *b;
if (number)
{
b -= i;
i = 0;
}
return fld_empty(b, len - i, number) ? 0 : res;
}
///////////////////////////////////////////////////////////
// TRectype (record di un file)
///////////////////////////////////////////////////////////
int TRectype::items() const
{
return _i->r->NFields;
}
const char* TRectype::start(int nf) const
{
return string() + _i->r->Fd[nf].RecOff;
}
int TRectype::compare(const TSortable& s) const
{
const TRectype& br = (const TRectype&) s;
int res = 0;
if (br.empty()) return UNDEFINED;
for (int i = 0; i < items() ; i++)
{
const char* b = br.start(i);
const char* a = start(i);
const byte typ = _i->r->Fd[i].TypeF;
/* if (typ == _boolfld) res = *a - *b;
else
{ */
const int sz = _i->r->Fd[i].Len;
const bool number = (typ == _intfld) || (typ == _realfld) ||
(typ == _longfld) || (typ == _wordfld) ||
(typ == _intzerofld) || (typ == _longzerofld)
|| (typ == _datefld) ;
if (fld_empty(b, sz, number)) continue;
res = ::fld_cmp(a, b, sz, number);
/* } */
if (res) return res;
}
return 0;
}
TFieldtypes TRectype::type(const char* fieldname) const
{
NOT_LINKED(_i, "type");
return (TFieldtypes) CFieldType((char*) fieldname, _i->r);
}
int TRectype::length(const char* fieldname) const
{
NOT_LINKED(_i, "length");
return CFieldSize((char*) fieldname, _i->r);
}
int TRectype::ndec(const char* fieldname) const
{
NOT_LINKED(_i, "dec");
return CFieldDec((char*) fieldname, _i->r);
}
bool TRectype::exist(const char* fieldname) const
{
NOT_LINKED(_i, "exist");
return findfld(_i->r, (char*)fieldname) != -1;
}
const char* TRectype::fieldname(int i) const
{
NOT_LINKED(_i, "fieldname");
return i >= 0 && i < _i->r->NFields ? _i->r->Fd[i].Name : NULL;
}
#ifndef FOXPRO
int TRectype::get_int(const char* fieldname) const
{
NOT_LINKED(_i, "get_int");
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
return atoi(__tmp_string);
}
long TRectype::get_long(const char* fieldname) const
{
NOT_LINKED(_i, "get_long");
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
return atol(__tmp_string);
}
word TRectype::get_word(const char* fieldname) const
{
NOT_LINKED(_i, "get_word");
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
return (word)atoi(__tmp_string);
}
real TRectype::get_real(const char* fieldname) const
{
NOT_LINKED(_i, "get_real");
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
real r(__tmp_string);
return r;
}
char TRectype::get_char(const char* fieldname) const
{
NOT_LINKED(_i, "get_char");
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
return *__tmp_string;
}
bool TRectype::get_bool(const char* fieldname) const
{
NOT_LINKED(_i, "get_bool");
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
return *__tmp_string == 'X';
}
#endif // FOXPRO
TDate TRectype::get_date(const char* fieldname) const
{
NOT_LINKED(_i, "get_date");
const TRecfield f((TRectype&)*this, fieldname);
return (TDate) f;
}
const TString& TRectype::get(const char* fieldname) const
{
static TFixed_string s(__tmp_string, 256);
NOT_LINKED(_i, "get");
if (CFieldType((char*) fieldname, _i->r) == _datefld)
{
const TRecfield f((TRectype&)*this, fieldname);
s = (const char*) f;
}
else
if (CGetFieldBuff((char*) fieldname, _i->r, _rec, __tmp_string) == -1)
UNKNOWN_FIELD(num(), fieldname);
return s;
}
#ifndef FOXPRO
void TRectype::put(const char* fieldname, int val)
{
NOT_LINKED(_i, "put");
if (CPutField((char*) fieldname, _i->r, &val, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, long val)
{
NOT_LINKED(_i, "put");
if (CPutField((char*) fieldname, _i->r, &val, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, word val)
{
NOT_LINKED(_i, "put");
if (CPutField((char*) fieldname, _i->r, &val, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, const real& val)
{
NOT_LINKED(_i, "put");
if (CPutField((char*) fieldname, _i->r, val.ptr(), _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, const TDate& val)
{
NOT_LINKED(_i, "put");
TRecfield f(*this, fieldname);
f = val.string(4);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, char val)
{
NOT_LINKED(_i, "put");
char w[2] = {val, '\0'};
if (CPutFieldBuff((char*) fieldname, _i->r, w, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, bool val)
{
NOT_LINKED(_i, "put");
char* s = val ? "X" : " ";
if (CPutFieldBuff((char*) fieldname, _i->r, s, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
#endif // FOXPRO
void TRectype::put(const char* fieldname, const char* val)
{
NOT_LINKED(_i, "put");
if (val == NULL || *val == '\0') // Da provare
{
TRecfield f(*this, fieldname);
if (*f.pos() == '\0') return;
}
if (CFieldType((char*) fieldname, _i->r) == _datefld)
{
TRecfield f(*this, fieldname);
f = val;
}
else
if (CPutFieldBuff((char*) fieldname, _i->r, (char*) val, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
setempty(FALSE);
}
void TRectype::zero(const char* fieldname)
{
NOT_LINKED(_i, "zero");
if (_cod != NULL && strcmp(fieldname , "COD") == 0)
*_cod = _tab;
else
if (CZeroField((char*) fieldname, _i->r, _rec) == -1)
UNKNOWN_FIELD(num(), fieldname);
}
void TRectype::zero()
{
zero('\0');
}
void TRectype::zero(char c)
{
NOT_LINKED(_i, "zero");
recall();
memset(_rec + 1, c, len() - 1);
if (_cod != NULL)
*_cod = _tab;
setempty(TRUE);
}
// Certified 99%
TRectype& TRectype::operator =(const TRectype& rec)
{
CHECK(num() == rec.num(), "Can't assign records of different file");
_i = rec._i; // Copy filehndl
memcpy(_rec, rec._rec, _length); // Copy contents
setempty(rec.empty()); // Copy emptiness status
return *this;
}
// Certified 100%
TRectype& TRectype::operator =(const TBaseisamfile& f)
{
return *this = f.curr();
}
// Certified 99%
TRectype& TRectype::operator =(const char* rec)
{
memcpy(_rec, rec, _length);
setempty(FALSE);
return *this;
}
const char* TRectype::key(int numkey) const
{
NOT_LINKED(_i, "key");
CBuildKey(_i->r, numkey, _rec, __tmp_string);
return __tmp_string;
}
TRec_array::TRec_array(int dimension, TBaseisamfile& i)
: TArray(dimension)
{
TRectype r(&i);
for (int j = 0 ; j < size(); j++) add(r, j);
}
///////////////////////////////////////////////////////////
// TRecfield (campo/sottocampo di un record)
///////////////////////////////////////////////////////////
void TRecfield::set(int from, int to)
{
int nf;
const isdef* bf = _rec->filehnd();
if ((nf = findfld(bf->r, _name)) == -1)
{
_p = NULL;
_len = 0;
_dec = 0;
_type = _nullfld;
yesnofatal_box("File n. %d unknown field %s", _rec->num(), _name);
}
else
{
CHECK(from >= 0, "Invalid Start");
_p = _rec->string() + bf->r->Fd[nf].RecOff + from;
_dec = bf->r->Fd[nf].Dec;
_type = bf->r->Fd[nf].TypeF;
if (to >= 0)
{
CHECK(from <= to && to <= bf->r->Fd[nf].Len,
"Invalid Range");
_len = to - from + 1;
}
else _len = bf->r->Fd[nf].Len - from;
}
}
TRecfield::TRecfield(TRectype& rec, const char* name, int from, int to)
{
strcpy(_name, name);
NOT_LINKED(rec.filehnd(), "TRecfield");
_rec = &rec;
set(from, to);
}
HIDDEN void __getfieldbuff(byte l, byte t, const char* recin, char *s)
{
if (recin == NULL)
{
*s = '\0';
return;
}
if ((t != _alfafld) && (t != _datefld))
{
while ((*recin == ' ') && (l))
{
recin++;
l--;
}
if ((t != _realfld) && (t != _charfld) &&
(t != _intzerofld) && (t != _longzerofld))
{
while ((*recin == '0') && (l))
{
recin++;
l--;
}
}
}
if (l)
{
strncpy(s, recin, l);
while (s[--l] == ' ');
l++;
}
s[l] = '\0';
if (t == _datefld && *s)
{
TDate dt(atol(s));
strcpy(s, dt.string(4));
}
}
HIDDEN void __putfieldbuff(byte l, byte d, byte t, const char* s, char* recout)
{
int len, i;
if (recout == NULL) return;
char s2[256];
strcpy(s2, s);
if (t == _datefld)
{
if (*s2)
{
TDate dt(s2);
sprintf(s2,"%06ld", (long) dt);
}
} else
if (t == _realfld) setdec(s2, d);
len = strlen(s2);
if (len > l) return ;
if ((t == _intfld) ||
(t == _longfld) ||
(t == _wordfld) ||
(t == _realfld))
{
if (len == 0)
{
strcpy(s2, "0");
len = 1;
}
i = 0;
while (i < l - len - 1) recout[i++] = ' ';
strncpy(&recout[l - len - 1], s2, len) ;
}
else
{
strncpy(recout, s2, len) ;
while (len < l) recout[len++] = ' ';
}
}
int TRecfield::operator =(int i)
{
if (_type == _intzerofld)
sprintf(__tmp_string, "%0*d", _len, i);
else
sprintf(__tmp_string, "%d", i);
__putfieldbuff( _len, _dec, _type, __tmp_string, _p);
_rec->setempty(FALSE);
return i;
}
long TRecfield::operator =(long l)
{
if (_type == _longzerofld)
sprintf(__tmp_string, "%0*ld", _len, l);
else
sprintf(__tmp_string, "%ld", l);
__putfieldbuff( _len, _dec, _type, __tmp_string, _p);
_rec->setempty(FALSE);
return l;
}
#ifndef FOXPRO
const real& TRecfield::operator =(const real& r)
{
strcpy(__tmp_string, r.string());
__putfieldbuff( _len, _dec, _type, __tmp_string, _p);
_rec->setempty(FALSE);
return r;
}
#endif // FOXPRO
const TDate& TRecfield::operator =(const TDate& d)
{
strcpy(__tmp_string, (const char*) d);
__putfieldbuff( _len, _dec, _type, __tmp_string, _p);
_rec->setempty(FALSE);
return d;
}
const char* TRecfield::operator =(const char* s)
{
__putfieldbuff( _len, _dec, _type, s, _p);
_rec->setempty(FALSE);
return s;
}
void TRecfield::setptr(TRecnotype r)
{
if (_p == NULL) return;
bool n = r < 0;
unsigned char* wp = (unsigned char*) _p;
if (n) r = -r;
while(wp - (unsigned char*) _p <= 3)
{
*wp = r && 0x000000FF;
r >>= 8;
wp++;
}
if (n) *wp += 128;
}
TRecfield::operator int() const
{
__getfieldbuff( _len, _type, _p, __tmp_string);
return atoi(__tmp_string);
}
TRecfield::operator long() const
{
__getfieldbuff( _len, _type, _p, __tmp_string);
return atol(__tmp_string);
}
#ifndef FOXPRO
TRecfield::operator const real() const
{
__getfieldbuff( _len, _type, _p, __tmp_string);
real r(__tmp_string);
return r;
}
#endif // FOXPRO
TRecfield::operator TDate() const
{
static TDate d;
__getfieldbuff( _len, _type, _p, __tmp_string);
d = __tmp_string;
return d;
}
TRecfield::operator const char*() const
{
__getfieldbuff( _len, _type, _p, __tmp_string);
return __tmp_string;
}
TRecnotype TRecfield::ptr() const
{
if (_p == NULL) return(-1L);
unsigned char* wp = (unsigned char*) _p + 3;
TRecnotype r = *wp;
bool n = r > 127;
if (n) r -= 128;
while(wp-- > (unsigned char*) _p) r = r << 8 + *wp;
return n ? -r : r;
}
void TTransaction::begin()
{
StTrans();
}
void TTransaction::end(bool success)
{
if (success) EndTrans();
else AbTrans();
}