campo-sirio/include/isam.cpp
guy 062241ade5 Ricorretto cambio ditta che non permetteva conversione
git-svn-id: svn://10.65.10.50/branches/R_10_00@23153 c028cbd2-c16b-5b4b-a496-9718f37d4682
2015-12-16 15:54:37 +00:00

4359 lines
108 KiB
C++
Executable File
Raw Blame History

#define __ISAM_CPP
#define _CRT_SECURE_NO_WARNINGS 1
#include <config.h>
#include <execp.h>
#include <expr.h>
#include <extcdecl.h>
#include <diction.h>
#include <dongle.h>
#include <mailbox.h>
#include <postman.h>
#include <prefix.h>
#include <progind.h>
#include <recarray.h>
#include <scanner.h>
#include <tabmod.h>
#include <utility.h>
#include <tabutil.h>
#include <varrec.h>
#ifdef WIN32
#include <io.h>
#include <share.h>
#include <stdio.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <codeb.h>
#include <nditte.h>
#define RECLOCKTYPES 0xFF00
#define READTYPES 0x00FF
#define INVFLD 255
bool __field_changed = FALSE;
#define NOALLOC (char **) -1
HIDDEN bool __autoload = TRUE;
// @doc INTERNAL
////////////////////////////////////////////////////////////////////////////////////////////////////
// Funzioni C
////////////////////////////////////////////////////////////////////////////////////////////////////
int hashfun(const char *s)
{
int l = strlen(s);
unsigned short temp = 0, *pw = (unsigned short *) s;
const unsigned short * end = (unsigned short *) (s + (l - 1));
while ((char *) pw < (char *) end)
{
temp ^= *pw;
pw++;
}
if (l & 1)
temp ^= (unsigned short ) (8192 + s[l - 1]);
l = (short) (temp % (MaxFields - 3));
CHECKS(l >= 0, "Negative remainder on ", s);
return(l);
}
int findfld(const RecDes *recd, const char *s)
{
short stp = hashfun(s);
for (byte i = 0 ; i < MaxFields; i++)
{
if (stp + i >= MaxFields)
stp -= MaxFields;
byte p = stp + i;
const int fp = recd->SortFd[p];
if (fp == INVFLD)
return(FIELDERR);
const int cmp = strcmp(recd->Fd[fp].Name, s);
if (cmp == 0)
return (int) fp;
else
if (cmp > 0)
return(FIELDERR);
}
return(FIELDERR);
}
void __getfieldbuff(byte l, byte t, const char * recin, TString& s)
{
CHECK(recin, "Can't read from a Null record");
if (t != _alfafld && t != _datefld)
{
if (t == _intzerofld || t == _longzerofld)
{
byte i = 0;
for (char* c = (char*)recin; *c == ' ' && i < l; c++, i++)
*c = '0';
if (i == l)
l = 0;
}
else
{
while ((*recin == ' ') && (l))
{
recin++;
l--;
}
if ((t != _realfld) && (t != _charfld))
{
while ((*recin == '0') && (l))
{
recin++;
l--;
}
}
}
}
if (l)
{
while(l > 0 && recin[l - 1] == ' ') l--;
if (l)
s.strncpy(recin, l);
}
s.cut(l);
if (l)
{
if (t == _datefld)
{
const TDate dt(s);
s = dt.string(full);
}
else
{
if (t == _boolfld)
{
const char ok = toupper(*s);
if (ok == 'T' || ok == 'Y' || ok == 'S' || ok == 'X')
s = "X";
else
s.spaces(1);
}
}
}
}
void __putfieldbuff(byte l, byte d, byte t, const char* s, char* recout)
{
CHECK(recout, "Can't write null record" );
TString80 s2;
if (t == _datefld)
{
if (s && *s && strlen(s) != 8)
{
const TDate dt(s);
s2 << dt.date2ansi();
s = s2.get_buffer();
}
}
else
if (t == _boolfld)
{
s2 = (*s && strchr("1STXY", toupper(*s)) != NULL) ? "T" : "F";
s = s2.get_buffer();
}
else
if (t == _realfld)
{
real r(s);
s2 = r.string(l, d);
s = s2.get_buffer();
}
int len = strlen(s);
const bool exceeded = len > l;
if ((t == _intfld) ||
(t == _longfld) ||
(t == _wordfld) ||
(t == _realfld) ||
(t == _intzerofld) ||
(t == _longzerofld)
)
{
if (len == 0 || exceeded)
{
s2 = "0";
s = s2.get_buffer();
len = 1;
}
__field_changed = FALSE;
const char c = (t == _intzerofld || t == _longzerofld) ? '0' : ' ';
for (int i = l - len - 1; i >= 0; i--)
{
__field_changed |= (recout[i] != c);
recout[i] = c;
}
if (!__field_changed)
{
__field_changed = memcmp(s, recout, l) != 0;
if (!__field_changed)
return;
}
strncpy(&recout[l-len], s, len) ;
}
else
{
if (exceeded)
len = l;
/*
// Il codice seguente e' completamente errato in quanto tutti i prefissi ingannano il test!
// La stringa vuota e' prefisso di qualsiasi stringa
// per cui l'azzeramento di un campo risulta sempre impossibile!
__field_changed = memcmp(s, recout, len) != 0;
if (!__field_changed)
return;
*/
__field_changed = TRUE; // Per ora e' meglio cosi'
strncpy(recout, s, len) ;
for (int i = l - 1; i >= len; i--)
recout[i] = ' ';
}
}
struct TCallbackFileinfo
{
TString16 _var;
TFilename _app;
};
HIDDEN int find_relapp(TConfig& cfg, void* jolly)
{
TCallbackFileinfo& info = *((TCallbackFileinfo*)jolly);
if (cfg.exist(info._var))
{
info._app = cfg.get(info._var);
return info._app.not_empty();
}
return FALSE;
}
bool get_relapp(int logicnum, TString& app)
{
TConfig ini(CONFIG_GENERAL);
TCallbackFileinfo fi;
fi._var.format("Edit_%d", logicnum);
ini.for_each_paragraph(find_relapp, &fi);
if (fi._app.not_empty())
app = fi._app;
return app.not_empty();
}
struct TCallbackTableinfo
{
TString16 _var1, _var2, _var3;
TString4 _module;
TFilename _tabapp, _relapp;
};
HIDDEN int find_tabapp(TConfig& cfg, void* jolly)
{
TCallbackTableinfo& info = *((TCallbackTableinfo*)jolly);
if (cfg.exist(info._var1))
{
info._tabapp = cfg.get(info._var1);
if (info._tabapp.not_empty())
return 1;
}
if (cfg.get_paragraph().compare(info._module, 2, TRUE) == 0)
{
if (cfg.exist(info._var2))
{
info._relapp = cfg.get(info._var2);
if (info._relapp.not_empty())
return 2;
}
if (info._var3.full() && cfg.exist(info._var3))
{
info._relapp = cfg.get(info._var3);
if (info._relapp.not_empty())
return 3;
}
}
return 0;
}
bool get_tabapp(const char* tabname, TString& app)
{
TConfig ini(CONFIG_GENERAL, "Main");
TCallbackTableinfo fi;
TTable t(tabname);
fi._var1.format("Edit_%s", t.name());
fi._var2.format("Edit_%d", t.num());
fi._var3.format("Edit_%d", t.num() == LF_TABCOM ? LF_TAB : LF_TABCOM);
fi._module = t.module();
ini.for_each_paragraph(find_tabapp, &fi);
app = fi._tabapp;
if (app.empty())
app = fi._relapp;
if (app.empty())
{
app = "ba3 -0";
if (!fi._module.starts_with("ba")) // Compatibility mode :-(
{
const TString& tp = ini_get_string(CONFIG_STUDIO, fi._module, "TabPrg");
if (tp.full())
app = tp;
}
}
app << ' ' << tabname;
return tabname && *tabname > ' ';
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Funzioni implementate per la gestione file dati tramite Codebase
////////////////////////////////////////////////////////////////////////////////////////////////////
// Inizio(@)
// @doc INTERNAL
// @func Ritorna una Token_string con in nome dell'indice
int get_table_names(
int logicnum, // @parm Numero logico del file di cui riconoscere l'indice
TToken_string& i_names, // @parm Token_string in cui inserire il nome dell'indice
int mode)
// @comm Ritorna il nome con il prefisso corrente
{
TFilename f = prefix().get_filename(logicnum);
i_names.cut(0);
if (mode & 1)
i_names = f;
if (mode & 2)
{
f.ext("cdx");
i_names.add(f);
}
if (mode & 4)
{
f.ext("fpt");
if (f.exist())
i_names.add(f);
}
return i_names.items();
}
// Converte un errore di codebase in un errore isam
#ifdef DBG
HIDDEN int cb_error = NOERR;
#endif
int get_error(int err)
{
// Codici negativi
HIDDEN int error_codes_g[] = {-1,_isnotopen,-1,-1,-1,_islocked,-1,-1,-1,-1,-1,-1,_isfilefull,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,_iskeynotfound,_ispatherr,-1,-1,_isdupkey};
// Codici da 0 a 9
HIDDEN int error_codes_ra[] = {NOERR,NOERR,_iskeynotfound,_iseof,_isbof,_isnrecerr} ;
// Codici da 10 a ...
HIDDEN int error_codes_rb[] = {-1,-1,_isreinsert,-1,-1,_islocked,-1,_isalropen,_iskeyerr } ;
int isamerr = NOERR;
#ifdef DBG
if (err <= 200 || err >= 230)
cb_error = err;
#endif
if (err > 0)
{
if (err >= 10)
{
if (err > 80 || error_codes_rb[err/10]==-1)
isamerr = err;
else
isamerr = error_codes_rb[err/10];
}
else
isamerr = error_codes_ra[err];
}
else
if (err < 0)
{
if (err == -1)
{
#ifdef DBG
int ierr = DB_get_error();
#endif
isamerr = _isnotopen;
}
else
{
int ierr = DB_get_error();
if (ierr == 0) ierr = -err; // DB_get_error already called
if (ierr < 0) ierr = -ierr;
if (ierr > 340 || error_codes_g[ierr/10]==-1)
isamerr = -ierr;
else
isamerr = error_codes_g[ierr/10];
}
}
DB_zero_error();
return isamerr;
}
// Used also by varrec
bool rec_has_memo(const RecDes& rd)
{
for( int i = rd.NFields - 1; i >= 0; i--)
if (rd.Fd[i].TypeF == _memofld)
return true;
return false;
}
HIDDEN bool lf_has_memo(int lffile)
{
return rec_has_memo(prefix().get_recdes(lffile));
}
HIDDEN void browse_null(char *start, int nc)
{
for (int i = nc - 1; i >= 0 ; i--) // Anche il primo byte(deletion flag) deve essere cambiato. nc comprende il primo byte
if (start[i] == '\0') start[i] = ' ';
}
// Traduce l'espressione chiave di CodeBase
HIDDEN int __build_key(const RecDes& recd, int numkey, const RecType recin, char *key, bool build_x_cb)
/* *recd; descrittore record */
/* numkey; numero chiave */
/* recin; buffer contenente il record */
/* *key; valore della chiave */
/* build_x_cb flag di costruzione per codebase */
{
CHECKD(numkey > 0, "Can't build key ", numkey);
const char null_char = -1;
key[0] = '\0';
if (numkey-- <= recd.NKeys)
{
int l = 0;
for (int i = 0; i < recd.Ky[numkey].NkFields; i++)
{
const KeyDes& kd = recd.Ky[numkey];
const bool upp = kd.FieldSeq[i] > MaxFields;
const int nf = upp ? kd.FieldSeq[i] - MaxFields : kd.FieldSeq[i];
const RecFieldDes& rf = recd.Fd[nf];
const TFieldtypes f = (TFieldtypes) rf.TypeF;
int off, len;
if (kd.FromCh[i] == 255)
{
off = rf.RecOff;
len = rf.Len;
}
else
{
off = rf.RecOff + kd.FromCh[i];
len = kd.ToCh[i] - kd.FromCh[i] + 1;
}
if ((l + len) > 255)
{
key[0] = '\0';
return(_iskeylenerr);
}
if (f == _boolfld)
{
const bool on = *(recin + off) > ' ' && strchr("STXY", *(recin + off)) != NULL;
key[l] = on ? 'T' : 'F';
}
else
strncpy((key + l), (recin + off), len);
if (recin[off] == '\0')
{
memset(key + l, ' ', len);
if ((f == _intfld) || (f == _longfld) || (f == _wordfld) ||
(f == _intzerofld) || (f == _longzerofld))
key[l + len - 1] = build_x_cb ? '0' : null_char;
}
else
if ((f == _intfld) || (f == _longfld) || (f == _wordfld) || (f == _intzerofld) || (f == _longzerofld))
{
int w = l, j = l + len;
while (w < j && key[w] == ' ') w++;
while (w < j && key[w] == '0') key[w++] = ' ';
if (w == j) key[w-1] = build_x_cb ? '0' : null_char;
}
if (upp)
for (int i = l+len-1; i >= l; i--)
key[i] = toupper(key[i]);
l += len;
}
// rtrim
if (build_x_cb)
{
for (l--; l>=0 && key[l] == ' '; l--);
key[l + 1] = '\0';
}
else
{
for (l--; l>=0 && (key[l] == ' ' || key[l] == null_char); l--);
key[l + 1] = '\0';
for (;l >= 0; l--)
if (key[l] == null_char)
key[l] = '0';
}
return(NOERR);
}
return(_ispatherr);
}
HIDDEN int cisread(int fhnd, int knum, TRectype& record, int mode, TRecnotype& curr_recno)
{
CHECKD(fhnd >= 0, "Can't use codebase handle ", fhnd);
const int rmode = (mode & READTYPES);
const int lmode = (mode & RECLOCKTYPES);
// Non usare mai _isnextn o _isprevn, usare il metodo skip!
CHECK (rmode !=_isnextn && rmode !=_isprevn, "_isnextn and _isprevn not supported in cisread");
TString256 keystr;
char* key = keystr.get_buffer();
int err = NOERR;
do
{
if (rmode>=_isequal && rmode<=_isgteq)
{
const RecDes& r = record.rec_des();
err=__build_key(r, knum, record.string(),key,TRUE);
if (err == NOERR)
{
err = DB_seek(fhnd,key);
if (err == NOERR && rmode == _isgreat)
err = DB_next(fhnd);
if (err != NOERR)
err = get_error(err);
}
if (rmode != _isequal && err == _iskeynotfound)
err = NOERR;
}
else
{
if (rmode==_isfirst)
err=DB_first(fhnd);
else
if (rmode==_islast)
err=DB_last(fhnd);
else
if (rmode==_isnext)
{
if (curr_recno != DB_recno(fhnd))
{
const RecDes& r = record.rec_des();
err = __build_key(r, knum, record.string(),key,TRUE);
if (err == NOERR)
{
err = DB_seek(fhnd,key);
err = get_error(err);
if (err != NOERR && err != _iskeynotfound && err != _iseof)
fatal_box("Errore nella next %d : non posso riposizionarmi", err);
else
if (err == NOERR)
err=DB_next(fhnd);
}
}
else
err=DB_next(fhnd);
}
else
if (rmode==_isprev)
{
if (curr_recno != DB_recno(fhnd))
{
const RecDes& r = record.rec_des();
err = __build_key(r, knum, record.string(),key,TRUE);
if (err == NOERR)
{
err = DB_seek(fhnd,key);
err = get_error(err);
if (err != NOERR && err != _iskeynotfound && err != _iseof)
fatal_box("Errore nella prev %d : non posso riposizionarmi", err);
else
if (err == NOERR)
err=DB_prev(fhnd);
}
}
else
err=DB_prev(fhnd);
}
else
if (rmode==_iscurr)
err=DB_go(fhnd,DB_recno(fhnd));
if (err != NOERR)
err=get_error(err);
}
if (err == _iseof)
DB_last(fhnd);
if (err == NOERR && (lmode == _lock || lmode == _testandlock)) // _lock e _testandlock
{
err=DB_lock(fhnd);
if (err != NOERR)
err = get_error(err);
if (err == _islocked && lmode == _testandlock)
break;
}
if (err == _islocked)
{
const RecDes& r = record.rec_des();
record = (const char*)DB_getrecord(fhnd);
__build_key(r, knum, record.string(), key, TRUE);
message_box("Codice %s in uso da parte\ndi un altro utente.", key);
if (lmode != _lock)
break;
}
} while (err ==_islocked);
if (err == NOERR && lmode == _unlock)
{
err=DB_unlock(fhnd);
if (err != NOERR)
err = get_error(err);
}
curr_recno = DB_recno(fhnd);
record = (const char *)DB_getrecord(fhnd);
return err;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Funzioni implementate per la gestione file dati tramite Codebase
////////////////////////////////////////////////////////////////////////////////////////////////////
// Fine(@)
// @doc EXTERNAL
// @func Setta il valore della variabile <p __autoload>
void set_autoload_new_files(
bool on) // @parm Valore da assegnare
// @comm Il valore di <p __autoload> indica il caricamento dei valori standard dei file
{
__autoload = on;
}
///////////////////////////////////////////////////////////
// TBaseisamfile
///////////////////////////////////////////////////////////
TBaseisamfile::TBaseisamfile(int logicnum)
{
_logicnum = logicnum;
_isam_handle = 0;
_curr_key = 0;
_lasterr = NOERR;
_current = new TRectype(logicnum);
}
// @doc EXTERNAL
// @mfunc Reperisce il tracciato dal file stesso.
//
TBaseisamfile::TBaseisamfile(
const char* name, // @parm Indica il nome del file
const char* descname) // @parm Indica la descrizione del file
// @comm Esiste la possibilita' di codificare i valori di pathpref e prefix in <p name>
// % si riferisce ai dati comuni
// $ si riferisce ai dati di ditta corrente
// # si riferisce al direttorio indicato da PATHPREF.INI
{
if (descname && *descname)
{
TTrec r;
ifstream f(descname);
f >> r;
const int err=DB_build(name, &r.rec()) ;
if (err != NOERR)
fatal_box("Non posso creare il file %s : errore n.ro %d", name, err);
}
_lasterr = NOERR;
TFilename filename(name);
CHECK(filename.full(),"Must define the file to open!");
_logicnum = prefix().get_handle(filename);
_current = new TRectype(this);
}
TBaseisamfile::~TBaseisamfile()
{
if (_current)
delete _current;
}
TCodeb_handle TBaseisamfile::handle(int key) const
{
return prefix().get_handle(_isam_handle, key > 0 ? key : _curr_key);
}
TRecnotype TBaseisamfile::items() const
{
return DB_reccount(handle());
}
const char* TBaseisamfile::name() const
{
TString& tmp = get_tmp_string();
tmp.format("%d", num());
return tmp;
}
const char* TBaseisamfile::module() const
{
TFilename app;
curr().get_relapp(app);
if (app.full())
return app.left(2);
return "ba";
}
const char* TBaseisamfile::filename() const
{
const int n = _isam_handle > 0 ? _isam_handle : num();
TString& tmp = get_tmp_string();
tmp = prefix().get_filename(n);
tmp << ".dbf";
return tmp;
}
const char* TBaseisamfile::description()
{
const int n = _isam_handle > 0 ? _isam_handle : num();
const FileDes& d = prefix().get_filedes(n);
return d.Des;
}
TRecnotype TBaseisamfile::eod() const
{
return items();
}
void TBaseisamfile::set_curr(TRectype * curr)
{
CHECK(curr != NULL, "You must set a valid current record");
CHECK(num() == curr->num(), "You must set a coherent current record");
if (_current != NULL)
delete _current;
_current = curr;
}
void TBaseisamfile::setkey(int nkey)
{
_curr_key = nkey;
}
int TBaseisamfile::getkey() const
{
return _curr_key;
}
int TBaseisamfile::first(word lockop)
{
return TBaseisamfile::read(curr(), _isfirst, lockop);
}
int TBaseisamfile::last(word lockop)
{
return TBaseisamfile::read(curr(), _islast, lockop);
}
int TBaseisamfile::next(word lockop)
{
return TBaseisamfile::read(curr(), _isnext, lockop);
}
int TBaseisamfile::prev(word lockop)
{
return TBaseisamfile::read(curr(), _isprev, lockop);
}
int TBaseisamfile::reread(word lockop)
{
return TBaseisamfile::reread(curr(), lockop);
}
int TBaseisamfile::reread(TRectype& rec, word lockop)
{
return rec.read(*this, _iscurr, lockop);
}
int TBaseisamfile::skip(TRecnotype nrec, word lockop)
{
if (nrec == 0)
return NOERR;
curr().setdirty();
const int fhnd = handle();
// controllo se mi sono spostato dall'ultima lettura
if (_recno != DB_recno(fhnd))
{
_lasterr = DB_go(fhnd, _recno);
if (_lasterr != NOERR)
{
_lasterr = get_error(_lasterr);
if (_lasterr != _islocked)
fatal_box("Errore nella skip %d : non posso riposizionarmi", _lasterr);
}
}
_lasterr=DB_skip(fhnd, nrec);
if (_lasterr != NOERR)
_lasterr = get_error(_lasterr);
while (_lasterr ==_islocked)
{
const RecDes& r = prefix().get_recdes(num());
TString256 key;
__build_key(r, _curr_key, curr().string(), key.get_buffer(), TRUE);
message_box("Codice %s in uso da parte\ndi un altro utente.\nSkipping", (const char*)key);
_lasterr = cisread(fhnd, getkey(), curr(),_iscurr + lockop, _recno);
}
_recno = DB_recno(fhnd);
if (curr().has_memo())
curr().init_memo(_recno, _isam_handle);
return _lasterr;
}
// funzione di lettura dei file
int TBaseisamfile::_read(TRectype& rec, word op, word lockop)
{
const TCodeb_handle fhnd = handle();
rec.setdirty();
_lasterr = cisread(fhnd, getkey(), rec, op + lockop, _recno);
// _recno = DB_recno(fhnd); // Gia' fatto nella cisread
if(rec.has_memo())
rec.init_memo(_recno, _isam_handle);
if (_lasterr == NOERR)
{
if (lockop == _lock || lockop == _testandlock)
prefix().lock_record(_isam_handle, _recno); else
if (lockop == _unlock)
prefix().unlock_record(_isam_handle, _recno);
}
return _lasterr;
}
int TBaseisamfile::read(TRectype& rec, word op, word lockop)
{
_lasterr=rec.read(*this, op, lockop);
return _lasterr;
}
int TBaseisamfile::read(word op, word lockop)
{
return TBaseisamfile::read(curr(), op, lockop);
}
int TBaseisamfile::readat(TRectype& rec, TRecnotype nrec, word lockop)
{
return rec.readat(*this, nrec, lockop);
}
int TBaseisamfile::readat(TRecnotype nrec, word lockop)
{
return TBaseisamfile::readat(curr(), nrec, lockop);
}
int TBaseisamfile::_readat(TRectype& rec, TRecnotype nrec, word lockop)
{
const int fhnd = handle();
rec.setdirty();
_lasterr = DB_go(fhnd, nrec);
if (_lasterr != NOERR)
_lasterr = get_error(_lasterr);
else
rec = (const char*)DB_getrecord(fhnd);
_recno = DB_recno(fhnd);
if (rec.has_memo())
rec.init_memo(_recno, _isam_handle);
return _lasterr;
}
int TBaseisamfile::_write(const TRectype& rec)
{
CHECK(!rec.empty(), "Can't write an empty record");
// Controlla che la chiave sia piena
TString256 key;
__build_key(rec.rec_des(), 1, rec.string(), key.get_buffer(), true);
if (key.blank())
return _iskeyerr;
if (dongle().demo() && items() > 979L)
return _isfilefull;
// Forza l'uso della chiave principale (per chiavi duplicate?)
const int fhnd = handle(_curr_key > 0 ? 1 : 0);
const int dst_len = DB_reclen(fhnd);
if (dst_len != rec.len())
NFCHECK("Record size mismatch on file %d: RecDes=%d, DB_reclen=%d",
_logicnum, rec.len(), dst_len);
browse_null(rec.string(), dst_len);
memcpy(DB_getrecord(fhnd), rec.string(), dst_len);
_lasterr = DB_add(fhnd);
_recno = DB_recno(fhnd);
if (_lasterr == NOERR)
{
if (rec.has_memo())
((TRectype&)rec).write_memo(_isam_handle, _recno );
}
else
_lasterr = get_error(_lasterr);
return _lasterr;
}
int TBaseisamfile::write(const TRectype& rec)
{
return rec.write(*this);
}
int TBaseisamfile::write()
{
return TBaseisamfile::write(curr());
}
int TBaseisamfile::write_rewrite(const TRectype& rec)
{
return rec.write_rewrite(*this);
}
int TBaseisamfile::write_rewrite()
{
return TBaseisamfile::write_rewrite(curr());
}
int TBaseisamfile::rewrite_write(const TRectype& rec)
{
return rec.rewrite_write(*this);
}
int TBaseisamfile::rewrite_write()
{
return TBaseisamfile::rewrite_write(curr());
}
int TBaseisamfile::_rewrite(const TRectype& rec)
{
CHECK(!rec.empty(), "Can't write an empty record");
TRectype save_rec(rec);
// Forza l'uso della chiave principale (per chiavi duplicate?)
const int fhnd = handle(1);
_lasterr = cisread(fhnd, 1, save_rec, _isequal + _nolock, _recno); // Si Posiziona per sicurezza...
if (_lasterr == NOERR)
{
const int len = DB_reclen(fhnd);
if (len != save_rec.len())
NFCHECK("Record size mismatch on file %d: RecDes=%d, DB_reclen=%d",
_logicnum, save_rec.len(), len);
browse_null(rec.string(), len);
if (memcmp(rec.string(), save_rec.string(), len) != 0)
{
memcpy(DB_getrecord(fhnd), rec.string(), len);
_lasterr = DB_rewrite(fhnd);
if (_lasterr == NOERR)
rec_cache(_logicnum).notify_change();
else
_lasterr = get_error(_lasterr);
}
else
DB_unlock(fhnd); // non vale la pena farlo sempre ?
_recno = DB_recno(fhnd);
prefix().unlock_record(_isam_handle, _recno);
if (_lasterr == NOERR)
{
if (curr().has_memo())
((TRectype&)rec).write_memo(_isam_handle, _recno);
}
}
return _lasterr;
}
int TBaseisamfile::rewrite(const TRectype& rec)
{
return rec.rewrite(*this);
}
int TBaseisamfile::rewrite()
{
return TBaseisamfile::rewrite(curr());
}
int TBaseisamfile::rewriteat(const TRectype& rec, TRecnotype nrec)
{
const int fhnd = handle();
if ((_lasterr=DB_go(fhnd,nrec))== NOERR)
{
browse_null(rec.string(),DB_reclen(fhnd));
memcpy(DB_getrecord(fhnd),rec.string(),DB_reclen(fhnd));
_lasterr=DB_rewrite(fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
}
else
_lasterr = get_error(_lasterr);
_recno = DB_recno(fhnd);
if(_lasterr == NOERR)
{
if (curr().has_memo())
((TRectype &)rec).write_memo(_isam_handle, _recno);
rec_cache(_logicnum).notify_change();
}
return _lasterr;
}
int TBaseisamfile::rewriteat(TRecnotype nrec)
{
return TBaseisamfile::rewriteat(curr(),nrec);
}
int TBaseisamfile::_remove(const TRectype& rec)
{
CHECK(!rec.empty(), "Can't remove an empty record");
const int fhnd = handle(1); // Forza l'uso della chiave principale (per chiavi duplicate?)
TRectype save_rec(rec);
_lasterr = cisread(fhnd, 1, save_rec, _isequal + _nolock, _recno); // Si Posiziona per sicurezza...
if (_lasterr == NOERR)
{
_lasterr = DB_delete(fhnd); // Put only deletion flag on record, must remove keys too!
if (_lasterr == NOERR)
{
if (curr().has_memo( ))
curr().init_memo();
rec_cache(_logicnum).notify_change();
DB_flush(fhnd);
}
else
_lasterr = get_error(_lasterr);
}
if (_lasterr != NOERR)
DB_recall(fhnd);
return _lasterr;
}
int TBaseisamfile::remove(const TRectype& rec)
{
return rec.remove(*this);
}
int TBaseisamfile::remove()
{
return TBaseisamfile::remove(curr());
}
int TBaseisamfile::lock()
{
const int fhnd = handle();
_lasterr = DB_lockfile(fhnd);
if (_lasterr != NOERR)
_lasterr = get_error(_lasterr);
return _lasterr;
}
int TBaseisamfile::unlock()
{
const int fhnd = handle();
_lasterr = DB_unlock(fhnd);
if (_lasterr != NOERR)
_lasterr = get_error(_lasterr);
return (_lasterr);
}
void TBaseisamfile::indexon()
{
}
void TBaseisamfile::indexoff()
{
}
bool TBaseisamfile::empty()
{
return items() <= 0;
}
// @doc EXTERNAL
// @mfunc Apre il file isam di base con lock
//
// @rdesc Ritorna NOERR se e' riuscita ad aprire il file, altrimenti ritorna il numero di errore
// generato (vedi <t TIsamerr>).
int TBaseisamfile::_open(
unsigned int mode, // @parm Indica il modo di apertura del file (default _manulock)
bool index) // @parm Indica se aprire con indici o meno (default TRUE)
// @comm Il parametro <p mode> puo' assumere i valori:
//
// @flag _manulock | Il lock dei record viene fatto manualmente
// @flag _exclock | Il file viene aperte in modo esclusivo
// @flag _autolock | Il lock dei record viene fatto in modo automatico
// @comm Il parametro <p index> puo' assumere i valori:
//
// @flag TRUE | Il file viene aperto con indici
// @flag FALSE | Il file viene aperto senza indici
{
CHECKD(_isam_handle == 0, "Can't reopen file ", _logicnum);
_curr_key = index ? 1 : 0;
TFilename filename;
_isam_handle = prefix().open_isamfile(_logicnum, filename, mode==_excllock, index);
if (_isam_handle > 0)
{
TCodeb_handle cb_handle = prefix().get_handle(_isam_handle, _curr_key);
const int dbfreclen = DB_reclen(cb_handle);
const int trcreclen = prefix().get_reclen(_logicnum);
const TRecnotype n = DB_reccount(cb_handle);
if (dbfreclen != trcreclen)
{
TString msg;
msg.format("Lunghezza record incoerente sul file %d (%s): file=%d trc=%d",
num(), (const char*)filename, dbfreclen, trcreclen);
if (n <= 0)
{
msg << "\nSi consiglia di eliminare il file ed i suoi indici.";
error_box(msg);
}
else
fatal_box(msg);
}
if (prefix().get_recdes(_logicnum).NKeys <= 0)
fatal_box("Il file %d (%s) e' senza indici", num(), (const char*)filename);
_recno = RECORD_NON_FISICO;
setkey(_curr_key);
_lasterr = NOERR;
}
else
{
TString e_msg;
_lasterr = get_error(_isam_handle);
if (_lasterr == -60)
{
if (!filename.exist())
e_msg.format("Il file %d(%s) non esiste, errore %d",num(),(const char*)filename,_lasterr);
else
e_msg.format("Il file %d(%s) e' aperto in modo esclusivo da un'altra applicazione",
num(), (const char*)filename);
}
if (e_msg.empty())
e_msg.format("Il file %d(%s) non puo' essere aperto, errore %d",num(),(const char*)filename,_lasterr);
fatal_box((const char*) e_msg);
}
return _lasterr;
}
int TBaseisamfile::_open_ex(
unsigned int mode, // @parm Indica il modo di apertura del file (default _manulock)
bool index) // @parm Indica se aprire con indici o meno (default TRUE)
// @comm Il parametro <p mode> puo' assumere i valori:
//
// @flag _manulock | Il lock dei record viene fatto manualmente
// @flag _exclock | Il file viene aperte in modo esclusivo
// @flag _autolock | Il lock dei record viene fatto in modo automatico
// @comm Il parametro <p index> puo' assumere i valori:
//
// @flag TRUE | Il file viene aperto con indici
// @flag FALSE | Il file viene aperto senza indici
{
CHECKD(_isam_handle == 0, "Can't reopen file ", _logicnum);
_curr_key = index ? 1 : 0;
TFilename filename;
_isam_handle = prefix().open_isamfile(_logicnum, filename, mode==_excllock, index);
if (_isam_handle > 0)
{
if (prefix().get_reclen(_logicnum) > 0)
{
const int fhnd = handle();
if (fhnd >= 0)
{
_recno = RECORD_NON_FISICO;
_lasterr = NOERR;
}
else
_lasterr = get_error(fhnd);
}
else
_lasterr = _isbadtrc;
}
else
{
_lasterr = get_error(_isam_handle);
_isam_handle = 0;
}
return _lasterr;
}
int TBaseisamfile::_close()
{
int err = NOERR;
if (prefix_valid())
{
err = prefix().close_isamfile(_isam_handle);
setstatus(err);
}
return err;
}
int TBaseisamfile::is_valid(bool exclusive)
{ // Ritorna NOERR se il file puo' essere aperto senza errori
CHECKD(_isam_handle == 0, "Can't reopen file ", _logicnum);
TFilename filename;
TIsam_handle isam_handle = prefix().open_isamfile(_logicnum, filename, exclusive, true);
TCodeb_handle fhnd = isam_handle > 0 ? prefix().get_handle(isam_handle,1) : isam_handle;
int err = NOERR;
if (fhnd < 0)
err = get_error(fhnd);
else
{
const int trcreclen = prefix().get_reclen(_logicnum);
if (trcreclen > 0)
{
if (DB_tagget(fhnd) == -1)
err = _ispatherr;
else
{
const int dbfreclen = DB_reclen(fhnd);
if (dbfreclen != trcreclen)
{
err = _istrcerr;
if (_logicnum == LF_CLIFO)
error_box("Clifo trc=%d dbf=%d", trcreclen, dbfreclen);
}
}
}
else
err = _isbadtrc;
}
if (isam_handle > 0)
prefix().close_isamfile(isam_handle);
return err;
}
bool TBaseisamfile::get_relapp(TString& app) const
{
return curr().get_relapp(app);
}
bool TBaseisamfile::is_changed_since(long& last) const
{
bool yes = false;
#ifdef WIN32
int fh = 0;
::_sopen_s(&fh, filename(), _O_RDONLY, _SH_DENYNO, _S_IREAD);
if (fh > 0)
{
struct stat stat;
if (::fstat(fh, &stat) == 0)
{
const long tim = long(stat.st_mtime) ^ long(stat.st_size);
yes = tim != last;
last = tim;
}
::_close(fh);
}
#else
struct stat stat;
if (lstat(filename(), &stat) == 0)
{
const long tim = long(stat.st_mtime) ^ long(stat.st_size);
yes = tim != last;
last = tim;
}
#endif
return yes;
}
///////////////////////////////////////////////////////////
// TLocalisamfile
///////////////////////////////////////////////////////////
// @doc EXTERNAL
// @mfunc Costruttore
//
// @rdesc Ritorna l'oggetto <c TLocalisamfile>
TLocalisamfile::TLocalisamfile(
int logicnum) // @parm Numero del logico del file
: TBaseisamfile(logicnum)
{
if (open() != NOERR)
fatal_box("Impossibile aprire il file %d", logicnum);
}
// @mfunc Costruttore
//
// @rdesc Ritorna l'oggetto <c TLocalisamfile>
TLocalisamfile::TLocalisamfile(
const char* name, // @parm Nome del file esterno da aprire
const char* descname) // @parm Indica la descrizione del file
: TBaseisamfile(name, descname)
{
}
TLocalisamfile::TLocalisamfile(int logicnum, bool tmpfile)
: TBaseisamfile(logicnum)
{
CHECK(tmpfile == TRUE, "Protected constructor badly used");
}
TLocalisamfile::~TLocalisamfile()
{
close();
}
int TLocalisamfile::close()
{
return TBaseisamfile::_close();
}
int TLocalisamfile::open(unsigned int mode)
{
return TBaseisamfile::_open(mode);
}
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)
: TBaseisamfile(logicnum)
{ }
TIsamfile::~TIsamfile()
{
close();
}
///////////////////////////////////////////////////////////
// TIsamtempfile
///////////////////////////////////////////////////////////
TIsamtempfile::TIsamtempfile(int logicnum, const char* radix, bool create, bool autodel)
: TLocalisamfile(logicnum, TRUE)
{
TRecnotype eod = 0;
TRecnotype eox = 100;
TFilename n;
if (radix && *radix)
{
if (*radix == '%')
n = radix + 1;
else
{
n.tempdir();
n.add(radix);
}
n.ext("dbf");
}
else
n.temp(NULL, "dbf");
if (!create)
{
const long sz = fsize(n);
if (sz <= 64)
fatal_box("Impossibile aprire il file %s", (const char*)n);
const long len = curr().len();
eod = eox = sz / len;
}
CHECK(create == FALSE || create == TRUE, "Il flag di autodel ora si setta con il terzo parametro del costruttore");
_autodel = autodel || (create != FALSE && create != TRUE);
n.insert("%", 0);
open(n, create, eod, eox);
}
TIsamtempfile::~TIsamtempfile()
{
close();
}
// @doc EXTERNAL
// @mfunc Apre il file
//
// @rdesc Ritorna NOERR se e' riuscita ad aprire il file, altrimenti ritorna il numero di errore
// generato (vedi <t TIsamerr>).
int TIsamtempfile::open(
const char* radix, // @parm Radice del path del file
bool create, // @parm Indica se va creato un nuovo file (se FALSE il file esiste gia')
TRecnotype eod, // @parm Numero di record presenti nel file
TRecnotype eox) // @parm Numero di record da aggiungere al file
// @comm Nel case <p create> sia TRUE allora viene settato automaticamente il valore di <p _autodel>
// a TRUE, cioe' viene abilitata l'eliminazione del file in chiusura.
{
int err = NOERR;
TFilename filename;
if (radix[0] == '%')
filename = radix+1;
else
filename.temp(radix);
filename.ext("");
CHECKS(_isam_handle == 0, "File already open ", (const char*)filename);
if (create)
{
RecDes* r = (RecDes*)&prefix().get_recdes(num());
err = DB_build(filename, r) ;
if (err != NOERR)
{
err = get_error(err);
fatal_box("Can't create temp file '%s' num. %d: Error n. %d", (const char*)filename, num(), err);
}
}
else
{
TFilename test = filename; test.ext("dbf");
for (int t = 0; t < 2; t++)
{
test.ext(t == 0 ? "dbf" : "cdx");
if (!test.exist())
{
err = -60;
break;
}
}
}
if (err == NOERR)
{
_isam_handle = prefix().open_isamfile(_logicnum, filename, true);
TCodeb_handle fhnd = handle(_curr_key = 1);
if (fhnd < 0)
err = get_error(fhnd);
}
if (err != NOERR)
{
filename.ext("dbf");
if (err == -60)
{
if (!filename.exist())
fatal_box("Apertura file %s : errore n. %d. File non esistente.",(const char*)filename,err);
else
fatal_box("Apertura file %s : errore n. %d. File aperto in uso esclusivo da un'altra applicazione.",(const char*)filename,err);
}
else
fatal_box("Apertura file %s : errore n. %d ",(const char*)filename,err);
}
_recno = RECORD_NON_FISICO;
setstatus(err);
return err;
}
int TIsamtempfile::close()
{
TFilename f = filename();
int err = prefix().close_isamfile(_isam_handle);
if (err == NOERR && _autodel)
{
const long c = DB_getconf();
f.ext("dbf");
::remove(f);
if (c & 1)
f.ext("fpt");
else
f.ext("dbt");
::remove(f);
if (c & 1) // FOXPRO format
f.ext("cdx");
if (c & 4) // DBIV format
f.ext("mdx");
if (c & 8 || c & 2) // CLIPPER and DBIII format
{
f.ext("cgp");
FILE* fp=NULL; fopen_s(&fp, f, "r");
char in[16];
while (fgets(in,16,fp)!=NULL)
{
TFilename a(in);
if (c & 8) // DBIII format
a.ext("ndx");
else
a.ext("ntx"); // CLIPPER format
::remove((const char *)a);
}
fclose(fp);
}
::remove(f);
if (curr().has_memo()) // Cancella eventuale file dei memo
{
f.ext("fpt");
::remove(f);
}
}
setstatus(err);
return err;
}
///////////////////////////////////////////////////////////
// TExternisamfile
///////////////////////////////////////////////////////////
TExternisamfile::TExternisamfile(const char* name, bool exclusive, bool index)
: TLocalisamfile(name)
{
init(name, exclusive, index);
}
TExternisamfile::TExternisamfile(const char* name, const char* descname, bool exclusive, bool index)
: TLocalisamfile(name, descname)
{
init(name, exclusive, index);
}
TExternisamfile::~TExternisamfile()
{
close();
}
void TExternisamfile::init(const char* name, bool exclusive, bool index)
{
_name = name;
_name.ext("dbf");
// Espande il nome!
const char c = _name[0];
if (c == '%' || c == '$')
_name = CAddPref(_name.get_buffer());
else
if (c == '#')
{
_name.ltrim(1);
_name.format("%s/%s",__ptprf,(const char*)_name);
}
open(exclusive, index);
}
int TExternisamfile::open(bool exclusive, bool index)
{
_isam_handle = prefix().open_isamfile(_logicnum, _name, exclusive, index);
if (_isam_handle > 0)
{
if (prefix().get_recdes(_logicnum).NKeys <= 0)
fatal_box("Il file %d (%s) e' senza indici", num(), (const char*)filename());
_recno = RECORD_NON_FISICO;
setkey(1);
_lasterr = NOERR;
}
else
{
TString e_msg;
_lasterr = get_error(_isam_handle);
if (_lasterr == -60)
{
if (!_name.exist())
e_msg.format("Il file %d(%s) non esiste, errore %d",num(),(const char*)_name,_lasterr);
else
e_msg.format("Il file %d(%s) e' aperto in modo esclusivo da un'altra applicazione",
num(), (const char*)_name);
}
if (e_msg.empty())
e_msg.format("Il file %d(%s) non puo' essere aperto, errore %d",num(),(const char*)_name,_lasterr);
fatal_box((const char*) e_msg);
}
return _lasterr;
}
int TExternisamfile::close()
{
return _close();
}
int TExternisamfile::zap()
{
RecDes rd = curr().rec_des();
int err = prefix().close_isamfile(_isam_handle);
if (err == NOERR)
{
err = DB_packfile(TRUE, _name, 0);
if (err == NOERR)
{
TRecnotype peod;
err = DB_packindex(TRUE, _name, &rd, &peod, FALSE);
}
_isam_handle = prefix().open_isamfile(_logicnum, _name);
}
return err;
}
const char* TExternisamfile::name() const
{
return filename();
}
///////////////////////////////////////////////////////////
// TSystemisamfile
///////////////////////////////////////////////////////////
int TSystemisamfile::build(const TTrec& r)
{
int err = NOERR;
const TDir d(num());
if (r.len() > 0)
{
TFilename f(filename());
TFilename fname(f); fname.ext(""); // sostituto per _filename
f = f.path(); if (!is_not_slash(f.right(1)[0])) f.rtrim(1);
if (!dexist(f))
make_dir(f);
err=DB_build(fname, &r.rec());
if (err != NOERR)
err = get_error(err);
setstatus(err);
if (err == NOERR && __autoload)
{
TFilename lf;
lf.format("%sstd/lf%04d.txt", __ptprf, num());
if (fexist(lf))
load(lf, '|', '\0', '\n', TRUE, TRUE);
}
}
else
{
NFCHECK("Can't create a file with empty field info");
setstatus(_isbadtrc);
}
return err;
}
int TSystemisamfile::build()
{
TTrec r;
r.get(num());
return build(r);
}
long TSystemisamfile::size(TRecnotype eox)
{
return 51200L;
}
#ifndef FOXPRO
// @doc INTERNAL
// @mfunc Esegue la conversione del file
//
// @rdesc Ritorna il rusultato dell'operazione
//
// @flag TRUE | Se la conversione e' stata effettuata correttamente
// @flag FALSE | Se h stato rilevato un errore durante la conversione (viene emesso un <f error_box>)
int TSystemisamfile::exec_convapp(
long flev, // @parm Livello a cui aggiornare l'archivio
const bool before) // @parm Indica se viene chiamata prima o dopo la conversione
{
const char * const v = before ? "BCNV" : "ACNV";
int err = 0;
if (flev == 0) flev = 199401;
else flev++;
TConfig conv(CONFIG_FCONV);
TString16 paragraph;
TString_array paralist;
conv.list_paragraphs(paralist);
for (unsigned int l = flev; err == 0 && l <= prefix().get_stdlevel(); l++)
{
paragraph.format("%06ld", l);
if (paralist.find(paragraph) < 0)
continue;
if (conv.set_paragraph(paragraph) && conv.exist(v, num()))
{
TToken_string s(conv.get(v, NULL, num()), ' ');
TFilename f(s.get(0));
f.ext(".exe");
s << ' ' << prefix().get_codditta();
TExternal_app app(s);
if (f.exist())
{
err = app.run(FALSE, 0x3); // Synchronous Spawn with User
TMailbox mail;
TMessage* msg = mail.next(TRUE);
if (err == 0 && msg != NULL)
err = atoi(msg->body());
}
if (err && err != 8)
return error_box("Impossibile eseguire il programma di %sconversione\ndel livello %ld/%ld\nErrore n.ro %d", before ? "pre" : "post", l / 100, l % 100, err);
}
}
return err;
}
// @doc INTERNAL
// @mfunc Recupera le conversioni logiche da effettuare sul file
//
// @rdesc Ritorna TRUE se occorre effettuare la conversione sul file
bool TSystemisamfile::getlcf(
long flev) // @parm livello archivi di partenza della convesione
// @comm Recupera le conversioni logiche da effettuare sul file per per passare dal
// livello archivi <p flev> a quello attuale degli archivi standard.
{
_flds.destroy();
_exps.destroy();
if (flev == 0) flev = 199401;
else flev++;
TConfig conv(CONFIG_FCONV);
TString16 paragraph;
TString_array paralist;
conv.list_paragraphs(paralist);
for (unsigned int l = flev; l <= prefix().get_stdlevel(); l++)
{
paragraph.format("%06ld", l);
if (paralist.find(paragraph) < 0)
continue;
if (conv.set_paragraph(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.as_string(), rec);
}
}
// @doc EXTERNAL
// @mfunc Esegue la conversione del tracciato record del file
//
// @rdesc Ritorna il risulato della conversione, altrimenti il codice di errore generato
// (vedi <t TIsamerr>)
int TSystemisamfile::update(
const TTrec& newrec, // @parm Nuovo tracciato record con cui aggiornare il file
bool interactive) // @parm Indica se riportare i campi personalizzati
{
//if (newrec.len() == 0)
if (newrec.len() <= 8)
{
// if (interactive) error_box(FR("Il nuovo tracciato per il file %d e' vuoto"), num()); // Fastidioso per Ilaria
setstatus(_istrcerr);
return status();
}
int err = NOERR;
TTrec wrec(newrec);
TDir dir; dir.get(num(), _unlock, _nordir, _sysdirop);
const bool is_com = prefix().is_com();
const bool toconvert = is_com ? dir.is_com() : dir.is_firm();
TTrec oldrec(num(), is_com ? _comdir : _nordir);
if (oldrec.fields() < 0 || oldrec.fields() > MaxFields)
{
if (yesno_box(FR("Il file %d (%s)\n"
"ha %d campi ed una lunghezza record di %d"
"\nSi desidera azzerare il vecchio tracciato?"),
num(), (const char*)filename(), oldrec.fields(), oldrec.len()))
{
oldrec.zero();
}
else
{
setstatus(_istrcerr);
return status();
}
}
int lenr = wrec.len();
if (lenr != 0)
{
const long lev = prefix().filelevel();
const bool lcf = getlcf(lev);
if (toconvert)
{
err = exec_convapp(lev, true); // Pre-conversion
if (err != NOERR)
{
setstatus(err);
return err;
}
if (!lcf && wrec == oldrec)
{
err = exec_convapp(lev, false); // Post-conversion (SOLO se il record e' rimasto uguale)
setstatus(err);
return err;
}
}
else
{
if (dir.eox() > 0L)
dir.reset_eox();
}
const int oldfields = oldrec.fields(); //numero campi del vecchio file
const int wfields = wrec.fields(); //numero campi del nuovo file
int newfields = wfields; //numero campi del nuovo file compresi quelli personalizzati (_)
TToken_string def; //riga del file .trr nome|tipo|lungh|dec
for (int j = 0; j < oldfields; j++)
{
def = oldrec.fielddef(j);
const TString16 fname = def.get(0); //nome e basta del campo
if (!interactive && fname[0] == '_')
{
if (wrec.field(fname) == FIELDERR)
{
if (newfields < MaxFields)
{
wrec.update_fielddef(newfields++, def);
wrec.set_fields(newfields);
wrec.rehash();
}
else
{
if(!yesno_box("Il campo %s non verr<72> preservato: continuare?",
(const char*)fname))
return NOERR;
}
}
}
}
if (wfields < newfields)
{
wrec.set_fields(newfields);
wrec.rehash();
lenr = wrec.len();
}
TFilename fname;
if (toconvert)
fname = filename();
if (toconvert && (dir.eox() > 0L || fname.exist()))
{
TRecnotype ni = 0L;
TFilename tmpfname; tmpfname.temp("tf");
err=DB_build(tmpfname, &wrec.rec());
if (err != NOERR)
{
err=get_error(err);
return (err);
}
if (dir.eod() > 0 && oldrec.len() > 0)
{
// Apro il file destinazione in modo esclusivo e senza indici
//int tmpnum = num();
//TIsam_handle ishandle = prefix().open_isamfile(tmpnum, tmpfname, true, false);
// TCodeb_handle fhnd = ishandle > 0 ? prefix().get_handle(ishandle) : ishandle;
TCodeb_handle fhnd = DB_open(tmpfname, 1, 0);
if (fhnd < 0)
{
err = get_error(fhnd);
return err;
}
err = _open_ex(_excllock, false);
if (err != NOERR)
return err;
TString s; s << TR("Aggiornamento") << ' ' << fname;
const TRecnotype nitems = items();
TProgress_monitor p(nitems, s, is_power_station());
TExtrectype nrec(wrec);
const int nflds = curr().items();
TArray infld, outfld;
int j;
for (j = 0; j < nflds; j++)
{
const char* fld_name = curr().fieldname(j);
infld.add(new TRecfield(curr(), fld_name), j);
if (nrec.exist(fld_name))
outfld.add(new TRecfield(nrec, fld_name), j);
}
const bool memo_inside = rec_has_memo(nrec.rec_des());
for (int errore = first(); errore == NOERR; errore = next())
{
if (!p.add_status())
{
err = _iseof; // Simula errore in caso di interruzione
break;
}
ni++;
if (curr().isdeleted())
continue; // Shold never happen
nrec.zero();
for (j = outfld.last(); j >= 0; j = outfld.pred(j))
{
TRecfield* in_fld = (TRecfield*)infld.objptr(j);
TRecfield* out_fld = (TRecfield*)outfld.objptr(j);
if (in_fld != NULL && out_fld != NULL)
{
char* fld_val = (char*)(const char*)*in_fld;
if (out_fld->type() != _datefld && out_fld->type() != _memofld)
{
const int l1 = out_fld->len();
const int l2 = strlen(fld_val);
if (l1 < l2)
{
if (out_fld->type() != _alfafld)
*fld_val = '\0';
else
fld_val[l1] = '\0';
}
}
*out_fld = fld_val;
}
}
if (lcf)
makelc((TRectype &)nrec);
browse_null(nrec.string(),lenr);
memcpy(DB_getrecord(fhnd),nrec.string(),lenr);
err=DB_add(fhnd);
if ( err == NOERR && memo_inside)
{
// nrec.write_memo(ishandle, DB_recno(fhnd));
for (j = outfld.last(); j >= 0; j = outfld.pred(j))
{
const TRecfield* in_fld = (const TRecfield*)infld.objptr(j);
const TRecfield* out_fld = (const TRecfield*)outfld.objptr(j);
if (in_fld != NULL && out_fld != NULL && out_fld->type() == _memofld)
{
const TFixed_string val(*in_fld);
if (val.full())
DB_memowrite(fhnd, out_fld->name(), val);
}
}
DB_flush(fhnd);
}
if (err != NOERR)
err=get_error(err);
setstatus(err);
}
close();
//prefix().close_isamfile(ishandle);
DB_close(fhnd);
if (err != NOERR)
err = get_error(err);
if (!p.setstatus(nitems))
err = _iseof;
}
if (err == NOERR)
{
long c = DB_getconf();
fname.ext("dbf");
tmpfname.ext("dbf");
fcopy(tmpfname, fname);
::remove(tmpfname);
if (c & 1)
tmpfname.ext("fpt");
else
tmpfname.ext("dbt");
if (tmpfname.exist())
{
if (c & 1)
fname.ext("fpt");
else
fname.ext("dbt");
fcopy(tmpfname, fname);
::remove(tmpfname);
}
if (c & 1) // FOXPRO format
tmpfname.ext("cdx");
if (c & 4) // DBIV format
tmpfname.ext("mdx");
if (c & 8 || c & 2)
{
tmpfname.ext("cgp");
TFilename a;
FILE *fp=NULL; fopen_s(&fp, tmpfname,"rb");
while (fgets(a.get_buffer(),16,fp) != NULL)
{
a.rtrim(1); // Cut \n
if (c & 8) // DBIII format
a.ext("ndx");
else
a.ext("ntx"); // CLIPPER format
::remove(a);
}
fclose(fp);
}
::remove(tmpfname);
dir.set_eod(ni);
}
}
if (err==NOERR)
{
dir.set_len(lenr);
dir.put(num(), _nordir, _sysdirop);
wrec.put(num());
prefix().update_recdes(num());
if (toconvert)
packindex(true);
if (err == NOERR)
err = exec_convapp(lev, FALSE); // Post - conversion
}
}
setstatus(err);
return err;
}
// @doc EXTERNAL
// @mfunc Rimuove fisicamente i record cancellati
//
// @rdesc Ritorna NOERR se l'operazione di compattamento e' riuscita, altrimenti il codice di
// di errore generato (vedi <t TIsamerr>).
int TSystemisamfile::packfile(
bool vis, // @parm Indica se visualizzare lo stato dell'operazione
bool zap) // @parm Indica se distruggere tutti i records
// @xref <mf TSystemisamfile::packindex>
{
TFilename fname = filename(); fname.ext("");
TRecnotype new_eod = 0L;
if (!zap)
{
const int lf = num();
TDir d(lf); // Chi commenta muore!
d.get(lf,_nolock, d.is_com() ? _comdir : _nordir, _sysdirop);
new_eod = d.eod();
if (d.len() <= 1) // Dati rovinati?
{
d.set_len(curr().len());
d.put(lf, d.is_com() ? _comdir : _nordir, _sysdirop);
}
}
int err = DB_packfile(vis, fname, new_eod);
if (zap && err == NOERR)
err = packindex(vis, false);
if (err == NOERR && curr().has_memo())
err = DB_packmemo(vis,fname);
if (err != NOERR)
{
err = get_error(err);
if (err != NOERR)
error_box("Errore in compattamento dati.\nFile %d : %d", num(), err);
}
setstatus(err);
return err;
}
int TSystemisamfile::zap()
{
safely_close_closeable_isamfiles();
return packfile(true, true);
}
// @doc EXTERNAL
// @mfunc Rimuove fisicamente gli indici cancellati
//
// @rdesc Ritorna NOERR se l'operazione di compattamento e' riuscita, altrimenti il codice di
// di errore generato (vedi <t TIsamerr>).
int TSystemisamfile::packindex(
bool vis, // @parm Indica se visualizzare lo stato dell'operazione
bool ask) // @parm Indica se chiedere il recupero dei record duplicati
// @xref <mf TSystemisamfile::packfile>
{
const TTrec r(num());
TDir d(num());
const bool is_com = d.is_com();
d.get(num(),_nolock, is_com ? _comdir : _nordir, _sysdirop);
TFilename name = d.filename(); name.ext("");
TRecnotype peod;
int err=DB_packindex(vis,name,&r.rec(),&peod,ask);
if (err != NOERR)
err = get_error(err);
if (err != NOERR)
{
if (vis || ask)
error_box("Errore in compattamento indici.\nFile %d : %d", num(),err);
}
else
{
if (peod >= 0 && peod != d.eod())
{
d.set_eod(peod);
d.put(num(), is_com ? _comdir : _nordir);
}
}
setstatus(err);
return err;
}
void TSystemisamfile::update_file()
{
TFilename fname;
int logicnum = _logicnum;
int isam_handle = prefix().open_isamfile(logicnum, fname, FALSE, 1);
if (isam_handle > 0)
{
TCodeb_handle cb_handle = prefix().get_handle(isam_handle, 1);
const TRecnotype n = DB_reccount(cb_handle); //numero di elementi del file
TDir dir;
dir.get(_logicnum, _lock, _nordir, _sysdirop);
dir.set_eox(n);
dir.set_eod(n);
dir.put(_logicnum, _nordir, _sysdirop);
prefix().close_isamfile(isam_handle);
}
}
int TSystemisamfile::pack(bool vis, bool ask)
{
int err = packfile(vis);
if (err == NOERR)
err = packindex(vis, ask);
setstatus(err);
return err;
}
// @doc EXTERNAL
// @mfunc Importa un file ascii
//
// @rdesc Ritorna NOERR se l'operazione di lettura e' riuscita, altrimenti il codice di
// di errore generato (vedi <t TIsamerr>).
int TSystemisamfile::load(
const char* from, // @parm Nome del file da importare
char fs, // @parm Carattere separatore di campo (default <pipe>)
char fd, // @parm Carattere delimitatore di campi (default '\\0')
char rs, // @parm Carattere separatore di record (default '\\n')
bool vis, // @parm Indica se visualizzare lo stato dell'operazione (default TRUE)
bool extended, // @parm Indica se interpretare alcune stringhe come macro (default FALSE)
bool indexed) // @parm Indica se indicizzare subito o alla fine
// @comm Se <p extended> e' TRUE e trova alcune stringhe col formato %stringa% (es. %frm%)
// ne sostituisce i valori (es. ditta corrente).
// @xref <mf TSystemisamfile::dump>
{
int err=NOERR;
FILE* fl = NULL; fopen_s(&fl, from, "r");
if (fl == NULL)
{
cantread_box(from);
setstatus(2);
return 2;
}
TRecnotype r = 0, e = 0, nitems = 0;
TString8 firm, year, attprev("00000");
if (extended)
{
const TDate d(TODAY);
year.format("%04d", d.year());
firm.format("%05ld", prefix().get_codditta());
attprev = cache().get(LF_NDITTE, firm, NDT_CODATTPREV);
}
fseek(fl, 0L, SEEK_END);
nitems = ftell(fl);
fclose(fl);
err = _open_ex(_excllock, indexed);
if (err != NOERR)
{
TString msg; msg << _logicnum << " (" << name() << ')';
cantread_box(msg);
return err;
}
TScanner f(from);
const bool fixedlen = (fs == '\0');
TToken_string s(1024, fixedlen ? char(255) : fs);
int nflds = curr().items();
TString_array fld(nflds);
TPointer_array fldlen(nflds);
int reclen = 0;
TString sfd(3);
TString s1(256);
bool lcf = FALSE;
if (f.paragraph("Header"))
{
int equal;
TString key;
nflds = 0;
while ((equal = f.line().find('=')) > 0)
{
key = f.token().left(equal);
key.trim();
if (key == "File")
{
const int logic = atoi(f.token().mid(equal+1));
if (logic != num())
{
error_box("L'archivio %s e' stato generato dal file %d", from, logic);
return _isbadtrc;
}
} else
if (key == "Fields")
{
TToken_string riga(f.token().mid(equal+1));
TToken_string wfd(32, ',');
FOR_EACH_TOKEN(riga, fd)
{
wfd = fd; wfd.strip_spaces();
fld.add(wfd.get(0));
const int l = wfd.get_int();
fldlen.add_long(l, nflds++);
reclen += l;
}
}
}
}
if (nflds == 0 || fld.items() == 0)
{
nflds = curr().items();
for (int j = 0; j < nflds; j++)
{
fld.add(curr().fieldname(j), j);
const TString& wfld = fld.row(j);
const int l = (curr().type(wfld) == _datefld) ? 10 : curr().length(wfld);
fldlen.add_long(l, j);
}
}
if (!f.paragraph("Data"))
{
error_box("Formato file non valido: manca il paragrafo [Data]");
close();
err = 1;
setstatus(err);
return err;
}
if (fd) sfd << fd;
int last = NOERR;
const char* const fmt = FR("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d");
s1.format(fmt, _logicnum, from, r, e, last);
TProgind p(nitems, s1);
while(!f.eof())
{
if (fixedlen)
f.getline(s.get_buffer(reclen+2), reclen+2);
else
s = f.line();
if (s.empty())
break;
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) % 100 == 0)
{
s1.format(fmt, _logicnum, from, r, e, last);
p.set_text(s1);
}
if (!p.setstatus((long)f.tellg()))
break;
zero();
if (fixedlen)
{
if (s.len() < reclen)
{
error_box(FR("Record di lunghezza errata: %d invece di %d"), s.len(), reclen);
break;
}
int pos = 0;
for (int j = 0; j < nflds; j++)
{
const int l = fldlen.get_int(j);
s1 = s.mid(pos, l);
s1.rtrim();
put(fld.row(j), s1);
pos += l;
}
}
else
{
s.restart();
for (int j = 0; j < nflds; j++)
{
s1 = s.get();
if (fd)
{
s1.rtrim(1);
s1.ltrim(1);
}
if (curr().type((const TString&) fld[j]) == _memofld)
{
TString s2 = s1;
s1 = esc(s2);
}
put((const TString&) fld[j], s1);
}
}
int err = write();
if (err == NOERR)
r++;
else
{
e++;
last = status();
}
}
s1.format(fmt, _logicnum, from, r, e, last);
p.set_text(s1);
close();
setstatus(err);
// Devo reindicizzare alla fine
if (err == NOERR && !indexed)
packindex(vis, false);
//aggiorna lo sheet con i nuovi valori di EOX EOD caricati
if (err == NOERR)
update_file();
return err;
}
// @doc EXTERNAL
// @mfunc Importa un file ascii
//
// @rdesc Ritorna NOERR se l'operazione di lettura e' riuscita, altrimenti il codice di
// di errore generato (vedi <t TIsamerr>).
int TSystemisamfile::overwrite(
const char* from, // @parm Nome del file da importare
char fs, // @parm Carattere separatore di campo (default <pipe>)
char fd, // @parm Carattere delimitatore di campi (default '\\0')
char rs, // @parm Carattere separatore di record (default '\\n')
bool vis) // @parm Indica se visualizzare lo stato dell'operazione (default TRUE)
// @comm Se <p extended> e' TRUE e trova alcune stringhe col formato %stringa% (es. %frm%)
// ne sostituisce i valori (es. ditta corrente).
// @xref <mf TSystemisamfile::dump>
{
int err=NOERR;
FILE* fl = NULL; fopen_s(&fl, from, "r");
if (fl == NULL)
{
error_box("Impossibile aprire il file %s",from);
clearerr(fl);
setstatus(2);
return 2;
}
TRecnotype r = 0, e = 0, nitems = 0;
TString16 firm, year, attprev("00000");
fseek(fl, 0L, SEEK_END);
nitems = ftell(fl);
fclose(fl);
err = _open_ex(_excllock);
if (err != NOERR)
{
error_box("Impossibile aprire il file %d in modo esclusivo", _logicnum);
return err;
}
TScanner f(from);
bool fixedlen = (fs == '\0');
TToken_string s(1024, fixedlen ? char(255) : fs);
int nflds = curr().items();
TString_array fld(nflds);
TString_array keyfld(nflds);
TAssoc_array vals;
int len[MaxFields];
TString sfd(3);
TString s1(256);
bool lcf = FALSE;
if (f.paragraph("Header"))
{
int equal;
TString key;
nflds = 0;
while ((equal = f.line().find('=')) > 0)
{
key = f.token().left(equal);
key.trim();
if (key == "Version")
{
const unsigned int level = atoi(f.token().mid(equal+1));
if (level > prefix().filelevel())
{
const unsigned int stdlevel = prefix().get_stdlevel();
error_box(FR("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);
} else
if (key == "File")
{
const int logic = atoi(f.token().mid(equal+1));
if (logic != num())
error_box("L'archivio %s e' stato generato dal file %d",
from, logic);
} else
if (key == "Fields")
{
TToken_string riga(f.token().mid(equal+1));
TToken_string wfd(32, ',');
FOR_EACH_TOKEN(riga, fd)
{
wfd = fd; wfd.strip_spaces();
fld.add(wfd.get(0));
len[nflds++] = wfd.get_int();
}
const RecDes& rd = curr().rec_des();
const KeyDes& kd = rd.Ky[0];
for (int i = 0 ; i < kd.NkFields; i++)
{
const int nf = kd.FieldSeq[i] % MaxFields;
const RecFieldDes& rf = rd.Fd[nf];
keyfld.add(rf.Name);
}
}
}
}
if (nflds == 0 || fld.items() == 0)
{
nflds = curr().items();
for (int j = 0; j < nflds; j++)
{
fld.add(curr().fieldname(j), j);
const TString & wfld = fld.row(j);
int l = 0;
switch (curr().type(wfld))
{
case _datefld: l = 10; break;
default : l = curr().length(wfld); break;
}
len[j] = l;
}
}
if (!f.paragraph("Data"))
{
error_box("Formato file non valido: manca il paragrafo [Data]");
close();
err = 1;
setstatus(err);
return err;
}
if (fd) sfd << fd;
int last = NOERR;
s1.format("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d",
_logicnum, from, r, e, last);
TProgind p(nitems, s1, true, true, 78);
long pos = 16*nflds;
for (s = f.line(); s.not_empty() && !p.iscancelled(); s = f.line())
{
if ((r + e) % 50 == 0)
{
s1.format("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d",
_logicnum, from, r, e, last);
p.set_text(s1);
}
pos += s.len()+2;
p.setstatus(pos);
zero();
vals.destroy();
if (fixedlen)
{
int pos = 0;
for (int j = 0; j < nflds; j++)
{
const TString & fldname = fld.row(j);
s1 = s.mid(pos,len[j]);
s1.rtrim();
vals.add(fldname, s1);
pos += len[j];
}
}
else
{
s.restart();
for (int j = 0; j < nflds; j++)
{
const TString & fldname = fld.row(j);
s1 = s.get();
if (fd)
{
s1.rtrim(1);
s1.ltrim(1);
}
if (curr().type(fldname) == _memofld)
{
TString s2 = s1;
s1 = esc(s2);
}
vals.add(fldname, s1);
}
}
FOR_EACH_ARRAY_ROW(keyfld, r0, kfldname)
{
const TString * value = (const TString *) vals.objptr(*kfldname);
if (value != NULL)
put(*kfldname, *value);
}
const bool nuovo = read() != NOERR;
if (nuovo)
zero();
FOR_EACH_ASSOC_STRING(vals, obj, fldname, value)
put(fldname, value);
const int err = nuovo ? write() : rewrite();
if (err == NOERR)
r++;
else
{
e++;
last = status();
}
}
s1.format("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d",
_logicnum, from, r, e, last);
p.set_text(s1);
close();
setstatus(err);
//aggiorna lo sheet con i nuovi valori di EOX EOD caricati
if (err == NOERR)
update_file();
return err;
}
// @doc EXTERNAL
// @mfunc Esporta VERSO un file ascii.
//
// @rdesc Ritorna NOERR se l'operazione di esportazione e' riuscita, altrimenti il codice di
// di errore generato (vedi <t TIsamerr>).
int TSystemisamfile::dump(
const char* to, // @parm Nome del file verso quale esportare
int nkey, // @parm Numero della chiave di ordinamento con cui scaricare i dati (defualt 1)
char fs, // @parm Carattere seperatore di campo (defualt <pipe>)
char fd, // @parm Carattere delimitatore di campo (default '\\0')
char rs, // @parm Carattere separatore di record (default '\\n')
bool vis, // @parm Indica se visualizzare lo stato dell'operazione (defualt TRUE)
bool withdeleted,// @parm Indica se scaricare anche i record cancellati (dafault FALSE)
const char * filter, // @parm Indica l'espressione filtro
SELECTIONFUNCTION select_func, // @parm funzione filtro
TObject * filter_obj) // @parm oggetto di filtro
// @xref <mf TSystemisamfile::load>
{
FILE* f = NULL; fopen_s(&f, to, "w");
if (f == NULL)
{
setstatus(2);
return 2;
}
if (withdeleted) nkey = 0;
int err = ferror(f);
open(FALSE, nkey ? TRUE : FALSE);
TString s(512);
bool fixedlen = (fs == '\0');
int nflds = curr().items();
TString_array fld(nflds);
TBit_array rjust(nflds);
int len[MaxFields];
int j;
for (j = 0; j < nflds; j++)
{
fld.add(curr().fieldname(j), j);
const TString & wfld = fld.row(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);
if (fixedlen && t == _memofld)
{
error_box(TR("Non e' possibile scaricare a lunghezza fissa un file con campi memo"));
return _isbadtrc;
}
}
TRecnotype i = 0;
const TRecnotype nitems = items();
s.format(FR("Esportazione %s"), filename());
TProgind p(nitems, s, TRUE, TRUE, 70);
TString s1, sfld;
fprintf(f, "[Header]\nVersion=%ld\nFile=%d",
(long) prefix().filelevel(), num());
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);
if (filter && *filter)
{
TToken_string filter_str(filter);
TString16 fname;
bool skip = false;
while (!skip && !(fname=filter_str.get()).empty())
{
const char* fval = filter_str.get();
const TString& cmp = get(fname);
skip = cmp != fval;
}
skip |= (select_func != NULL) && (select_func(curr(), filter_obj) == false);
if (skip)
continue;
}
s.cut(0);
for (j = 0; j < nflds; j++)
{
const TString& fname = fld.row(j);
if (fixedlen)
{
s1 = get(fname);
if (rjust[j]) s1.right_just(len[j]);
else s1.left_just(len[j]);
}
else
{
s1.cut(0);
if (j && fs) s1 << fs;
if (fd) s1 << fd;
sfld = get(fname);
switch (curr().type(fname))
{
case _intfld:
case _longfld:
case _intzerofld:
case _longzerofld:
case _realfld:
if (real::is_null(sfld))
sfld.cut(0);
break;
case _memofld:
if (sfld.full())
{
int p = 0;
while ((p = sfld.find('\n', 0)) >= 0)
{
sfld.overwrite("\\", p);
sfld.insert("n", p+1);
}
}
else
sfld.cut(0);
break;
default: // strfld, charfld, boolfld
if (sfld.blank())
sfld.cut(0);
break;
}
s1 << sfld;
if (fd) s1 << fd;
}
s << s1;
}
if (fs) // Elimina tutti i campi vuoti a fine record
{
int i;
for (i = s.len()-1; i >= 0 && s[i] == fs; i--);
s.cut(i+1);
}
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);
if (filter && *filter)
{
TToken_string filter_str(filter);
TString16 fname;
bool skip = FALSE;
while (!skip && !(fname=filter_str.get()).empty())
{
const char* fval = filter_str.get();
const TString& cmp = get(fname);
skip = cmp != fval;
}
if (skip)
continue;
}
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;
sfld = get((const TString&)fld[j]);
if (curr().type((const TString&) fld[j]) == _memofld)
{
int p = 0;
while ((p = sfld.find('\n', 0)) >= 0)
{
sfld.overwrite("\\", p);
sfld.insert("n", p+1);
}
}
s1 << sfld;
if (fd) s1 << fd;
}
s << s1;
}
fprintf(f, "%s%c", (const char*) s, rs);
}
}
}
p.setstatus(nitems);
close();
fclose(f);
setstatus(err);
return err;
}
int TSystemisamfile::dump(
const char* to, // @parm Nome del file verso quale esportare
TToken_string & field_list, // @parm Lista dei campi
int nkey, // @parm Numero della chiave di ordinamento con cui scaricare i dati (defualt 1)
char fs, // @parm Carattere seperatore di campo (defualt <pipe>)
char fd, // @parm Carattere delimitatore di campo (default '\\0')
char rs, // @parm Carattere separatore di record (default '\\n')
bool vis, // @parm Indica se visualizzare lo stato dell'operazione (defualt TRUE)
bool withdeleted,// @parm Indica se scaricare anche i record cancellati (dafault FALSE)
const char * filter, // @parm Indica l'espressione filtro
SELECTIONFUNCTION select_func, // @parm funzione filtro
TObject * filter_obj) // @parm oggetto di filtro
// @xref <mf TSystemisamfile::load>
{
FILE* f = NULL; fopen_s(&f, to, "w");
if (f == NULL)
{
setstatus(2);
return 2;
}
if (withdeleted) nkey = 0;
int err = ferror(f);
open(FALSE, nkey ? TRUE : FALSE);
TString s(512);
bool fixedlen = (fs == '\0');
int nflds = curr().items();
TString_array fld(nflds);
TBit_array rjust(nflds);
int len[MaxFields];
int j = 0;
FOR_EACH_TOKEN(field_list, str)
{
const TString16 fldname(str);
fld.add(fldname);
const TFieldtypes t = curr().type(fldname);
rjust.set(j, t == _intfld || t == _longfld || t == _realfld ||
t == _wordfld || t == _intzerofld || t == _longzerofld);
len[j++] = (t == _datefld) ? 10 : curr().length(fldname);
if (fixedlen && t == _memofld)
return error_box(TR("Non <20> possibile scaricare a lunghezza fissa un file con campi memo"));
}
TRecnotype i = 0;
const TRecnotype nitems = items();
s.format(FR("Esportazione %s"), filename());
TProgind p(nitems, s, TRUE, TRUE, 70);
TString s1, sfld;
fprintf(f, "[Header]\nVersion=%ld\nFile=%d",
(long) prefix().filelevel(), num());
FOR_EACH_ARRAY_ROW(fld, k, el)
{
if ((k % 10) == 0) fprintf(f, "\nFields=");
else fprintf(f, "|");
const TString & fldname =fld.row(k);
fprintf(f, "%s,%d", (const char *) fldname, len[k]);
}
fprintf(f, "\n\n[Data]\n");
if (nkey)
{
setkey(nkey);
for ( first(); status() == NOERR && !p.iscancelled(); next(), i++)
{
bool skip = false;
p.setstatus(i + 1);
if (filter && *filter)
{
TToken_string filter_str(filter);
TString16 fname;
while (!skip && !(fname=filter_str.get()).empty())
{
const char* fval = filter_str.get();
const TString& cmp = get(fname);
skip = cmp != fval;
}
}
skip |= (select_func != NULL) && (select_func(curr(), filter_obj) == false);
if (skip)
continue;
s = "";
FOR_EACH_ARRAY_ROW(fld, j, el)
{
const TString & fldname =fld.row(j);
if (fixedlen)
{
s1 = get(fldname);
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;
sfld = get(fldname);
if (curr().type(fldname) == _memofld)
{
int p = 0;
while ((p = sfld.find('\n', 0)) >= 0)
{
sfld.overwrite("\\", p);
sfld.insert("n", p+1);
}
}
s1 << sfld;
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);
if (filter && *filter)
{
TToken_string filter_str(filter);
TString16 fname;
bool skip = FALSE;
while (!skip && !(fname=filter_str.get()).empty())
{
const char* fval = filter_str.get();
const TString& cmp = get(fname);
skip = cmp != fval;
}
if (skip)
continue;
}
s="";
if (withdeleted || curr().valid())
{
FOR_EACH_ARRAY_ROW(fld, j, el)
{
const TString & fldname = fld.row(j);
if (fixedlen)
{
s1 = get(fldname);
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;
sfld = get(fldname);
if (curr().type(fldname) == _memofld)
{
int p = 0;
while ((p = sfld.find('\n', 0)) >= 0)
{
sfld.overwrite("\\", p);
sfld.insert("n", p+1);
}
}
s1 << sfld;
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()
{
}
////////////////////////////////////////////////////////////
// Memo data
////////////////////////////////////////////////////////////
void TMemo_data::init(TRecnotype recno, TIsam_handle file)
{
CHECK(file > 0 || recno < 0, "Valid memo recno with NULL memo file"); // verificare
_recno = recno;
_isamfile = file;
}
void TMemo_data::destroy()
{
TString_array::destroy();
_dirty.reset();
_recno = RECORD_NON_FISICO;
_isamfile = 0;
}
void TMemo_data::copy(const TMemo_data& m)
{
TString_array::operator=(m);
_dirty = m._dirty;
_recno = m._recno;
_isamfile = m._isamfile;
}
////////////////////////////////////////////////////////////
// TRectype
////////////////////////////////////////////////////////////
void TRectype::init(int logicnum)
{
_logicnum = logicnum;
CHECK(_logicnum > 0,"Impossibile costruire un record di un file esterno");
_length = prefix().get_reclen(logicnum);
_rec = new char [_length];
*_tab = '\0';
if (_length > 0)
zero();
else
setempty(TRUE);
if (_length > 0 && lf_has_memo(logicnum))
init_memo(RECORD_NON_FISICO);
}
TRectype::TRectype(int logicnum)
: _memo_data(NULL)
{
init(logicnum);
}
TRectype::TRectype(const TBaseisamfile* i)
: _memo_data(NULL)
{
init(i->num());
}
TRectype::TRectype(const TRectype& r)
: _memo_data(NULL)
{
init(r._logicnum);
if (r._memo_data)
{
init_memo(r._memo_data->recno(), r._memo_data->file());
*_memo_data = *r._memo_data;
}
memcpy(_rec, r._rec, _length);
memcpy(_tab, r._tab, sizeof(_tab));
setempty(r.empty());
}
TRectype::~TRectype()
{
if (_rec != NULL)
delete _rec;
if (_memo_data != NULL )
delete _memo_data;
}
void TRectype::unknown_field(const char* name) const
{
static int last_file = 0;
if (_logicnum != last_file)
{
NFCHECK("Il campo '%s' non appartiene al file %d", name, _logicnum);
last_file = _logicnum;
}
}
void TRectype::write_memo(TIsam_handle file, const TRecnotype recno)
{
const RecDes& r = rec_des( );
TIsam_handle orig = _memo_data->file();
if (orig && (file != orig || recno != _memo_data->recno()))
{
TCodeb_handle cb_orig = prefix().get_handle(orig);
DB_go(cb_orig, _memo_data->recno());
for(int i = r.NFields - 1; i >= 0; i--)
{
if (r.Fd[i].TypeF == _memofld)
{
if (_memo_data->objptr(i) == NULL)
{
const char* memo = DB_memoptr(cb_orig, r.Fd[i].Name);
if (memo && *memo)
_memo_data->add(memo, i);
}
_memo_data->set_dirty(i);
}
}
}
CHECKD(recno >= 0, "Maiale! Non fare le GO con _recno < 0: ", recno);
const TCodeb_handle cb_handle = prefix().get_handle(file);
DB_go( cb_handle, recno);
FOR_EACH_ARRAY_ROW_BACK((*_memo_data), i, memo)
{
if (_memo_data->is_dirty(i))
DB_memowrite(cb_handle, r.Fd[i].Name, *memo);
}
DB_flush(cb_handle);
*this = (const char*)DB_getrecord(cb_handle);
init_memo(recno, file);
}
void TRectype::init_memo(TRecnotype recno, TIsam_handle file)
{
if (_memo_data == NULL)
_memo_data = new TMemo_data;
else
_memo_data->destroy();
_memo_data->init(recno, file);
}
void TRectype::settab(const char *tab)
{
strcpy(_tab, tab);
zero();
}
TObject* TRectype::dup() const
{
TRectype* o = new TRectype(*this);
return o;
}
const char* TRectype::build_key(int num) const
{
TString& tmp = get_tmp_string(256);
__build_key(rec_des(), num, string(), tmp.get_buffer(), TRUE);
return tmp;
}
const char* TRectype::last_key_field(int key) const
{
const KeyDes& kd = rec_des().Ky[key];
const int last = kd.NkFields-1;
const bool upp = kd.FieldSeq[last] > MaxFields;
const int nf = upp ? kd.FieldSeq[last] - MaxFields : kd.FieldSeq[last];
const RecFieldDes& rf = rec_des().Fd[nf];
return rf.Name;
}
// @doc EXTERNAL
// @mfunc Confronta le chiavi di due record
//
// @rdesc Ritorna il risultato di una <f strcmp>:
//
// @flag 0 | Se le due chiavi sono uguali
// @flag <lt><gt>0 | Se le due chiavi sono diverse
int TRectype::compare_key(
const TRectype& rec, // @parm Record di cui confrontare le chiavi
int key, // @parm Numero della chiave del presente record (defautl 1)
int skip_last) const // @parm Numero di campi da ignorare nella comparazione a partire dall'ultimo
// @xref <mf TRectype::build_key>
{
/* Vecchio modo con molte operazioni su stringhe e molte chiamate a rec_des()!
TString256 key1 = build_key(key);
TString256 key2 = rec.build_key(key);
if (skip_last > 0)
{
const KeyDes& kd = rec_des()->Ky[key-1];
const int last = kd.NkFields-1;
CHECKD(last >= skip_last, "Can't ignore so many fields in key: ", skip_last);
for (int l = 0; l < skip_last; l++)
{
int nf = kd.FieldSeq[last-l];
if (nf > MaxFields) nf -= MaxFields;
const RecFieldDes& rf = rec_des()->Fd[nf];
key1.rtrim(rf.Len);
key2.rtrim(rf.Len);
}
}
const int res = strcmp(key1, key2);
*/
const char* key1 = build_key(key);
const char* key2 = rec.build_key(key);
int res = 0;
if (skip_last > 0)
{
int maxlen = 0;
const RecDes& rd = rec_des();
const KeyDes& kd = rd.Ky[key-1];
const int last = kd.NkFields-skip_last;
for (int l = 0; l < last; l++)
{
const int nf = kd.FieldSeq[l] % MaxFields;
const RecFieldDes& rf = rd.Fd[nf];
maxlen += rf.Len;
}
res = strncmp(key1, key2, maxlen);
}
else
res = strcmp(key1, key2);
return res;
}
HIDDEN bool fld_empty(const char* s, int len, bool /* number */)
{
if (s && *s && len > 0)
{
for (; len; s++, len--) if (*s != ' ')
return false;
}
return true;
}
HIDDEN int fld_cmp(const char* a, const char* b, int len, bool number)
{
int res = memcmp(a, b, len);
if (res == 0)
return res;
int i = 0;
if (number) // Aggiunta del 11-02-2014: ignoro spazi e zeri iniziali dei numeri
for (; i < len && (*a==' ' || *a=='0') && (*b==' ' || *b=='0'); b++, a++, i++);
for (; i < len && *a == *b; b++, a++, i++);
if (i == len)
return 0;
res = *a - *b;
if (number)
{
b -= i;
i = 0;
}
return fld_empty(b, len - i, number) ? 0 : res;
}
///////////////////////////////////////////////////////////
// TRectype (record di un file)
///////////////////////////////////////////////////////////
const RecDes& TRectype::rec_des() const
{
return prefix().get_recdes(_logicnum);
}
int TRectype::items() const
{
return rec_des().NFields;
}
const char* TRectype::start(int nf) const
{
return string() + rec_des().Fd[nf].RecOff;
}
// Confronto tra record: Attenzione i campi vuoti di s non vengono confrontati!
int TRectype::compare(const TSortable& s) const
{
const TRectype& br = (const TRectype&) s;
int res = 0;
if (br.empty()) return UNDEFINED;
const RecDes& rd = rec_des();
for (int i = 0; i < rd.NFields; i++)
{
const char* b = br.start(i);
const char* a = start(i);
const byte typ = rd.Fd[i].TypeF;
const int sz = rd.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;
}
// Confronto stretto
bool TRectype::is_equal(const TRectype& r) const
{
char* r1 = new char[_length];
char* r2 = new char[_length];
memcpy(r1, _rec, _length);
memcpy(r2, r._rec, _length);
browse_null(r1, _length);
browse_null(r2, _length);
if (has_memo())
{
const RecDes& rd = rec_des();
for(int i = rd.NFields - 1; i >= 0; i--)
{
if (rd.Fd[i].TypeF == _memofld)
{
memset(r1+rd.Fd[i].RecOff, ' ', rd.Fd[i].Len);
memset(r2+rd.Fd[i].RecOff, ' ', rd.Fd[i].Len);
}
}
}
bool yes = memcmp(r1, r2, _length) == 0;
delete r1;
delete r2;
if (yes && has_memo())
{
const RecDes& rd = rec_des();
for(int i = rd.NFields - 1; yes && i >= 0; i--)
{
if (rd.Fd[i].TypeF == _memofld)
yes = get(rd.Fd[i].Name) == r.get(rd.Fd[i].Name);
}
}
return yes;
}
TFieldtypes TRectype::type(const char* fieldname) const
{
const RecDes& recd = rec_des();
const int p = findfld(&recd, fieldname);
return p != FIELDERR ? (TFieldtypes)recd.Fd[p].TypeF : _nullfld;
}
int TRectype::length(const char* fieldname) const
{
const RecDes& recd = rec_des();
const int p = findfld(&recd, fieldname);
return p != FIELDERR ? recd.Fd[p].Len : 0;
}
int TRectype::ndec(const char* fieldname) const
{
const RecDes& recd = rec_des();
const int p = findfld(&recd, fieldname);
return p != FIELDERR ? recd.Fd[p].Dec : 0;
}
bool TRectype::exist(const char* fieldname) const
{
return findfld(&rec_des(), fieldname) != FIELDERR;
}
const char* TRectype::fieldname(int i) const
{
const RecDes& recd = rec_des();
return i >= 0 && i < recd.NFields ? recd.Fd[i].Name : NULL;
}
const TString& TRectype::get_str(const char* fieldname) const
{
const RecDes& recd = rec_des();
const int nf = findfld(&recd, fieldname);
if (nf != FIELDERR)
{
const RecFieldDes& fd = recd.Fd[nf];
TString& tmp = get_tmp_string(fd.Len + (fd.TypeF == _datefld ? 2 : 0));
__getfieldbuff(fd.Len, fd.TypeF, _rec + fd.RecOff, tmp);
return tmp;
}
else
unknown_field(fieldname);
return EMPTY_STRING;
}
const TString& TRectype::get(const char* fieldname) const
{
if (_memo_data && type(fieldname) == _memofld)
{
const RecDes& recd = rec_des();
const int index = findfld(&recd, fieldname);
if ( _memo_data->objptr( index ))
return _memo_data->row( index );
if (_memo_data->recno() >= 0L)
{
const TIsam_handle orig = _memo_data->file();
if (orig)
{
CHECKD(orig >= LF_EXTERNAL || orig == num(), "Invalid isam handle ", orig);
TCodeb_handle cb_handle = prefix().get_handle(orig, -1);
CHECKD(cb_handle >= 0, "Can't read memo from file ", orig);
if (DB_recno(cb_handle) != _memo_data->recno())
DB_go(cb_handle, _memo_data->recno());
_memo_data->add(DB_memoptr(cb_handle, fieldname), index);
}
else
NFCHECK("Valid memo recno with null memo file");
}
else
_memo_data->add("", index);
return _memo_data->row(index);
}
return get_str(fieldname);
}
int TRectype::get_int(const char* fieldname) const
{
return atoi(get_str(fieldname));
}
long TRectype::get_long(const char* fieldname) const
{
return atol(get_str(fieldname));
}
word TRectype::get_word(const char* fieldname) const
{
return (word)atoi(get_str(fieldname));
}
real TRectype::get_real(const char* fieldname) const
{
const real r(get_str(fieldname));
return r;
}
char TRectype::get_char(const char* fieldname) const
{
return get_str(fieldname)[0];
}
bool TRectype::get_bool(const char* fieldname) const
{
const char c = get_char(fieldname);
return (c == 'X') || (c == '1');
}
TDate TRectype::get_date(const char* fieldname) const
{
const TDate d(get_str(fieldname));
return d;
}
void TRectype::put(const char* fieldname, int val)
{
char tmp[16];
_itoa_s(val, tmp, 10);
put_str(fieldname, tmp);
}
void TRectype::put(const char* fieldname, long val)
{
char tmp[16];
_ltoa_s(val, tmp, 10);
put_str(fieldname, tmp);
}
void TRectype::put(const char* fieldname, word val)
{
put(fieldname, (int)val);
}
void TRectype::put(const char* fieldname, const real& val)
{
put_str( fieldname, val.string());
}
void TRectype::put(const char* fieldname, const TCurrency& val)
{
put_str( fieldname, val.get_num().string());
}
void TRectype::put(const char* fieldname, const TDate& val)
{
put( fieldname, val.date2ansi());
}
void TRectype::put(const char* fieldname, char val)
{
const char w[2] = { val, '\0' };
put_str( fieldname, w);
}
void TRectype::put(const char* fieldname, bool val)
{
put(fieldname, val ? 'X' : ' ');
}
void TRectype::put_str(const char* fieldname, const char* val)
{
const RecDes& recd = rec_des();
const int nf = findfld(&recd, fieldname);
if (nf == FIELDERR)
{
unknown_field(fieldname);
return;
}
const RecFieldDes& fd = recd.Fd[nf];
const TFieldtypes ft = TFieldtypes(fd.TypeF);
if (val == NULL)
val = "";
if (ft == _boolfld)
val = (*val && strchr("1STXY", toupper(*val)) != NULL) ? "T" : "F";
if (*val == '\0')
{
TRecfield f(*this, fieldname);
if (*f.pos() == '\0') return;
}
if (ft == _memofld)
{
_memo_data->add(val, nf);
_memo_data->set_dirty(nf);
}
else
{
__putfieldbuff(fd.Len, fd.Dec, ft, val, _rec + fd.RecOff);
}
setempty(FALSE);
}
void TRectype::add(const char* fieldname, const real& val)
{
if (!val.is_zero())
{
real k = get_real(fieldname);
k += val;
put(fieldname, k);
}
}
void TRectype::zero(const char* fieldname)
{
if (*_tab && strcmp(fieldname , "COD") == 0)
put("COD", _tab);
else
{
const RecDes& recd = rec_des();
const int nf = findfld(&recd, fieldname);
if (nf == FIELDERR)
unknown_field(fieldname);
else
{
const int recoff = recd.Fd[nf].RecOff;
char * p = _rec + recoff;
const byte len = recd.Fd[nf].Len;
const byte dec = recd.Fd[nf].Dec;
const TFieldtypes type = (TFieldtypes) recd.Fd[nf].TypeF;
switch (type)
{
case _datefld:
__putfieldbuff(len, dec, _datefld, "", p);
break;
case _memofld:
__putfieldbuff(len, dec, _memofld, "", p);
_memo_data->add("", nf);
_memo_data->set_dirty(nf);
break;
default:
memset(p, ' ', len);
if ((type == _intfld) || (type == _longfld) || (type == _wordfld))
*(p + len - 1) = '0';
else
if (type == _realfld)
{
if (dec)
{
memset(p + len - dec - 2, '0', dec + 2);
*(p + len - dec - 1) = '.';
}
else
*(p + len - 1) = '0';
}
break;
}
}
}
}
void TRectype::zero(char c)
{
memset(_rec, c, len());
recall();
if (*_tab)
put("COD", _tab);
if(has_memo())
init_memo( RECORD_NON_FISICO );
setempty(true);
}
// Certified 99%
TRectype& TRectype::operator =(const TRectype& rec)
{
CHECK(num() == rec.num(), "Can't assign records of different file");
memcpy(_rec, rec._rec, _length); // Copy contents
if (rec._memo_data)
{
init_memo(rec._memo_data->recno(), rec._memo_data->file());
*_memo_data = *rec._memo_data;
}
memcpy(_tab, rec._tab, sizeof(_tab));
setempty(rec.empty()); // Copy emptiness status
return *this;
}
// Certified 100%
TRectype& TRectype::operator =(const TBaseisamfile& f)
{
return *this = f.curr();
}
// Certified 50%
int TRectype::read(TBaseisamfile& f, word op, word lockop)
{
int err = f._read(*this,op,lockop);
return err;
}
int TRectype::readat(TBaseisamfile& f, TRecnotype nrec, word lockop)
{
return f._readat(*this,nrec,lockop);
}
// Certified 100%
int TRectype::next(TBaseisamfile& f,word lockop)
{
return read(f, _isnext, lockop);
}
// Certified 100%
int TRectype::prev(TBaseisamfile& f,word lockop)
{
return read(f, _isprev, lockop);
}
int TRectype::first(TBaseisamfile& f,word lockop)
{
return read(f, _isfirst, lockop);
}
int TRectype::last(TBaseisamfile& f,word lockop)
{
return read(f, _islast, lockop);
}
// Certified ??%
int TRectype::write(TBaseisamfile& f) const
{ return f._write(*this); }
// Certified ??%
int TRectype::rewrite(TBaseisamfile& f) const
{
return f._rewrite(*this);
}
int TRectype::write_rewrite(TBaseisamfile& f) const
{
int err = write(f);
if (err == NOERR)
f._read((TRectype&)*this, _iscurr, _unlock); // Sblocca record 19-09-2012 (andrebbe nella _write)
else
err = rewrite(f);
return err;
}
int TRectype::rewrite_write(TBaseisamfile& f) const
{
int err = rewrite(f);
if (err != NOERR)
{
err = write(f);
if (err == NOERR)
f._read((TRectype&)*this, _iscurr, _unlock); // Sblocca record 19-09-2012 (andrebbe nella _write)
}
return err;
}
// Certified ??%
int TRectype::remove(TBaseisamfile& f) const
{
return f._remove(*this);
}
void TRectype::renum_key(const char* field, const char* val)
{
if (strchr(field, '[') != NULL) // Accept CODTAB[6,10]
{
const TFieldref fref(field, 0);
TString80 str = val;
if (real::is_natural(val))
str.right_just(fref.len(*this), '0');
fref.write(str, *this);
}
else
put(field, val);
}
// Certified 99%
TRectype& TRectype::operator =(const char* rec)
{
if (rec && *rec)
{
memcpy(_rec, rec, _length);
setempty(false);
}
else
zero();
return *this;
}
const char* TRectype::key(int numkey) const
{
TString& tmp = get_tmp_string(256);
__build_key(rec_des(), numkey, _rec, tmp.get_buffer(), false);
return tmp;
}
void TRectype::fill_transaction(TConfig& cfg, int row) const
{
TString16 p; p << num();
if (row > 0) p << ',' << row;
cfg.set_paragraph(p);
for (int f = items()-1; f >= 0; f--)
{
const char* name = fieldname(f);
const char* value = get(name);
cfg.set(name, value);
}
}
bool TRectype::send_mail(const char* action) const
{
TWait_cursor hourglass;
bool ok = ::can_dispatch_transaction(*this);
if (ok)
{
TFilename ininame; ininame.temp("msg", "ini");
if (ok) // Dummy test per {}
{
TConfig ini(ininame, "Transaction");
ini.set("Action", action);
ini.set("Mode", "A");
fill_transaction(ini);
}
ok = ::dispatch_transaction(*this, ininame);
ininame.fremove();
}
return ok;
}
bool TRectype::get_relapp(TString& app) const
{
if (*_tab)
{
TString4 cod(_tab);
switch (num())
{
case LF_TABCOM: cod.insert("%"); break;
case LF_TABGEN: cod.insert("^"); break;
case LF_TABMOD:
{
TModule_table mod(_tab);
return mod.get_relapp(app);
}
break;
default : break;
}
return ::get_tabapp(cod, app);
}
return ::get_relapp(num(), app);
}
bool TRectype::edit(int logicnum, const char* alternate_key_fields, const char* hint) const
{
bool ok = false;
if (logicnum <= 0)
logicnum = num();
TRectype r(logicnum);
if (*_tab)
r.settab(_tab);
TString app = hint;
if (app.blank())
r.get_relapp(app);
if (app.full())
{
const RecDes& recd = r.rec_des(); // Descrizione del record della testata
const KeyDes& kd = recd.Ky[0]; // Elenco dei campi della chiave 1
TToken_string key_labels;
for (int i = 0; i < kd.NkFields; i++)
{
const int nf = kd.FieldSeq[i] % MaxFields;
const RecFieldDes& rf = recd.Fd[nf];
key_labels.add(rf.Name);
}
TToken_string key_fields(alternate_key_fields);
if (key_fields.empty_items())
key_fields = key_labels;
TFilename ininame; ininame.temp("lnk", "ini");
{
TConfig ini(ininame, "Transaction");
ini.set("Action", "LINK");
TString8 p; p << logicnum;
ini.set_paragraph(p);
FOR_EACH_TOKEN(key_labels, tok)
{
const TString16 name(tok);
const TString& value = get(key_fields.get());
ini.set(name, value);
}
}
app << " -i" << ininame;
TExternal_app a(app);
ok = a.run() == 0;
if (ok)
{
xvt_sys_sleep(500);
const TString& result = ini_get_string(ininame, "Transaction", "Result");
ok = result == "OK";
}
xvt_fsys_remove_file(ininame);
if (ok)
rec_cache(logicnum).notify_change();
}
return ok;
}
bool TRectype::set_edit_info(const char* ut, const char* dt, const char* or)
{
bool ok = false;
if (num() >= LF_TABCOM)
{
// Se esiste un campo alfanumerioco UT*
if (ut && *ut && type(ut) == _alfafld)
{
const int len = length(ut);
TString80 usr = user();
TString80 s;
xvt_sys_get_user_name(s.get_buffer(), s.size());
const int at = s.find('@'); if (at > 0 ) s.cut(at); // Windows 8.1 / 10.0 user profile
if (usr.len()+s.len()+1 <= len)
usr << ':' << s;
xvt_sys_get_host_name(s.get_buffer(), s.size());
if (usr.len()+s.len()+1 <= len)
usr << '@' << s;
put(ut, usr); // Scrivi utente corrente
ok = true;
// Se esiste un campo data DT*
if (dt && *dt && type(dt) == _datefld)
{
const TDate oggi(TODAY);
put(dt, oggi); // Scrivi data odierna
// Se esisnte un campo long OR*
if (or && *or && (type(or) == _longfld || type(or) == _longzerofld))
put(or, daytime()); // Scrivi ora attuale HHMMSS
}
}
}
return ok;
}
bool TRectype::set_modify_info()
{
bool done = false;
if (num() >= LF_LVPASPLAN && exist("UTULAGG")) // Lavanderie
done = set_edit_info("UTULAGG", "DTULAGG", "ORULAGG"); else
if (exist("UTENTE"))
done = set_edit_info("UTENTE", "DATAAGG", NULL);
return done;
}
bool TRectype::set_creation_info()
{
bool done = set_modify_info();
if (num() >= LF_LVPASPLAN && exist("UTCREAZ")) // Lavanderie
done |= set_edit_info("UTCREAZ", "DTCREAZ", "ORCREAZ");
return done;
}
///////////////////////////////////////////////////////////
// TRecfield (campo/sottocampo di un record)
///////////////////////////////////////////////////////////
TRecfield::TRecfield(TRectype& rec, const char* name, int from, int to)
{
_rec = &rec;
const TFixed_string fname(name);
const int colon = fname.find(':');
if (colon > 0)
{
_name.strncpy(name, colon);
_sub_field = name+colon+1;
_sub_field << '='; // ???????????????
}
else
_name = name;
const RecDes& rd = _rec->rec_des();
const int nf = findfld(&rd, _name);
if (nf == FIELDERR)
{
_sub_field = _name;
_p = _rec->string();
_len = 0;
_dec = 0;
_type = _alfafld;
}
else
{
if (from < 0)
{
NFCHECK("Invalid Start %d", from);
from = 0;
}
_p = _rec->string() + rd.Fd[nf].RecOff;
_dec = rd.Fd[nf].Dec;
_type = (TFieldtypes)rd.Fd[nf].TypeF;
if (_sub_field.empty())
{
_p += from;
if (to >= 0)
{
CHECKS(_type == _memofld || (from <= to && to <= rd.Fd[nf].Len), "Invalid Range on field ", (const char *)_name);
_len = to - from + 1;
}
else
_len = rd.Fd[nf].Len - from;
}
else
{
CHECK(_type == _memofld, "You can use Subfields only with Memo");
_from = from;
_to = to;
if (_type == _memofld)
_len = 0;
else
_len = rd.Fd[nf].Len;
}
}
CHECKS(colon < 0 || _type == _memofld, "SubField on non memo field: ", name);
}
void TRecfield::put_subfield(const char* s)
{
if (_name == _sub_field)
return;
const TString& str = _rec->get(_name);
int p = str.find(_sub_field);
if (p == 0 || (p > 0 && str[p - 1] < ' '))
{
p += _sub_field.len();
int e = str.find('\n', p);
if (_to > 0 && p + _to < e)
e = p + _to;
p += _from;
if (p < e)
{
TString val(s);
if (_to > 0)
{
val.left(e - p + 1);
val.rpad(e - p + 1);
}
TString out = str.left(p);
out << val << str.mid(e); // ? e + 1
_rec->put(_name, out);
}
}
}
int TRecfield::operator =(int i)
{
TString16 buff; buff << i;
if (_sub_field.empty())
__putfieldbuff( _len, _dec, _type, buff, _p);
else
put_subfield(buff);
_rec->setempty(FALSE);
return i;
}
long TRecfield::operator =(long l)
{
TString16 buff; buff << l;
if (_sub_field.empty())
__putfieldbuff( _len, _dec, _type, buff, _p);
else
put_subfield(buff);
_rec->setempty(false);
return l;
}
const real& TRecfield::operator =(const real& r)
{
const char* buff = r.string();
if (_sub_field.empty())
__putfieldbuff( _len, _dec, _type, buff, _p);
else
put_subfield(buff);
_rec->setempty(FALSE);
return r;
}
const TDate& TRecfield::operator =(const TDate& d)
{
const TString16 buff = d.stringa();
if (_sub_field.empty())
__putfieldbuff( _len, _dec, _type, buff, _p);
else
put_subfield(buff);
_rec->setempty(FALSE);
return d;
}
const char* TRecfield::operator =(const char* s)
{
if (_sub_field.empty())
{
if (_type == _memofld)
_rec->put(_name, s);
else
__putfieldbuff( _len, _dec, _type, s, _p);
}
else
put_subfield(s);
_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;
}
void TRecfield::get_subfield(TString& s) const
{
const TString& str = _rec->get(_name);
if (_name == _sub_field)
s = str;
else
{
int p = str.find(_sub_field);
if (p == 0 || (p > 0 && str[p - 1] < ' '))
{
p += _sub_field.len();
int e = str.find('\n', p);
if (e < 0) e = str.len(); // L'ultima variabile non termina con \n
if (_to > 0 && p + _to < e)
e = p + _to;
p += _from;
if (p < e)
s = str.sub(p, e);
else
s.cut(0);
}
else
s.cut(0);
}
}
TRecfield::operator int() const
{
TString16 tmp;
if (_sub_field.empty())
{
if (_type == _intfld || _type == _intzerofld || _type == _longfld || _type == _longzerofld)
tmp.strncpy(_p, _len);
else
__getfieldbuff( _len, _type, _p, tmp);
}
else
get_subfield(tmp);
return atoi(tmp);
}
TRecfield::operator long() const
{
TString16 tmp;
if (_sub_field.empty())
{
if (_type == _longfld || _type == _longzerofld || _type == _intfld || _type == _intzerofld)
tmp.strncpy(_p, _len);
else
__getfieldbuff( _len, _type, _p, tmp);
}
else
get_subfield(tmp);
return atol(tmp);
}
TRecfield::operator const real() const
{
TString80 tmp;
if (_sub_field.empty())
{
if (_type == _realfld)
tmp.strncpy(_p, _len);
else
__getfieldbuff( _len, _type, _p, tmp);
}
else
get_subfield(tmp);
return real(tmp);
}
TRecfield::operator TDate() const
{
TString16 tmp;
if (_sub_field.empty())
{
if (_type == _datefld)
{
tmp.strncpy(_p, 8);
return TDate(atol(tmp));
}
__getfieldbuff(_len, _type, _p, tmp);
}
else
get_subfield(tmp);
return TDate(tmp);
}
TRecfield::operator const char*() const
{
TString& tmp = get_tmp_string(max(_len, 50));
if (_sub_field.empty())
{
if (_type == _memofld)
return _rec->get(_name);
__getfieldbuff(_len, _type, _p, tmp);
}
else
get_subfield(tmp);
return tmp;
}
TRecnotype TRecfield::ptr() const
{
if (_p == NULL) return(RECORD_NON_FISICO);
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;
}