campo-sirio/include/isam.cpp
guy 21ea6df4df applicat.cpp Gestione di EdApp oltre che EdMask nelle configurazioni
execp.cpp    Aggiunta forzatura user sulla riga di comando
form.cpp     Aggiunte sezioni ad altezza variabile
form.h       Aggiuto metodo virtual bool TForm_item::is_section() const
isam.cpp     Forzatura user in chiamata delle conversioni
lffiles.h    Sostituito LF_ABPROF con LF_SVRIEP
mask.*       Aggiunto metodo sfield() che ritorna direttamente uno spreadsheet
rdoc.h       Risolti conflitti
relapp.cpp   Corretta cancellazione veloce di documenti protetti
relation.cpp Tolto spazio inutile


git-svn-id: svn://10.65.10.50/trunk@5062 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-08-18 14:11:37 +00:00

3484 lines
83 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>
#include <memo.h>
#include <codeb.h>
#include <varrec.h>
#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
#include <process.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#define NOT_OPEN() CHECKS(_isamfile != NULL, "File chiuso: ", (const char*)name())
#define RECLOCKTYPES 0xFF00
#define READTYPES 0x00FF
#define INVFLD 255
#define EXTERNAL_FILE 1000 // Files with id >= are considered to be externals
isfdptr* ext_files;
isfdptr* openf;
Str80 cprefix;
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};
HIDDEN int error_codes_ra[] = {NOERR,NOERR,_iskeynotfound,_iseof,_isbof,_isnrecerr} ;
// Codici da 0 a 9
HIDDEN int error_codes_rb[] = {-1,-1,_isreinsert,-1,-1,_islocked,-1,_isalropen,_iskeyerr } ;
// Codici da 10 a ...
extern "C" {
void CUpString(char*);
void crtrim(char*);
};
HIDDEN char _isam_string[257];
#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 (ODD(l))
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)
return (int) fp;
else
if (cmp > 0) return(FIELDERR);
}
return(FIELDERR);
}
void __getfieldbuff(byte l, byte t, const char * recin, char *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)
strncpy(s, recin, l);
}
s[l] = '\0';
if (l)
{
if (t == _datefld)
{
const TDate dt(s);
strcpy(s, dt.string(full));
}
else
if (t == _boolfld)
{
const char ok = toupper(*s);
if (ok == 'T' || ok == 'Y' || ok == 'S' || ok == 'X')
strcpy(s,"X");
else
strcpy(s," ");
}
}
}
void __putfieldbuff(byte l, byte d, byte t, const char* s, char* recout)
{
int len, i;
CHECK(recout, "Can't write null record" );
char s2[40];
if (t == _datefld)
{
if (*s)
{
const TDate dt(s);
strcpy(s2, dt.string(ANSI));
s = s2;
}
}
else
if (t == _boolfld)
{
strcpy(s2, (*s && strchr("STXY", toupper(*s)) != NULL) ? "T" : "F");
s = s2;
}
else
if (t == _realfld)
{
real r(s);
strcpy(s2, r.string(l, d));
s = s2;
}
len = strlen(s);
if (len > l)
{
yesnofatal_box("Impossibile scrivere %d caratteri su di un campo di %d", (int)len, (int)l);
return;
}
if ((t == _intfld) ||
(t == _longfld) ||
(t == _wordfld) ||
(t == _realfld) ||
(t == _intzerofld) ||
(t == _longzerofld)
)
{
if (len == 0)
{
strcpy(s2, "0");
s = s2;
len = 1;
}
const char c = (t == _intzerofld || t == _longzerofld) ? '0' : ' ';
for (i = l - len - 1; i >= 0; i--) recout[i] = c;
strncpy(&recout[l - len], s, len) ;
}
else
{
strncpy(recout, s, len) ;
for (i = l - 1; i >= len; i--) recout[i] = ' ';
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Funzioni implementate per la gestione file dati tramite Codebase
////////////////////////////////////////////////////////////////////////////////////////////////////
// Inizio(@)
// @doc INTERNAL
// @func Ritorna una Token_string con in nome dell'indice
void get_idx_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
// @comm Ritorna il nome con il prefisso corrente
{
long c = DB_getconf();
TDir d;
TTrec r;
d.get(logicnum);
r.get(logicnum);
TFilename f(d.name());
if ( c & 1) f.ext("cdx");
if ( c & 4) f.ext("mdx");
i_names.cut(0);
i_names.add(f);
f.ext("");
f.rtrim(1);
if (c & 2 || c & 8) // DBIII or CLIPPER format, returns f_name + .cgp, f_nameX + .n{d|t}x
for (int j=1; j<=r.keys();j++)
{
TString xx=f.name();
if (xx.len()<8)
f << ('0' + j);
else
f[8] = ('0' + j);
if (c & 2) // CLIPPER
f.ext("ndx");
else // DBIII
f.ext("ntx");
i_names.add(f);
}
i_names.restart();
}
int get_error(int err)
{
if (err > 0)
{
if (err >= 10)
{
if (err > 80 || error_codes_rb[err/10]==-1) return err;
else
return(error_codes_rb[err/10]);
}
else
return(error_codes_ra[err]);
}
else
if (err < 0)
{
int ierr = DB_get_error();
if (ierr < 0) ierr = -ierr;
if (ierr > 340 || error_codes_g[ierr/10]==-1)
return (-ierr);
return (error_codes_g[ierr/10]);
}
DB_zero_error();
return(NOERR);
}
HIDDEN 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( const int lffile )
{
TTrec r;
r.get( lffile );
return rec_has_memo(r.rec());
}
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] = ' ';
}
HIDDEN const char * translate_key(const char* key) // Traduce l'espressione chiave di CodeBase
{
// Trasforma l'espressione
static TToken_string t;
t = key;
TToken_string k(t.get(0),'+');
TToken_string range("",',');
TString ws;
const bool is_dup = t.get(1)[0] == 'X';
const int items = k.items();
t = "";
for (int i = 0; i<items; i++) // scorre i campi dell'espressione
{
ws = k.get(i); // Primo campo
const bool is_upper = ws.find("UPPER") >= 0;
const bool is_sub = ws.find("SUBSTR") >= 0;
int paren1 = ws.find('('); // Trova la prima parentesi aperta
int paren2,last,from,to;
if (paren1 >= 0 && is_sub && is_upper)
paren1 = ws.find('('); // Trova la seconda parentesi (in questo caso c'e' per forza)
if (paren1 >= 0) // Trova la prima virgola o parentesi chiusa (per qualsiasi espressione)
{
paren2 = ws.find(',');
if (paren2 == -1) // se non ci sono virgole trova la parentesi chiusa
paren2 = ws.find(')');
CHECK(paren2 > paren1,"Something wrong happened translating CodeBase expressions.");
if (is_sub) // Se e' una sottostringa estrae i campi DA e A
{
range = ws;
last = ws.find(')');
range.sub(paren2,last); // dalla virgola alla parentesi
from = range.get_int(0);
to = range.get_int(1);
}
ws = ws.sub(paren1+1,paren2); // Nome del campo pulito pulito
ws.upper();
}
if (is_upper)
t << "UPPER(";
t << ws; // aggiunge il nome del campo
if (is_sub)
{
t << "[";
t << from << ",";
t << to << "]";
}
if (is_upper)
t << ")";
t << '+';
}
t.rtrim(1); // Toglie il + in piu'
t.add(is_dup ? "X" : " ");
return t;
}
HIDDEN void getisfd(isfdptr & isfd, int logicnum)
{
CHECK(logicnum < EXTERNAL_FILE, "Incorrect use of getisfd() with external file definition");
isfd = new isdef ;
isfd->r = new RecDes ;
isfd->d = new FileDes ;
CGetFile(logicnum, isfd->d, _nolock, _nordir);
const TFixed_string name(isfd->d->SysName);
if (name.not_empty() && name[0] != '$')
isfd->ft = _comdir;
else
isfd->ft = _nordir;
COpenFile(logicnum, isfd->d, _nolock, isfd->ft);
CGetRec(logicnum, isfd->r, isfd->ft);
isfd->ln = logicnum;
}
HIDDEN void getisfd(isfdptr & isfd, const char* name)
{
// For External file definition only
TTrec rec;
int err;
char* cb_keys = new char[256*MaxKeys];
isfd = new isdef ;
isfd->r = new RecDes ;
isfd->d = new FileDes ;
isfd->ln = -1;
if (!fexist(name))
fatal_box("Il file %s non esiste.",(const char*)name);
TFilename n(name);
n.ext(""); // Remove extension
err = DB_recinfo(n,isfd->d,rec.rec(),cb_keys);
if (err == NOERR)
{
strncpy(isfd->d->SysName, name,40);
isfd->d->SysName[41] = '\0';
isfd->fhnd = 0;
isfd->RecNo = -1;
isfd->ft = 0;
isfd->knum = 0;
rec.rehash();
const int num_keys = rec.keys();
TToken_string keys(cb_keys,'$');
for (int i=0; i< num_keys; i++)
rec.update_keydef(i,translate_key(keys.get(i))); // Traduce l'espressione chiave di CodeBase
memcpy(isfd->r,rec.rec(),sizeof(RecDes));
}
else
{
if (err == -60) // This because existance of file is checked before
fatal_box("File %s aperto in modo esclusivo da un'altra applicazione.",name);
else
fatal_box("Apertura file %s : errore n. %d ",name,err);
}
delete cb_keys;
}
HIDDEN void relisfd(isfdptr & isfd)
{
if (isfd->ln > 0 && isfd->fhnd >= 0)
{
TDir d;
d.get(isfd->ln, _lock, (TDirtype) isfd->ft, _sysdirop);
d.eod() = isfd->d->EOD;
d.eox() = isfd->d->EOX;
d.put(isfd->ln, (TDirtype) isfd->ft, _sysdirop);
}
delete isfd->d;
delete isfd->r;
delete isfd;
#ifdef DBG
isfd = NULL; // Per provocare errori
#endif
}
HIDDEN int __build_key(RecDes *recd, int numkey, 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) > 80)
{
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 cisstart(isfdptr isfd, int keynum, TRectype & record, unsigned int mode)
{
// It seems quite unuseful... Quando cambio la chiave con setkey, la d4tagselect
// seleziona gia' l'indice, rendendo inutile il senso della cisstart
return NOERR;
}
HIDDEN int cisread(isfdptr isfd, TRectype & record, int mode)
{
int rmode = (mode & READTYPES), 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");
char key[128];
int err = NOERR ;
do
{
if (rmode>=_isequal && rmode<=_isgteq)
{
err=__build_key(isfd->r, isfd->knum, record.string(),key,TRUE);
if (err == NOERR)
{
err = DB_seek(isfd->fhnd,key);
if (rmode == _isgreat && err == NOERR)
err = DB_next(isfd->fhnd);
if (err != NOERR)
err = get_error(err);
}
if (rmode != _isequal && err == _iskeynotfound)
err = NOERR;
}
else
{
if (rmode==_isfirst)
err=DB_first(isfd->fhnd); else
if (rmode==_islast)
err=DB_last(isfd->fhnd); else
if (rmode==_isnext)
err=DB_next(isfd->fhnd); else
if (rmode==_isprev)
err=DB_prev(isfd->fhnd); else
if (rmode==_iscurr)
err=DB_go(isfd->fhnd,DB_recno(isfd->fhnd));
if (err != NOERR) err=get_error(err);
}
if (err == _iseof)
DB_last(isfd->fhnd);
if (err == NOERR && (lmode == _lock || lmode == _testandlock)) // _lock e _testandlock
{
err=DB_lock(isfd->fhnd);
if (err != NOERR) err=get_error(err);
if (err == _islocked && lmode == _testandlock) break;
}
if (err == _islocked)
{
record = (const char *) DB_getrecord(isfd->fhnd);
__build_key(isfd->r, isfd->knum, record.string(), key, TRUE);
message_box("Codice %s in uso da parte\ndi un altro utente.", key);
}
} while (err ==_islocked);
if (err == NOERR && lmode == _unlock)
{
err=DB_unlock(isfd->fhnd);
if (err != NOERR) err=get_error(err);
}
record = (const char *) DB_getrecord(isfd->fhnd);
isfd->RecNo = DB_recno(isfd->fhnd);
return err;
}
#ifndef CB6
HIDDEN int delkeys(isfdptr fd, char* record,long recno)
{
int rt=NOERR,oldkey = fd->knum;
for (int i=1; i<=fd->r->NKeys;i++)
{
char key[128];
DB_tagselect(fd->fhnd,i);
rt=__build_key(fd->r,i,record,key,TRUE);
if (rt!=NOERR) break;
rt=DB_delkey(fd->fhnd,key,recno);
if (rt!=NOERR) break;
}
DB_tagselect(fd->fhnd,oldkey);
return(rt);
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
// 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;
}
///////////////////////////////////////////////////////////
// TExtrectype
///////////////////////////////////////////////////////////
class TExtrectype : public TVariable_rectype
{
RecDes* _rd;
protected: // TRectype
virtual RecDes* rec_des() const { return _rd; }
virtual bool auto_virtual_fields() const { return TRUE; }
public:
TExtrectype(const TTrec& r); // Costruisce il record a partire da r
virtual ~TExtrectype() {}
};
TExtrectype::TExtrectype(const TTrec& r) : TVariable_rectype(r.num())
{
delete _rec;
_length = r.len();
_rec = new char [ _length ];
_rd = r.rec();
if( rec_has_memo(r.rec()))
init_memo(RECORD_NON_FISICO );
zero();
}
///////////////////////////////////////////////////////////
// TBaseisamfile
///////////////////////////////////////////////////////////
TBaseisamfile::TBaseisamfile(int logicnum, bool linkrecinst)
{
_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
{
NFCHECK("linkrecinst sparira' quanto prima, poiche' non sicura");
_current = openrec[_logicnum - 1];
_delrec = FALSE;
}
// _historicfile = ((r.field(RFLD_SYS_DATE) != FIELDERR) &&
// (r.field(RFLD_SYS_FIRST) != FIELDERR) &&
// (r.field(RFLD_SYS_LAST) != FIELDERR));
_historicfile = FALSE;
}
// @doc EXTERNAL
// @mfunc Reperisce il tracciato dal file stesso.
//
TBaseisamfile::TBaseisamfile(
const char* name) // @parm Indica il nome 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
{
_isamfile = NULL;
_lasterr = NOERR;
_delopenrec = FALSE;
_logicnum = -1;
TFilename n(name);
CHECK(n.not_empty(),"Must define the file to open!");
// Espande il nome!
const char c = n[0];
if (c == '%' || c == '$')
n = CAddPref((char*)(const char*)n);
else
if (c == '#')
{
n.ltrim(1);
n.format("%s/%s",__ptprf,(const char*)n);
}
n.ext("dbf");
getisfd (_isamfile, n); // Importa il tracciato dal file
TDir d;
d.get(1);
const int max = (int) d.eod();
for (int i=0; i<max; i++)
if (ext_files[i]==NULL)
{
_logicnum = _isamfile->ln = i+EXTERNAL_FILE; // Primo slot libero
ext_files[i] = _isamfile;
break;
}
if (_logicnum == -1)
fatal_box("Raggiunto il numero massimo di files esterni apribili.");
_current = new TRectype(this);
_delrec = TRUE;
_historicfile = FALSE;
}
TBaseisamfile::~TBaseisamfile()
{
if (_delrec)
{
if (_delopenrec)
openrec[_logicnum - 1] = NULL;
delete _current;
}
if (_isamfile != NULL)
delete _isamfile;
}
long TBaseisamfile::items() const
{
NOT_OPEN();
return(DB_reccount(filehnd()->fhnd));
}
const char* TBaseisamfile::name() const
{
sprintf(_isam_string, "%d", num());
return _isam_string;
}
const char* TBaseisamfile::filename() const
{
if (_isamfile == NULL && num() < EXTERNAL_FILE)
{
TDir d;
d.get(num());
strcpy(_isam_string, d.filename());
}
else
{
strcpy(_isam_string, _isamfile->d->SysName);
strcat(_isam_string, ".dbf");
}
return _isam_string;
}
const char* TBaseisamfile::description() const
{
if (_isamfile == NULL && num() < EXTERNAL_FILE)
{
TDir d;
d.get(num());
strcpy(_isam_string, d.des());
return _isam_string;
}
return _isamfile->d->Des;
}
TRecnotype TBaseisamfile::eod() const
{
NOT_OPEN();
return(DB_reccount(_isamfile->fhnd));
}
void TBaseisamfile::set_curr(TRectype * curr)
{
CHECK(curr != NULL, "You must pass a valid record");
if (_current != NULL)
delete _current;
_current = curr;
}
void TBaseisamfile::setkey(int nkey)
{
CHECKD(nkey > 0 && nkey-1 <= _isamfile->r->NKeys, "Chiave non valida ", nkey);
NOT_OPEN();
int rt = DB_tagselect(_isamfile->fhnd,nkey);
if (rt>=0) _isamfile->knum=nkey;
if (rt!=NOERR) rt=get_error(rt);
if (_lasterr == NOERR) setstatus(rt);
}
int TBaseisamfile::getkey() const
{
NOT_OPEN();
CHECKD(DB_tagget(_isamfile->fhnd) == _isamfile->knum, "Chiave inconsistente sul file ", _logicnum);
return _isamfile->knum;
}
int TBaseisamfile::first(word lockop)
{
NOT_OPEN();
curr().setdirty();
_lasterr=cisread(_isamfile, curr(), _isfirst + lockop);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
_recno = _isamfile->RecNo;
if( curr().has_memo( ) )
curr( ).init_memo(_recno);
return _lasterr;
}
int TBaseisamfile::last(word lockop)
{
NOT_OPEN();
curr().setdirty();
_lasterr=cisread(_isamfile, curr(), _islast + lockop );
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
_recno = _isamfile->RecNo;
if( curr().has_memo( ) )
curr( ).init_memo(_recno);
return _lasterr;
}
int TBaseisamfile::_next(word lockop)
{
NOT_OPEN();
curr().setdirty();
if (_recno != DB_recno(_isamfile->fhnd))
{
_lasterr = cisread(_isamfile, curr(), _isgreat + lockop);
if (_lasterr != NOERR)
{
_lasterr = get_error(_lasterr);
if (_lasterr != _islocked && _lasterr != _iseof)
fatal_box("Errore nella next %d : non posso riposizionarmi", _lasterr);
}
}
else
{
_lasterr=cisread(_isamfile, curr(), _isnext + lockop);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
}
_recno = _isamfile->RecNo;
if( curr().has_memo( ) )
curr( ).init_memo(_recno );
return _lasterr;
}
int TBaseisamfile::next(word lockop)
{
return curr().next(*this, lockop);
}
int TBaseisamfile::prev(word lockop)
{
NOT_OPEN();
curr().setdirty();
if (_recno != DB_recno(_isamfile->fhnd))
{
_lasterr = cisread(_isamfile, curr(), _isgteq + _nolock);
if (_lasterr != NOERR)
{
_lasterr = get_error(_lasterr);
if (_lasterr != _islocked && _lasterr != _iseof)
fatal_box("Errore nella next %d : non posso riposizionarmi", _lasterr);
}
}
_lasterr=cisread(_isamfile, curr(), _isprev + lockop);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
_recno = _isamfile->RecNo;
if( curr().has_memo( ) )
curr( ).init_memo(_recno);
return _lasterr;
}
int TBaseisamfile::reread(word lockop)
{
NOT_OPEN();
curr().setdirty();
_lasterr=cisread(_isamfile, curr(), _iscurr + lockop);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
_recno = _isamfile->RecNo;
if( curr().has_memo( ) )
curr( ).init_memo(_recno);
return _lasterr;
}
int TBaseisamfile::reread(TRectype& rec, word lockop)
{
NOT_OPEN();
rec.setdirty();
_lasterr=cisread(_isamfile, rec, _iscurr + lockop);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
_recno = _isamfile->RecNo;
if( rec.has_memo( ) )
rec.init_memo(_recno);
return _lasterr;
}
int TBaseisamfile::skip(TRecnotype nrec, word lockop)
{
char key[128];
NOT_OPEN();
if (!nrec) return NOERR;
curr().setdirty();
if (_recno != DB_recno(_isamfile->fhnd))
{
_lasterr = DB_go(_isamfile->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(_isamfile->fhnd,nrec);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
do {
if (_lasterr == _islocked)
{
__build_key(_isamfile->r, DB_tagget(_isamfile->fhnd), curr().string(), key,TRUE);
message_box("Codice %s in uso da parte\ndi un altro utente.", key);
}
_lasterr=cisread(_isamfile,curr(),_iscurr + lockop);
} while (_lasterr ==_islocked);
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
if( curr().has_memo( ) )
curr( ).init_memo(_recno);
return _lasterr;
}
// funzione di lettura dei file
int TBaseisamfile::_read(TRectype& rec, word op, word lockop)
{
NOT_OPEN();
rec.setdirty();
_lasterr=cisread(_isamfile, rec, op + lockop);
if (_lasterr != NOERR) _lasterr=get_error(_lasterr);
_recno = _isamfile->RecNo;
if( rec.has_memo( ) )
rec.init_memo(_recno);
return _lasterr;
}
int TBaseisamfile::read(TRectype& rec, word op, word lockop)
{
// CHECKD(op >= _iscurr && op <= _isgteq, "Invalid read operation : ", op);
NOT_OPEN();
_lasterr=rec.read(*this, op, lockop);
return _lasterr;
}
int TBaseisamfile::read(word op, word lockop)
{
// CHECKD(op >= _iscurr && op <= _isgteq, "Invalid read operation : ", op);
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)
{
NOT_OPEN();
rec.setdirty();
_lasterr=DB_go(_isamfile->fhnd,nrec);
if (_lasterr != NOERR)
_lasterr = get_error(_lasterr);
else
rec = (const char *) DB_getrecord(_isamfile->fhnd);
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
if( rec.has_memo( ) )
rec.init_memo( _recno );
return _lasterr;
}
int TBaseisamfile::_write(const TRectype& rec)
{
/*
NOT_OPEN();
TRectype save_rec(curr());
const int cur_key = getkey();
setkey(1);
_lasterr = cisread(_isamfile, save_rec, _isequal + _nolock); // Si Posiziona per sicurezza...
setkey(cur_key);
if (_lasterr == NOERR)
{
const int len = DB_reclen(_isamfile->fhnd);
browse_null(curr().string(), len);
if (memcmp(curr().string(),save_rec.string(), len) != 0)
{
memcpy(DB_getrecord(_isamfile->fhnd), curr().string(), len);
_lasterr = DB_rewrite(_isamfile->fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
}
else
DB_unlock(_isamfile->fhnd);
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
if(_lasterr == NOERR && curr().has_memo( ))
curr( ).write_memo( _isamfile, _recno );
}
return _lasterr;
*/
CHECK(!rec.empty(), "Can't write an empty record");
NOT_OPEN();
int oldkey=getkey();
browse_null(rec.string(),DB_reclen(_isamfile->fhnd));
setkey(1);
memcpy(DB_getrecord(_isamfile->fhnd),rec.string(),DB_reclen(_isamfile->fhnd));
_lasterr = DB_add(_isamfile->fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
setkey(oldkey);
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
if (_lasterr == NOERR && rec.has_memo())
((TRectype &)rec).write_memo( _isamfile, _recno );
return _lasterr;
}
int TBaseisamfile::write(const TRectype& rec)
{
// CHECK(!rec.empty(), "Can't write an empty record");
return rec.write(*this);
}
int TBaseisamfile::write()
{
// CHECK(!curr().empty(), "Can't write an empty record");
return TBaseisamfile::write(curr());
}
int TBaseisamfile::_rewrite(const TRectype& rec)
{
CHECK(!rec.empty(), "Can't write an empty record");
NOT_OPEN();
TRectype save_rec(rec);
const int cur_key = getkey();
setkey(1);
_lasterr = cisread(_isamfile, save_rec, _isequal + _nolock); // Si Posiziona per sicurezza...
setkey(cur_key);
if (_lasterr == NOERR)
{
const int len = DB_reclen(_isamfile->fhnd);
browse_null(rec.string(), len);
if (memcmp(rec.string(), save_rec.string(), len) != 0)
{
memcpy(DB_getrecord(_isamfile->fhnd), rec.string(), len);
_lasterr = DB_rewrite(_isamfile->fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
}
else
DB_unlock(_isamfile->fhnd);
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
if(_lasterr == NOERR && curr().has_memo( ))
((TRectype &)rec).write_memo( _isamfile, _recno );
}
return _lasterr;
}
int TBaseisamfile::rewrite(const TRectype& rec)
{
// CHECK(!rec.empty(), "Can't write an empty record");
return rec.rewrite(*this);
}
int TBaseisamfile::rewrite()
{
// CHECK(!curr().empty(), "Can't rewrite an empty record");
return TBaseisamfile::rewrite(curr());
}
int TBaseisamfile::rewriteat(const TRectype& rec, TRecnotype nrec)
{
NOT_OPEN();
if ((_lasterr=DB_go(_isamfile->fhnd,nrec))== NOERR)
{
browse_null(rec.string(),DB_reclen(_isamfile->fhnd));
memcpy(DB_getrecord(_isamfile->fhnd),rec.string(),DB_reclen(_isamfile->fhnd));
_lasterr=DB_rewrite(_isamfile->fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
} else
_lasterr = get_error(_lasterr);
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
if(_lasterr == NOERR && curr().has_memo( ))
((TRectype &)rec).write_memo( _isamfile, _recno );
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");
NOT_OPEN();
memcpy(DB_getrecord(_isamfile->fhnd),rec.string(),DB_reclen(_isamfile->fhnd));
if ((_lasterr=cisread(_isamfile, (TRectype&) rec, _isequal + _nolock))==NOERR)
{
_lasterr = DB_delete(_isamfile->fhnd); // Put only deletion flag on record, must remove keys too!
if (_lasterr != NOERR)
{
_lasterr = get_error(_lasterr);
DB_recall(_isamfile->fhnd);
}
#ifndef CB6
else
{
_lasterr=delkeys(_isamfile,rec.string(),_isamfile->RecNo);
if (_lasterr != NOERR)
{
DB_recall(_isamfile->fhnd);
_lasterr = get_error(_lasterr);
}
}
#endif
}
if(_lasterr == NOERR && curr().has_memo())
curr().memo_recno();
_recno = _isamfile->RecNo = DB_recno(_isamfile->fhnd);
return _lasterr;
}
int TBaseisamfile::remove(const TRectype& rec)
{
return rec.remove(*this);
}
int TBaseisamfile::remove()
{
return TBaseisamfile::remove(curr());
}
int TBaseisamfile::lock()
{
NOT_OPEN();
_lasterr = DB_lockfile(_isamfile->fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
return _lasterr;
}
int TBaseisamfile::unlock()
{
NOT_OPEN();
_lasterr = DB_unlock(_isamfile->fhnd);
if (_lasterr != NOERR) _lasterr = get_error(_lasterr);
return (_lasterr);
}
void TBaseisamfile::indexon()
{
}
bool TBaseisamfile::empty()
{
return (DB_reccount(_isamfile->fhnd) == 0);
}
void TBaseisamfile::indexoff()
{
}
// @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)
// @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
{
CHECKS(filehnd() == NULL, "File already open ", (const char*)filename());
getisfd(_isamfile,num());
if ((filehnd()->fhnd = DB_open(filehnd()->d->SysName,mode==_excllock)) >= 0)
{
TRecnotype n=DB_reccount(filehnd()->fhnd);
TDir d;
d.get(num(),_nolock,_nordir,_sysdirop);
if (d.is_com()) d.get(num(),_nolock,_comdir,_sysdirop);
if ((filehnd()->d->EOD != n && n > 0) || (n > d.eox()))
{
filehnd()->d->EOD = d.eod() = n;
filehnd()->d->EOX = d.eox() = n;
if (d.is_com())
d.put(num(),_comdir,_sysdirop);
else
d.put(num(),_nordir,_sysdirop);
}
filehnd()->ln = num();
openf[num() - 1] = filehnd();
_recno = RECORD_NON_FISICO;
CHECKD(filehnd()->r->NKeys > 0, "File senza indici: ", num());
setkey(1);
_lasterr = NOERR;
}
else
{
TString e_msg;
_lasterr = get_error(filehnd()->fhnd);
if (_lasterr == -60)
{
int rc = access(filename(),0); // check for existance
if (rc!=0)
e_msg.format("Il file %d(%s) non esiste, errore %d",num(),filename(),_lasterr);
else
e_msg.format("Il file %d(%s) e' aperto in modo esclusivo da un'altra applicazione",
num(), filename());
}
if (e_msg.empty())
e_msg.format("Il file %d(%s) non puo' essere aperto, errore %d",num(),filename(),_lasterr);
relisfd(_isamfile);
fatal_box((const char*) e_msg);
}
return (_lasterr);
}
int TBaseisamfile::_close()
{
int err = NOERR;
if (filehnd() != NULL)
{
if (num() > 0)
{
TDir d;
TRecnotype n=DB_reccount(filehnd()->fhnd);
d.get(num(),_nolock,_nordir,_sysdirop);
if (d.is_com()) d.get(num(),_nolock,_comdir,_sysdirop);
if ((filehnd()->d->EOD != n && n > 0) || (n > d.eox()))
{
filehnd()->d->EOD = d.eod() = n;
filehnd()->d->EOX = d.eox() = n;
if (d.is_com())
d.put(num(),_comdir,_sysdirop);
else
d.put(num(),_nordir,_sysdirop);
}
CHECK(openf[num() - 1] != NULL, "Open file array corrupted");
err=DB_close(filehnd()->fhnd);
if (err != NOERR) err = get_error(err);
if ((err == NOERR) && (num() > 0))
openf[num() - 1] = NULL ;
}
else
if (filehnd() == NULL)
{
err = _isnotopen;
error_box("File n. %d close : Error n. %d ", num(), err);
}
if (err == NOERR)
{
relisfd(_isamfile);
clearfilehnd();
}
}
setstatus(err);
return err;
}
int TBaseisamfile::is_valid()
{ // Ritorna 0 se il file puo' essere aperto senza errori
CHECKS(filehnd() == NULL, "File already open ", (const char*)filename());
int err = NOERR;
getisfd(_isamfile,num());
if ((filehnd()->fhnd = DB_open(filehnd()->d->SysName,0)) >= 0)
{
if (DB_tagget(filehnd()->fhnd) == -1) err = _ispatherr;
DB_close(filehnd()->fhnd);
}
else
err = get_error(filehnd()->fhnd);
relisfd(_isamfile);
return err;
}
///////////////////////////////////////////////////////////
// TLocalisamfile
///////////////////////////////////////////////////////////
// @doc EXTERNAL
// @mfunc Costruttore
//
// @rdesc Ritorna l'oggetto <c TLocalisamfile>
TLocalisamfile::TLocalisamfile(
int logicnum, // @parm Numero del logico del file
bool linkrecinst) // @parm Puo assumere i valori:
//
// @flag 0 | Istanzio un nuovo file fisico (default)
// @flag 1 | Utilizza, se possibile, un file gia' esistente
// @flag 2 | Crea un file temporaneo
: TBaseisamfile(logicnum, linkrecinst == TRUE)
// @comm ATTENZIONE: <p linkrecinst> puo' valere 0, 1, 2.
// Se vale 2 significa che si sta costruendo un file temporaneo
// per cui linkrecinst va' considerato FALSE
{
if (linkrecinst <= TRUE)
{
open();
if (_was_open)
_oldkey = getkey();
setkey(1);
}
else _was_open = FALSE;
}
// @mfunc Costruttore
//
// @rdesc Ritorna l'oggetto <c TLocalisamfile>
TLocalisamfile::TLocalisamfile(
const char* name) // @parm Nome del file esterno da aprire
: TBaseisamfile(name)
{
_was_open = FALSE;
}
TLocalisamfile::~TLocalisamfile()
{
if (_was_open)
setkey(_oldkey);
close();
}
int TLocalisamfile::close()
{
int err = NOERR;
if (!_was_open)
{
clearfilehnd();
}
else
{
if (_isamfile)
{
TRecnotype n = DB_reccount(filehnd()->fhnd);
TDir d;
d.get(num(),_nolock,_nordir,_sysdirop);
if (d.is_com()) d.get(num(),_nolock,_comdir,_sysdirop);
if ((filehnd()->d->EOD!=n && n > 0) || (n > d.eox()))
{
filehnd()->d->EOD = d.eod() = n;
filehnd()->d->EOX = d.eox() = n;
if (d.is_com())
d.put(num(),_comdir,_sysdirop);
else
d.put(num(),_nordir,_sysdirop);
}
err = DB_close(_isamfile->fhnd);
_isamfile->fhnd = -1;
if (err != NOERR) err = get_error(err);
relisfd(_isamfile);
_isamfile=NULL;
}
openf[num() -1] = 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];
}
else
{
err = _open();
_was_open = TRUE;
}
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();
}
// @doc EXTERNAL
// @mfunc Aggiorna i flags associati al file
//
// @rdesc Ritorna NOERR se e' riuscita ad eseguiore l'operazione, altrimenti ritorna il numero
// di errore generato (vedi <t TIsamerr>).
int TIsamfile::flags(
bool updateeod) // @parm Indica se aggiornare anche l'EOD del file
{
TDir d;
int err = NOERR;
if (filehnd()->ln <= 0) return NOERR ;
NOT_OPEN();
const TDirtype dirtype = (TDirtype) filehnd()->ft;
d.get(num(), _lock, dirtype);
if ((err = d.status(dirtype)) == NOERR)
{
d.flags() = filehnd()->d->Flags;
if (updateeod) d.eod() = filehnd()->d->EOD;
d.put(num(), dirtype);
}
setstatus(err);
return err;
}
///////////////////////////////////////////////////////////
// TIsamtempfile
///////////////////////////////////////////////////////////
TIsamtempfile::TIsamtempfile(int logicnum, const char* radix, bool create)
: TLocalisamfile(logicnum, 2)
{
TRecnotype eod = 0;
TRecnotype eox = 100;
TFilename n;
if (radix && *radix)
{
if (*radix == '%')
n = radix;
else
{
n.tempdir();
n << '/' << radix;
}
}
n.ext("dbf");
if (!create)
{
TDir dir; dir.get(logicnum);
const word& len = dir.len();
// Tolgo il % senno' che fa la fopen ?
if (n[0] == '%')
n = n.sub(1);
FILE* f = fopen(n, "r");
TString err;
err.format("Can't open temporary file %s: %s",(const char*) n,(const char*)_strerror(NULL));
CHECK(f, (const char *) err );
fseek(f, 0, SEEK_END);
eod = eox = ftell(f) / len;
fclose(f);
}
_autodel = create > TRUE;
n.ext("");
// Ci rimetto il % se prima l'avevo tolto, senno' che fa la open ?
if (n[0] != '%')
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 creatoun 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 tmpname;
CHECKS(filehnd() == NULL, "File already open", (const char*)filename());
if (radix[0] == '%')
tmpname << &radix[1] ;
else
tmpname.temp(radix);
getisfd (_isamfile, num());
strcpy(filehnd()->d->SysName, (const char*)tmpname);
filehnd()->d->EOX = eox;
if (create)
{
err=DB_build(filehnd()->d->SysName, filehnd()->r) ;
if (err == NOERR)
filehnd()->d->EOD = 0L;
else
{
err = get_error(err);
relisfd(_isamfile);
fatal_box("Create temporary file: Error n. %d", err);
}
}
else
filehnd()->d->EOD = eod;
filehnd()->fhnd = DB_open(filehnd()->d->SysName, 0);
if (filehnd()->fhnd < 0)
err = get_error(filehnd()->fhnd);
if (err != NOERR)
{
TFilename n(filehnd()->d->SysName);
relisfd(_isamfile);
if (err == -60)
{
if (access(n,0)) // check for existance
fatal_box("Apertura file %s : errore n. %d. File non esistente.",(const char*) n,err);
else
fatal_box("Apertura file %s : errore n. %d. File aperto in uso esclusivo da un'altra applicazione.",(const char*) n,err);
}
else
fatal_box("Apertura file %s : errore n. %d ",(const char*) n,err);
}
else
{
filehnd()->ln = -num();
filehnd()->knum = 1;
}
_recno = RECORD_NON_FISICO;
setstatus(err);
return err;
}
int TIsamtempfile::close()
{
int err = NOERR;
if (filehnd() != NULL)
{
err=DB_close(filehnd()->fhnd);
if (err != NOERR) err = get_error(err);
if (_autodel && err==NOERR)
{
TFilename f(filehnd()->d->SysName);
long c = DB_getconf();
f.ext("dbf");
::remove((const char*)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=fopen((const char*)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((const char *)f);
}
relisfd(_isamfile);
clearfilehnd();
}
setstatus(err);
return err;
}
///////////////////////////////////////////////////////////
// TExternisamfile
///////////////////////////////////////////////////////////
TExternisamfile::TExternisamfile(const char* name, bool exclusive)
: TLocalisamfile(name)
{
_name = name;
_name.ext("dbf");
// Espande il nome!
const char c = _name[0];
if (c == '%' || c == '$')
_name = CAddPref((char*)(const char*)_name);
else
if (c == '#')
{
_name.ltrim(1);
_name.format("%s/%s",__ptprf,(const char*)_name);
}
open(exclusive);
}
TExternisamfile::~TExternisamfile()
{
close();
}
int TExternisamfile::open(bool exclusive)
{
int err=NOERR;
filehnd()->fhnd = DB_open(_name, exclusive);
if (filehnd()->fhnd < 0)
err = get_error(filehnd()->fhnd);
if (err != NOERR)
{
relisfd(_isamfile);
if (err == -60)
{
if (access(_name,0)) // check for existance
fatal_box("Apertura file %s : errore n. %d. File non esistente.",(const char*) _name,err);
else
fatal_box("Apertura file %s : errore n. %d. File aperto in uso esclusivo da un'altra applicazione.",(const char*) _name,err);
}
else
fatal_box("Apertura file %s : errore n. %d ",(const char*) _name,err);
}
else
filehnd()->knum = 1;
_recno = RECORD_NON_FISICO;
setstatus(err);
return err;
}
int TExternisamfile::close()
{
CHECKS(filehnd() != NULL, "File already closed", (const char*)_name);
int err;
err=DB_close(filehnd()->fhnd);
if (err != NOERR) err = get_error(err);
if (err == NOERR)
{
ext_files[_isamfile->ln - EXTERNAL_FILE] = NULL;
relisfd(_isamfile);
clearfilehnd();
}
setstatus(err);
return err;
}
const char* TExternisamfile::name() const
{
sprintf(_isam_string, "%s", (const char*)_name);
return _isam_string;
}
///////////////////////////////////////////////////////////
// TSystemisamfile
///////////////////////////////////////////////////////////
int TSystemisamfile::build(TRecnotype eox, const TTrec& r)
{
CHECKS(filehnd() == NULL, "Can't build open file", (const char*)filename());
int err=NOERR;
TDir d;
d.get(num());
CHECK(r.len() != 0, "Can't create a file with empty field info");
TFilename f(d.name());
f = f.path(); if (!is_not_slash(f.right(1)[0])) f.rtrim(1);
if (!fexist(f))
make_dir(f);
if (r.len() != 0)
{
err=DB_build(d.name(),r.rec());
if (err == NOERR)
{
isfdptr i;
getisfd(i,num());
i->d->EOX = eox;
i->fhnd = 0; // So relisfd() will record the EOX just set
relisfd(i);
}
else
err = get_error(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::build(TRecnotype eox)
{
TTrec r;
r.get(num());
return build(eox,r);
}
int TSystemisamfile::extend(TRecnotype eox)
{
int err = NOERR;
isfdptr i;
CHECKS(filehnd() == NULL, "Can't extend open file ", (const char*)filename());
getisfd(i,num());
if (num() > 0)
{
if (eox < i->d->EOD)
err = _ispathfull;
else
{
i->d->EOX = eox;
i->fhnd = 0; // So relisfd() will write the EOX just set.
}
}
relisfd(i);
setstatus(err);
clearfilehnd();
return err;
}
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++;
for (long l = flev; err == 0 && l <= get_std_level(); l++)
{
TString16 paragraph(format("%06ld", l));
TConfig conv(CONFIG_FCONV, paragraph);
if (!conv.new_paragraph() && conv.exist(v, num()))
{
TToken_string s(conv.get(v, NULL, num()), ' ');
TFilename f(s.get(0));
f.ext(".exe");
s << " " << main_app().get_firm();
TExternal_app app(s);
if (app.can_run())
{
if (fexist(f))
{
app.run(FALSE, 0x3); // Synchronous Spawn with User
err = app.error();
TMailbox mail;
TMessage* msg = mail.next(TRUE);
if (err == 0 && msg != NULL)
err = atoi(msg->body());
}
}
else err = 16;
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++;
for (long l = flev; l <= get_std_level(); 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);
}
}
// @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 vis) // @parm Indica se visualizzare lo stato dell'operazione
{
CHECKS(filehnd() == NULL, "Can't update open file", (const char*)filename());
CHECK(newrec.len() != 0, "Can't update to file with empty field info");
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();
int err = NOERR;
TTrec oldrec;
oldrec.get(num());
if (wrec.len() != 0)
{
const long lev = prefix().filelevel();
const bool lcf = getlcf(lev);
err = exec_convapp(lev, TRUE);
if (err != NOERR)
{
setstatus(err);
return err;
}
if (!lcf && wrec == oldrec)
{
err = exec_convapp(lev, FALSE);
setstatus(err);
return err;
}
const TRecnotype nitems = dir.eod();
const unsigned int lenr = wrec.len();
if (!toconvert && dir.eox() > 0L)
{
dir.eod() = 0L;
dir.eox() = 0L;
}
if (toconvert && dir.eox() > 0L)
{
TRecnotype ni = 0L;
isfdptr i0;
TFilename tmpfname("tmpf");
open(_excllock);
getisfd(i0, num());
err=DB_build((const char*) tmpfname, wrec.rec());
if (err != NOERR)
{
err=get_error(err);
return (err);
}
i0->fhnd=DB_open((const char*)tmpfname,0);
if (i0->fhnd < 0 ) err=get_error(i0->fhnd);
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(wrec);
TRecnotype i = 0;
for (int j = 0; j < nflds; j++)
fld.add(TString(curr().fieldname(j)), j);
for (first(); good(); next())
{
if ((i++ % 50) == 0) p.setstatus(i + 1);
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);
browse_null(nrec.string(),DB_reclen(i0->fhnd));
memcpy(DB_getrecord(i0->fhnd),nrec.string(),DB_reclen(i0->fhnd));
err=DB_add(i0->fhnd);
if ( err == NOERR && nrec.has_memo())
nrec.write_memo( i0, DB_recno(i0->fhnd));
if (err != NOERR) err=get_error(err);
setstatus(err);
}
const int werr=DB_close(i0->fhnd);
close();
if (err!=NOERR) err=get_error(err);
relisfd(i0);
p.setstatus(nitems);
if (err == NOERR)
{
long c = DB_getconf();
fname.ext("dbf");
tmpfname.ext("dbf");
fcopy((const char*)tmpfname,(const char*)fname);
::remove((const char*)tmpfname);
if (c & 1)
tmpfname.ext("fpt");
else
tmpfname.ext("dbt");
if (fexist((const char *) tmpfname))
{
if (c & 1)
fname.ext("fpt");
else
fname.ext("dbt");
fcopy((const char*)tmpfname,(const char*)fname);
::remove((const char*)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");
char in[16];
FILE *fp=fopen((const char *) tmpfname,"r");
while (fgets(in,16,fp)!=NULL)
{
TFilename a(in);
a.rtrim(1); // Cut \n
if (c & 8) // DBIII format
a.ext("ndx");
else
a.ext("ntx"); // CLIPPER format
::remove((const char *)a);
}
fclose(fp);
}
::remove((const char*)tmpfname);
dir.eod() = ni;
}
}
dir.set_len(lenr);
dir.put(num(), _nordir, _sysdirop);
wrec.put(num());
if (toconvert && dir.eox() > 0L) packindex();
if (err == NOERR)
err = exec_convapp(lev, FALSE);
}
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
// @xref <mf TSystemisamfile::packindex>
{
int err=NOERR;
TDir d;
d.get(num(),_nolock, _nordir,_sysdirop);
d.get(num(),_nolock, (d.is_com()) ? _comdir : _nordir);
CHECKS(filehnd() == NULL, "Can't pack open file", (const char*)filename());
err=DB_packfile(vis,d.name(),d.eod());
if (err == NOERR && curr().has_memo())
err = DB_packmemo(vis,d.name());
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;
}
// @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>
{
int err=NOERR;
TRecnotype peod;
TTrec r;
TDir d;
CHECKS(filehnd() == NULL, "Can't pack index of open file", (const char*)filename());
r.get(num());
d.get(num(),_nolock, _nordir,_sysdirop);
bool is_com = d.is_com();
d.get(num(),_nolock, is_com ? _comdir : _nordir);
err=DB_packindex(vis,d.name(),r.rec(),&peod,ask);
if (err != NOERR) err = get_error(err);
if (err != NOERR) error_box("Errore in compattamento indici.\nFile %d : %d", num(),err);
else
if (peod >= 0 && peod != d.eod())
{
d.eod() = peod;
d.put(num(), is_com ? _comdir : _nordir);
}
setstatus(err);
return err;
}
int TSystemisamfile::pack(bool vis, bool ask)
{
int err=NOERR;
if ((err=packfile(vis))==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)
// @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>
{
FILE* fl = fopen(from, "r");
int err=NOERR;
if (fl == NULL)
{
error_box("Non riesco ad aprire il file %s",from);
return 2;
}
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 > get_std_level())
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, get_std_level()/100, get_std_level()%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
{
#ifdef DBG
yesnofatal_box("Numero linea relativa all'errore: %ld",r+e+1);
#endif
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;
}
// @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)
// @xref <mf TSystemisamfile::load>
{
FILE* f = fopen(to, "w");
if (f == NULL)
{
setstatus(2);
return 2;
}
if (withdeleted) nkey = 0;
int err = ferror(f);
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", prefix().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()
{
}
////////////////////////////////////////////////////////////
// TRectype
////////////////////////////////////////////////////////////
TRectype::TRectype(int logicnum)
: _cod(NULL), _memo_data(NULL), _memo_dirty(NULL)
{
bool has_memo_fld = FALSE;
_logicnum = logicnum;
if (openf[_logicnum - 1] != NULL)
{
_length = DB_reclen(openf[logicnum - 1]->fhnd);
has_memo_fld = rec_has_memo(rec_des());
}
else
{
TDir wdir;
wdir.get(_logicnum, _nolock, _nordir, _sysdirop);
if (wdir.is_com())
wdir.get(_logicnum, _nolock, _comdir, _sysdirop);
_length = wdir.len();
has_memo_fld = _length > 0 && lf_has_memo(_logicnum);
}
_rec = new char [ _length ];
*_tab = '\0';
if (_length)
zero();
else
setempty(TRUE);
if(has_memo_fld)
init_memo(RECORD_NON_FISICO );
}
TRectype::TRectype(const TBaseisamfile* i)
: _cod(NULL), _memo_data(NULL), _memo_dirty(NULL)
{
bool has_memo_fld = FALSE;
_logicnum = i->num();
if (i->filehnd() != NULL && _logicnum < EXTERNAL_FILE)
{
_length = DB_reclen(i->filehnd()->fhnd);
has_memo_fld = rec_has_memo(rec_des());
}
else
if (_logicnum >= EXTERNAL_FILE)
{
_length = i->filehnd()->d->LenR;
has_memo_fld = rec_has_memo(i->filehnd()->r);
}
else
{
TDir wdir;
wdir.get(_logicnum, _nolock, _nordir, _sysdirop);
if (wdir.is_com())
wdir.get(_logicnum, _nolock, _comdir, _sysdirop);
_length = wdir.len();
has_memo_fld = _length > 0 && lf_has_memo(_logicnum);
}
*_tab = '\0';
_rec = new char [ _length ];
if (_length)
zero();
else
setempty(TRUE);
if(has_memo_fld)
init_memo(RECORD_NON_FISICO );
}
TRectype::TRectype(const TRectype& r)
: _cod(NULL), _memo_data(NULL), _memo_dirty(NULL)
{
_logicnum = r._logicnum;
if (r._memo_data)
{
init_memo();
*_memo_data = *r._memo_data;
CHECK(r._memo_dirty, "memo_dirty NULL con memo_data valido");
*_memo_dirty= *r._memo_dirty;
}
_length = r.len();
_rec = new char [ _length ];
_rec[0] = r._rec[0];
memcpy(_rec + 1, r._rec + 1, _length - 1);
strcpy(_tab, r._tab);
if (r._cod != NULL)
_cod = new TRecfield(*this, "COD");
setempty(r.empty());
}
TRectype::~TRectype()
{
if (_cod != NULL) delete _cod;
if (_rec != NULL) delete _rec;
if (_memo_data != NULL ) delete _memo_data;
if (_memo_dirty != NULL ) delete _memo_dirty;
}
void TRectype::unknown_field(const char* name) const
{
yesnofatal_box("Il campo '%s' non appartiene al file %d", name, _logicnum);
}
void TRectype::write_memo(isdef * file, const TRecnotype recno)
{
memo_recno(recno);
CHECK( _memo_recno > 0, "Maiale! Non fare le GO con _recno < 0 " );
DB_go( file->fhnd, _memo_recno );
RecDes *r = rec_des( );
for( int i = _memo_data->last( ); i > 0; i = _memo_data->pred( i ) )
DB_memowrite( file->fhnd, r->Fd[ i ].Name, ( char * )( const char * )_memo_data->row( i ) );
*this = (const char *) DB_getrecord(file->fhnd);
init_memo(recno);
}
void TRectype::init_memo( const TRecnotype recno)
{
memo_recno(recno);
if (_memo_data == NULL)
_memo_data = new TString_array();
else
_memo_data->destroy();
if (_memo_dirty == NULL)
_memo_dirty = new TBit_array();
else
_memo_dirty->reset();
}
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;
}
const char* TRectype::build_key(int num) const
{
__build_key(rec_des(), num, string(), __tmp_string, TRUE);
return __tmp_string;
}
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>
{
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);
return res;
}
HIDDEN bool fld_empty(const char* s, int len, bool number)
{
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)
///////////////////////////////////////////////////////////
RecDes* TRectype::rec_des() const
{
const isdef* i = _logicnum < EXTERNAL_FILE ? openf[_logicnum-1] : ext_files[_logicnum - EXTERNAL_FILE];
CHECKD(i, "Can't use a record of closed file ", _logicnum);
RecDes* r = i->r;
CHECKD(r, "Missing record description of file", _logicnum);
return r;
}
int TRectype::items() const
{
return rec_des()->NFields;
}
const char* TRectype::start(int nf) const
{
return string() + rec_des()->Fd[nf].RecOff;
}
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 < items() ; 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;
}
TFieldtypes TRectype::type(const char* fieldname) const
{
int p;
const RecDes * recd = rec_des();
if ((p = findfld(recd, fieldname)) != -1) return (TFieldtypes) recd->Fd[p].TypeF;
else return _nullfld;
}
int TRectype::length(const char* fieldname) const
{
int p;
const RecDes * recd = rec_des();
if ((p = findfld(recd, fieldname)) != -1) return(recd->Fd[p].Len);
else return(0);
}
int TRectype::ndec(const char* fieldname) const
{
int p;
const RecDes * recd = rec_des();
if ((p = findfld(recd, fieldname)) != -1) return(recd->Fd[p].Dec);
else return(0);
}
bool TRectype::exist(const char* fieldname) const
{
const bool ok = findfld(rec_des(), (char*)fieldname) != FIELDERR;
return ok;
}
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
{
char * s = _isam_string;
static TFixed_string tmp(_isam_string, sizeof(_isam_string));
const RecDes * recd = rec_des();
int nf = findfld(recd, fieldname);
if (nf == FIELDERR)
{
unknown_field(fieldname);
*s = '\0';
}
else
__getfieldbuff(recd->Fd[nf].Len, recd->Fd[nf].TypeF,
_rec + recd->Fd[nf].RecOff, s);
return tmp;
}
#ifndef FOXPRO
const TString& TRectype::get(const char* fieldname) const
{
if(type( fieldname ) == _memofld )
{
int index( findfld( rec_des( ), ( char * )fieldname ) );
if ( _memo_data->objptr( index ) && (*_memo_dirty)[ index ] )
return _memo_data->row( index );
if( _memo_recno >= 0L )
{
TLocalisamfile posfile( num() );
isdef * def = posfile.filehnd( );
DB_go( def->fhnd, _memo_recno );
_memo_data->add( DB_memoptr( def->fhnd, fieldname ), index );
}
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
{
real r(get_str(fieldname));
return r;
}
char TRectype::get_char(const char* fieldname) const
{
return *(get_str(fieldname));
}
bool TRectype::get_bool(const char* fieldname) const
{
return *(get_str(fieldname)) == 'X';
}
// @doc EXTERNAL
// @mfunc Ritorna il contenuto di un campo memo
//
// @rdesc Ritorna sempre TRUE
bool TRectype::get_memo(
const char* fieldname, // @parm Nome del campo da cui estrarre il contenuto
TTextfile& txt) const // @parm Reference della variabile a cui assegnare il contenuto dell campo
{
TToken_string memo( get( fieldname ), '\n' );
const int last = memo.items( );
for( int i = 0; i < last; i ++ )
{
TString m(memo.get(i));
const int l = m.len() > 0 ? m.len()-1 : 0;
if (m[l] == '\r') m.cut(l);
txt.append( m );
}
return TRUE;
}
#endif // FOXPRO
TDate TRectype::get_date(const char* fieldname) const
{
TDate d(get_str(fieldname));
return d;
}
#ifndef FOXPRO
void TRectype::put(const char* fieldname, int val)
{
sprintf(_isam_string, "%d", val);
put_str( fieldname, _isam_string);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, long val)
{
sprintf(_isam_string, "%ld", val);
put_str( fieldname, _isam_string);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, TTextfile& txt)
{
long val = get_long(fieldname);
bool isnew = val == 0;
TLocalisamfile f(_logicnum);
TMemo_file memo(f.filename());
long id = memo.set_field(txt, isnew ? FIELDERR : val);
if (isnew) val = id;
sprintf(_isam_string, "%ld", val);
put_str( fieldname, _isam_string);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, word val)
{
sprintf(_isam_string, "%u", val);
put_str( fieldname, _isam_string);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, const real& val)
{
put_str( fieldname, val.string());
setempty(FALSE);
}
void TRectype::put(const char* fieldname, const TDate& val)
{
put_str( fieldname, val.string(full));
setempty(FALSE);
}
void TRectype::put(const char* fieldname, char val)
{
const char w[2] = {val, '\0'};
put_str( fieldname, w);
setempty(FALSE);
}
void TRectype::put(const char* fieldname, bool val)
{
char s[2] = { val ? 'X' : ' ', '\0'};
put_str( fieldname, s);
setempty(FALSE);
}
#endif // FOXPRO
void TRectype::put_str(const char* fieldname, const char* val)
{
const TFieldtypes ft = type(fieldname);
if (val == NULL)
val = "";
if (ft == _boolfld)
val = (*val && strchr("1STXY", toupper(*val)) != NULL) ? "T" : "F";
if (*val == '\0') // Da provare
{
TRecfield f(*this, fieldname);
if (*f.pos() == '\0') return;
}
if(type(fieldname) == _memofld)
{
int index( findfld( rec_des( ), ( char * ) fieldname ) );
_memo_dirty->set( index );
_memo_data->add( val, index );
}
else
{
const RecDes * recd = rec_des();
int nf = findfld(recd, fieldname);
if (nf == FIELDERR)
unknown_field(fieldname);
else
__putfieldbuff(recd->Fd[nf].Len, recd->Fd[nf].Dec, recd->Fd[nf].TypeF, val,
_rec + recd->Fd[nf].RecOff);
}
setempty(FALSE);
}
void TRectype::zero(const char* fieldname)
{
if (_cod != NULL && strcmp(fieldname , "COD") == 0)
*_cod = _tab;
else
{
const RecDes * recd = rec_des();
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;
if (type == _datefld)
__putfieldbuff(len, dec, _datefld, "", p);
else
{
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';
}
}
}
}
}
void TRectype::zero(char c)
{
recall();
memset(_rec + 1, c, len() - 1);
if (_cod != NULL)
*_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_recno);// ??
*_memo_data = *rec._memo_data;
CHECK(rec._memo_dirty, "memo_dirty NULL con memo_data valido");
*_memo_dirty= *rec._memo_dirty;
}
setempty(rec.empty()); // Copy emptiness status
return *this;
}
// Certified 100%
TRectype& TRectype::operator =(const TBaseisamfile& f)
{
return *this = f.curr();
}
// Certified ??%
int TRectype::read(TBaseisamfile& f, word op, word lockop)
{
return f._read(*this,op,lockop) ;
}
int TRectype::readat(TBaseisamfile& f, TRecnotype nrec, word lockop)
{
return f._readat(*this,nrec,lockop);
}
// Certified 100%
int TRectype::next(TBaseisamfile& f,word lockop)
{
const int err = f._next(lockop);
*this = f.curr();
return err;
}
// Certified ??%
int TRectype::write(TBaseisamfile& f) const
{ return f._write(*this); }
// Certified ??%
int TRectype::rewrite(TBaseisamfile& f) const
{
return f._rewrite(*this);
}
// Certified ??%
int TRectype::remove(TBaseisamfile& f) const
{
return f._remove(*this);
}
void TRectype::renum_key(const char* field, const char* val)
{
put(field, val);
}
// Certified 99%
TRectype& TRectype::operator =(const char* rec)
{
memcpy(_rec, rec, _length);
setempty(FALSE);
return *this;
}
const char* TRectype::key(int numkey) const
{
__build_key(rec_des(), numkey, _rec, _isam_string,FALSE);
return _isam_string;
}
///////////////////////////////////////////////////////////
// TRecfield (campo/sottocampo di un record)
///////////////////////////////////////////////////////////
void TRecfield::set(int from, int to)
{
int nf;
RecDes* rd = _rec->rec_des();
if ((nf = findfld(rd, _name)) == FIELDERR)
{
_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() + rd->Fd[nf].RecOff + from;
_dec = rd->Fd[nf].Dec;
_type = (TFieldtypes)rd->Fd[nf].TypeF;
if (to >= 0)
{
CHECK(from <= to && to <= rd->Fd[nf].Len, "Invalid Range");
_len = to - from + 1;
}
else _len = rd->Fd[nf].Len - from;
}
}
TRecfield::TRecfield(TRectype& rec, const char* name, int from, int to)
{
strcpy(_name, name);
_rec = &rec;
set(from, to);
}
int TRecfield::operator =(int i)
{
sprintf(_isam_string, "%d", i);
__putfieldbuff( _len, _dec, _type, _isam_string, _p);
_rec->setempty(FALSE);
return i;
}
long TRecfield::operator =(long l)
{
sprintf(_isam_string, "%ld", l);
__putfieldbuff( _len, _dec, _type, _isam_string, _p);
_rec->setempty(FALSE);
return l;
}
#ifndef FOXPRO
const real& TRecfield::operator =(const real& r)
{
strcpy(_isam_string, r.string());
__putfieldbuff( _len, _dec, _type, _isam_string, _p);
_rec->setempty(FALSE);
return r;
}
#endif // FOXPRO
const TDate& TRecfield::operator =(const TDate& d)
{
strcpy(_isam_string, (const char*)d);
__putfieldbuff( _len, _dec, _type, _isam_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
{
if (_type == _intfld || _type == _intzerofld || _type == _longfld || _type == _longzerofld)
{
strncpy(_isam_string, _p, _len);
_isam_string[_len] = '\0';
}
else
__getfieldbuff( _len, _type, _p, _isam_string);
return atoi(_isam_string);
}
TRecfield::operator long() const
{
if (_type == _longfld || _type == _longzerofld || _type == _intfld || _type == _intzerofld)
{
strncpy(_isam_string, _p, _len);
_isam_string[_len] = '\0';
}
else
__getfieldbuff( _len, _type, _p, _isam_string);
return atol(_isam_string);
}
#ifndef FOXPRO
TRecfield::operator const real() const
{
if (_type == _realfld)
{
strncpy(_isam_string, _p, _len);
_isam_string[_len] = '\0';
}
else
__getfieldbuff( _len, _type, _p, _isam_string);
real r(_isam_string);
return r;
}
#endif // FOXPRO
TRecfield::operator TDate() const
{
if (_type == _datefld)
{
strncpy(_isam_string, _p, 8);
_isam_string[8] = '\0';
return TDate(atol(_isam_string));
}
__getfieldbuff(_len, _type, _p, _isam_string);
return TDate(_isam_string);
}
TRecfield::operator const char*() const
{
if (_type == _memofld)
return _rec->get(_name);
__getfieldbuff(_len, _type, _p, _isam_string);
return _isam_string;
}
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;
}