4b2662e4d9
Files correlati : Ricompilazione Demo : [ ] Commento : Correzzione relaitive al riporto precedente git-svn-id: svn://10.65.10.50/trunk@9671 c028cbd2-c16b-5b4b-a496-9718f37d4682
3581 lines
85 KiB
C++
Executable File
3581 lines
85 KiB
C++
Executable File
#include <fcntl.h>
|
|
#include <share.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define __ISAM_CPP
|
|
|
|
#ifndef FOXPRO
|
|
#include <expr.h>
|
|
#include <execp.h>
|
|
#include <progind.h>
|
|
#endif
|
|
|
|
#include <codeb.h>
|
|
#include <config.h>
|
|
#include <extcdecl.h>
|
|
#include <mailbox.h>
|
|
#include <postman.h>
|
|
#include <prefix.h>
|
|
#include <relation.h>
|
|
#include <scanner.h>
|
|
#include <utility.h>
|
|
#include <memo.h>
|
|
#include <varrec.h>
|
|
#include <codeb.h>
|
|
#include <lffiles.h>
|
|
|
|
#ifdef DBG
|
|
#define JOURNAL
|
|
#endif
|
|
|
|
#ifdef JOURNAL
|
|
#include <journal.h>
|
|
|
|
static FILE* _journal = (FILE*)0xFFFF;
|
|
|
|
FILE* get_journal()
|
|
{
|
|
if (_journal == (FILE*)0xFFFF)
|
|
{
|
|
TConfig ini(CONFIG_INSTALL, "Main");
|
|
const TString& name = ini.get("Journal");
|
|
if (name.not_empty())
|
|
_journal = fopen(name, "ab");
|
|
else
|
|
_journal = NULL;
|
|
}
|
|
return _journal;
|
|
}
|
|
|
|
TJournalHeader& get_journal_header(int num, const char* op, const char* type)
|
|
{
|
|
static TJournalHeader jh;
|
|
const int size = sizeof(TJournalHeader);
|
|
CHECKD(size == 64, "Invalid journal header: ", size);
|
|
|
|
memset(&jh, 0, size);
|
|
strcpy(jh._signature, "J00");
|
|
jh._header_length = size;
|
|
time(&jh._time);
|
|
jh._firm = prefix().get_codditta();
|
|
jh._logic_num = num;
|
|
strcpy(jh._operation, op);
|
|
strcpy(jh._type, type);
|
|
jh._data_size = 0;
|
|
return jh;
|
|
}
|
|
|
|
void write_journal(TJournalHeader& jh, void* data, int len)
|
|
{
|
|
FILE* j = get_journal();
|
|
jh._data_size = len;
|
|
fwrite(&jh, sizeof(TJournalHeader), 1, j);
|
|
fwrite(data, len, 1, j);
|
|
fflush(j);
|
|
}
|
|
|
|
#endif
|
|
|
|
#define RECLOCKTYPES 0xFF00
|
|
#define READTYPES 0x00FF
|
|
#define INVFLD 255
|
|
|
|
Str80 cprefix;
|
|
bool __field_changed = FALSE;
|
|
|
|
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 == 0)
|
|
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)
|
|
{
|
|
TDate dt(s);
|
|
#ifdef _DEMO_
|
|
int y = dt.year();
|
|
if (y & 0x0001) y--;
|
|
y >>= 3;
|
|
y++;
|
|
y /= 10;
|
|
if (y >= 25)
|
|
{
|
|
int m = dt.month();
|
|
if (m > 3)
|
|
dt.set_month(rand() % 3 + 1);
|
|
}
|
|
#endif
|
|
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("1STXY", 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);
|
|
|
|
const bool exceeded = len > l;
|
|
|
|
if ((t == _intfld) ||
|
|
(t == _longfld) ||
|
|
(t == _wordfld) ||
|
|
(t == _realfld) ||
|
|
(t == _intzerofld) ||
|
|
(t == _longzerofld)
|
|
)
|
|
{
|
|
if (len == 0 || exceeded)
|
|
{
|
|
strcpy(s2, "0");
|
|
s = s2;
|
|
len = 1;
|
|
}
|
|
|
|
__field_changed = FALSE;
|
|
const char c = (t == _intzerofld || t == _longzerofld) ? '0' : ' ';
|
|
for (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;
|
|
__field_changed = memcmp(s, &recout, l) != 0;
|
|
if (!__field_changed)
|
|
return;
|
|
|
|
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();
|
|
}
|
|
|
|
// 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)
|
|
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
|
|
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(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] = ' ';
|
|
}
|
|
|
|
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); ws.upper(); // 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 int __build_key(const 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 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))
|
|
{
|
|
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))
|
|
{
|
|
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)
|
|
{
|
|
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);
|
|
_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);
|
|
}
|
|
|
|
long TBaseisamfile::items() const
|
|
{
|
|
return DB_reccount(handle());
|
|
}
|
|
|
|
const char* TBaseisamfile::name() const
|
|
{
|
|
sprintf(_isam_string, "%d", num());
|
|
return _isam_string;
|
|
}
|
|
|
|
const char* TBaseisamfile::filename() const
|
|
{
|
|
const int n = _isam_handle > 0 ? _isam_handle : num();
|
|
strcpy(_isam_string, prefix().get_filename(n));
|
|
strcat(_isam_string, ".dbf");
|
|
return _isam_string;
|
|
}
|
|
|
|
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) 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());
|
|
TString key(128);
|
|
__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); // qui
|
|
if(rec.has_memo())
|
|
rec.init_memo(_recno, _isam_handle);
|
|
|
|
if (_lasterr == NOERR)
|
|
{
|
|
if (lockop == _lock)
|
|
prefix().lock_record(_isam_handle, _recno);
|
|
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");
|
|
|
|
#ifdef _DEMO_
|
|
|
|
if ((num() > LF_COMUNI && num() < LF_ANALISI) || num() > LF_RELANA)
|
|
{
|
|
if (items() > 979L)
|
|
return _isfilefull;
|
|
}
|
|
#endif
|
|
|
|
// Forza l'uso della chiave principale (per chiavi duplicate?)
|
|
const int fhnd = handle(1);
|
|
|
|
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);
|
|
|
|
if (_lasterr == NOERR)
|
|
{
|
|
#ifdef JOURNAL
|
|
if (get_journal())
|
|
{
|
|
TJournalHeader& jh = get_journal_header(num(), "ADD", "REC");
|
|
write_journal(jh, rec.string(), dst_len);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
_lasterr = get_error(_lasterr);
|
|
|
|
_recno = DB_recno(fhnd);
|
|
if (_lasterr == NOERR && rec.has_memo())
|
|
((TRectype &)rec).write_memo(_isam_handle, _recno );
|
|
|
|
return _lasterr;
|
|
}
|
|
|
|
int TBaseisamfile::write(const TRectype& rec)
|
|
{
|
|
return rec.write(*this);
|
|
}
|
|
|
|
|
|
int TBaseisamfile::write()
|
|
{
|
|
return TBaseisamfile::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)
|
|
{
|
|
#ifdef JOURNAL
|
|
if (get_journal())
|
|
{
|
|
TJournalHeader& jh = get_journal_header(num(), "MOD", "REC");
|
|
write_journal(jh, rec.string(), len);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
_lasterr = get_error(_lasterr);
|
|
}
|
|
else
|
|
DB_unlock(fhnd);
|
|
_recno = DB_recno(fhnd);
|
|
if(_lasterr == NOERR && 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 && curr().has_memo( ))
|
|
((TRectype &)rec).write_memo(_isam_handle, _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");
|
|
|
|
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)
|
|
{
|
|
_lasterr = DB_delete(fhnd); // Put only deletion flag on record, must remove keys too!
|
|
if (_lasterr == NOERR)
|
|
{
|
|
DB_flush(fhnd);
|
|
#ifdef JOURNAL
|
|
if (get_journal())
|
|
{
|
|
const int len = DB_reclen(fhnd);
|
|
TJournalHeader& jh = get_journal_header(num(), "DEL", "REC");
|
|
write_journal(jh, rec.string(), len);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
_lasterr = get_error(_lasterr);
|
|
DB_recall(fhnd);
|
|
}
|
|
}
|
|
|
|
if(_lasterr == NOERR && curr().has_memo())
|
|
curr().init_memo();
|
|
|
|
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);
|
|
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) // qui
|
|
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
|
|
{
|
|
_isam_handle = 0;
|
|
_lasterr = get_error(_isam_handle);
|
|
}
|
|
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()
|
|
{ // 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, FALSE, TRUE);
|
|
int err= isam_handle > 0 ? prefix().get_handle(isam_handle,1) : -60;
|
|
if (err < 0)
|
|
err = get_error(err);
|
|
else
|
|
{
|
|
const int trcreclen = prefix().get_reclen(_logicnum);
|
|
if (trcreclen > 0)
|
|
{
|
|
err = NOERR;
|
|
if (DB_tagget(isam_handle) == -1)
|
|
err = _ispatherr;
|
|
else
|
|
{
|
|
const int dbfreclen = DB_reclen(isam_handle);
|
|
if (dbfreclen != trcreclen)
|
|
err = _istrcerr;
|
|
}
|
|
}
|
|
else
|
|
err = _isbadtrc;
|
|
}
|
|
if (isam_handle > 0)
|
|
prefix().close_isamfile(isam_handle);
|
|
return err;
|
|
}
|
|
|
|
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 TBaseisamfile::get_relapp(TString& app) const
|
|
{
|
|
TConfig ini("install.ini");
|
|
TCallbackFileinfo fi;
|
|
fi._var.format("Edit_%d", num());
|
|
ini.for_each_paragraph(find_relapp, &fi);
|
|
if (fi._app.not_empty())
|
|
app = fi._app;
|
|
return app.not_empty();
|
|
}
|
|
|
|
|
|
bool TBaseisamfile::is_changed_since(long& last) const
|
|
{
|
|
bool yes = FALSE;
|
|
const int fh = ::_sopen(filename(), _O_RDONLY, _SH_DENYNO);
|
|
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);
|
|
}
|
|
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();
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @mfunc Aggiorna i flags associati al file
|
|
//
|
|
// @rdesc Ritorna NOERR se e' riuscita ad eseguire 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
|
|
|
|
{
|
|
if (num() <= 0)
|
|
return NOERR ;
|
|
|
|
TDir d;
|
|
const TDirtype dirtype = prefix().get_dirtype(_filename);
|
|
d.get(num(), _lock, dirtype);
|
|
int err = d.status(dirtype);
|
|
if (err == NOERR)
|
|
{
|
|
const FileDes& fd = prefix().get_filedes(_filename);
|
|
d.flags() = fd.Flags;
|
|
if (updateeod)
|
|
d.eod() = fd.EOD;
|
|
d.put(num(), dirtype);
|
|
}
|
|
setstatus(err);
|
|
return err;
|
|
}
|
|
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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 << SLASH << radix;
|
|
}
|
|
n.ext("dbf");
|
|
}
|
|
else
|
|
n.temp(NULL, "dbf");
|
|
|
|
if (!create)
|
|
{
|
|
TDir dir; dir.get(logicnum);
|
|
const word& len = dir.len();
|
|
|
|
FILE* f = fopen(n, "rb");
|
|
if (f == NULL)
|
|
fatal_box("Impossibile aprire il file temporaneo %s: %s",(const char*) n,(const char*)_strerror(NULL));
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
eod = eox = ftell(f) / len;
|
|
fclose(f);
|
|
}
|
|
|
|
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);
|
|
// dalla 1.5 serve ? relisfd(_isamfile);
|
|
fatal_box("Can't create temp file '%s' num. %d: Error n. %d", (const char*)filename, num(), err);
|
|
}
|
|
}
|
|
|
|
_isam_handle = prefix().open_isamfile(_logicnum, filename);
|
|
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=fopen(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; // qui
|
|
_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()
|
|
{
|
|
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, curr().rec_des(), &peod, FALSE);
|
|
}
|
|
_isam_handle = prefix().open_isamfile(_logicnum, _name);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
const char* TExternisamfile::name() const
|
|
{
|
|
return filename();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TSystemisamfile
|
|
///////////////////////////////////////////////////////////
|
|
|
|
int TSystemisamfile::build(TRecnotype eox, const TTrec& r)
|
|
{
|
|
int err=NOERR;
|
|
TDir d;
|
|
d.get(num());
|
|
CHECK(r.len() != 0, "Can't create a file with empty field info");
|
|
|
|
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 (!fexist(f))
|
|
make_dir(f);
|
|
if (r.len() != 0)
|
|
{
|
|
err=DB_build(fname,r.rec());
|
|
if (err != NOERR)
|
|
err = get_error(err);
|
|
setstatus(err);
|
|
|
|
#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;
|
|
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++;
|
|
|
|
TConfig conv(CONFIG_FCONV);
|
|
TString16 paragraph;
|
|
|
|
TString_array paralist;
|
|
conv.list_paragraphs(paralist);
|
|
|
|
for (long l = flev; err == 0 && l <= get_std_level(); 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 (long l = flev; l <= get_std_level(); 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 vis) // @parm Indica se visualizzare lo stato dell'operazione
|
|
|
|
{
|
|
CHECK(newrec.len() != 0, "Can't update file with empty field info");
|
|
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;
|
|
oldrec.get(num());
|
|
|
|
const 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
|
|
setstatus(err);
|
|
return err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dir.eox() > 0L)
|
|
{
|
|
dir.eod() = 0L;
|
|
dir.eox() = 0L;
|
|
}
|
|
}
|
|
|
|
TFilename fname;
|
|
if (toconvert)
|
|
fname = filename();
|
|
|
|
if (toconvert && (dir.eox() > 0L || fname.exist()))
|
|
{
|
|
TRecnotype ni = 0L;
|
|
TFilename tmpfname; tmpfname.temp("tf");
|
|
|
|
err=DB_build((const char*) tmpfname, wrec.rec());
|
|
|
|
if (err != NOERR)
|
|
{
|
|
err=get_error(err);
|
|
return (err);
|
|
}
|
|
|
|
if (dir.eod() > 0 && oldrec.len() > 0)
|
|
{
|
|
err = _open_ex(_excllock, FALSE);
|
|
if (err != NOERR)
|
|
return err;
|
|
|
|
// 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 = prefix().get_handle(ishandle);
|
|
if (fhnd < 0 )
|
|
{
|
|
err=get_error(fhnd);
|
|
return err;
|
|
}
|
|
|
|
TString s(80);
|
|
s.format("Aggiornamento archivio %s\nTempo stimato alla fine del processo: ", (const char*) fname);
|
|
|
|
const TRecnotype nitems = items();
|
|
TProgind p(nitems > 0 ? nitems : 1, s, FALSE, TRUE, 70);
|
|
|
|
TExtrectype nrec(wrec);
|
|
|
|
const int nflds = curr().items();
|
|
TArray infld, outfld;
|
|
for (int 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 clock_t start_time = clock();
|
|
for (first(); good(); next())
|
|
{
|
|
const bool tick = p.addstatus(1);
|
|
ni++;
|
|
|
|
if (curr().isdeleted())
|
|
continue;
|
|
|
|
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 && nrec.has_memo())
|
|
nrec.write_memo(ishandle, DB_recno(fhnd));
|
|
if (err != NOERR)
|
|
err=get_error(err);
|
|
setstatus(err);
|
|
|
|
if (tick)
|
|
{
|
|
const clock_t elapsed_ticks = clock() - start_time;
|
|
const clock_t total_ticks = elapsed_ticks * nitems / ni;
|
|
const clock_t estimated_ticks = total_ticks - elapsed_ticks;
|
|
long secs = estimated_ticks / CLOCKS_PER_SEC;
|
|
CHECK(secs >= 0, "Bad time estimation");
|
|
const int hours = int(secs / 3600L);
|
|
secs %= 3600L;
|
|
const int mins = int(secs / 60L);
|
|
secs %= 60L;
|
|
const int append_pos = s.find("o: ")+3;
|
|
s.cut(append_pos);
|
|
s << format("%02d:%02d:%02ld", hours, mins, secs);
|
|
p.set_text(s);
|
|
}
|
|
}
|
|
close();
|
|
prefix().close_isamfile(ishandle);
|
|
|
|
if (err!=NOERR) err=get_error(err);
|
|
|
|
p.setstatus(nitems);
|
|
}
|
|
|
|
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=fopen(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.eod() = ni;
|
|
}
|
|
}
|
|
if (err==NOERR)
|
|
{
|
|
dir.set_len(lenr);
|
|
dir.put(num(), _nordir, _sysdirop);
|
|
wrec.put(num());
|
|
prefix().update_recdes(num());
|
|
|
|
if (toconvert)
|
|
packindex();
|
|
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>
|
|
|
|
{
|
|
TDir d;
|
|
d.get(num(),_nolock, _nordir,_sysdirop); // Chi commenta muore!
|
|
d.get(num(),_nolock, (d.is_com()) ? _comdir : _nordir);
|
|
|
|
// CHECKS(filehnd() == NULL, "Can't pack open file", (const char*)filename());
|
|
|
|
int err = DB_packfile(vis, d.name(), zap ? 0L : d.eod());
|
|
|
|
if (zap && err == NOERR)
|
|
err = packindex(vis, FALSE);
|
|
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;
|
|
|
|
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 = 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)
|
|
|
|
// @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 = fopen(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");
|
|
|
|
if (extended)
|
|
{
|
|
TDate d(TODAY);
|
|
TLocalisamfile ditte(LF_NDITTE);
|
|
|
|
firm.format("%05ld", prefix().get_codditta());
|
|
year.format("%04d", d.year());
|
|
ditte.zero();
|
|
ditte.put("CODDITTA", firm);
|
|
if (ditte.read() == NOERR)
|
|
attprev = ditte.get("CODATTPREV");
|
|
}
|
|
|
|
fseek(fl, 0L, SEEK_END);
|
|
nitems = ftell(fl);
|
|
fclose(fl);
|
|
|
|
err = _open_ex();
|
|
if (err != NOERR)
|
|
{
|
|
error_box("Impossibile aprire il file %d", _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);
|
|
int len[MaxFields];
|
|
TString sfd(3);
|
|
TString s1(64);
|
|
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 long level = atol(f.token().mid(equal+1));
|
|
if (level > prefix().filelevel())
|
|
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);
|
|
} 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();
|
|
nflds++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = (const TString & ) fld[j];
|
|
len[j] = (curr().type(wfld) == _datefld) ? 10 : curr().length(wfld);
|
|
}
|
|
}
|
|
|
|
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("Imp. archivio %d\n%6ld records %6ld errori - %3d", _logicnum, r, e, last);
|
|
TProgind p(nitems, s1, TRUE, TRUE, 70);
|
|
for (s = f.line(); s.not_empty() && !p.iscancelled(); s = f.line())
|
|
{
|
|
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 %d\n%6ld records %6ld errori - %3d", _logicnum, r, e, last);
|
|
p.set_text(s1);
|
|
}
|
|
p.setstatus(f.tellg());
|
|
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';
|
|
}
|
|
if (curr().type((const TString&) fld[j]) == _memofld)
|
|
s1 = esc(s2);
|
|
else
|
|
s1 = s2;
|
|
put((const TString&) fld[j], s1);
|
|
}
|
|
}
|
|
|
|
int err = write();
|
|
if (err == _isreinsert)
|
|
err = rewrite();
|
|
|
|
if (err == NOERR)
|
|
r++;
|
|
else
|
|
{
|
|
error_box("Errore di scrittura alla riga %ld", r+e+1);
|
|
e++;
|
|
last = status();
|
|
break;
|
|
}
|
|
}
|
|
s1.format("Imp. archivio %d\n%6ld records %6ld errori - %3d", _logicnum, 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)
|
|
const char * filter) // @parm Indica l'espressione filtro
|
|
|
|
// @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(FALSE, nkey ? TRUE : FALSE);
|
|
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);
|
|
if (fixedlen && t == _memofld)
|
|
return error_box("Non e' possibile scaricare a lunghezza fissa un file con campi memo");
|
|
}
|
|
TRecnotype i = 0;
|
|
// const TRecnotype nitems = nkey ? items() : filehnd()->d->EOD;
|
|
const TRecnotype nitems = items();
|
|
|
|
s.format("Esportazione archivio %s", filename());
|
|
TProgind p(nitems, s, TRUE, TRUE, 70);
|
|
TString s1, sfld;
|
|
|
|
fprintf(f, "[Header]\nVersion=%ld\nFile=%d",
|
|
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;
|
|
}
|
|
if (skip)
|
|
continue;
|
|
}
|
|
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;
|
|
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);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
#endif // FOXPRO
|
|
|
|
|
|
void TBaseisamfile::recover()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Memo data
|
|
////////////////////////////////////////////////////////////
|
|
|
|
void TMemo_data::init(TRecnotype recno, TIsam_handle file)
|
|
{
|
|
CHECK(file != NULL || recno < 0, "Valid memo recno with NULL memo file");
|
|
_recno = recno;
|
|
_isamfile = file;
|
|
}
|
|
|
|
void TMemo_data::destroy()
|
|
{
|
|
TString_array::destroy();
|
|
_dirty.reset();
|
|
_recno = RECORD_NON_FISICO;
|
|
_isamfile = NULL;
|
|
}
|
|
|
|
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"); // qui
|
|
|
|
_length = prefix().get_reclen(logicnum);
|
|
|
|
_rec = new char [_length];
|
|
*_tab = '\0';
|
|
if (_length > 0)
|
|
zero();
|
|
else
|
|
setempty(TRUE);
|
|
|
|
const bool has_memo_fld = _length > 0 && lf_has_memo(_logicnum);
|
|
|
|
if(has_memo_fld)
|
|
init_memo(RECORD_NON_FISICO);
|
|
}
|
|
|
|
TRectype::TRectype(int logicnum)
|
|
: _memo_data(NULL)
|
|
|
|
{
|
|
init(logicnum); //qui
|
|
}
|
|
|
|
|
|
TRectype::TRectype(const TBaseisamfile* i)
|
|
: _memo_data(NULL)
|
|
{
|
|
init(i->num());
|
|
}
|
|
|
|
|
|
TRectype::TRectype(const TRectype& r)
|
|
:
|
|
_memo_data(NULL)
|
|
|
|
{
|
|
init(r._logicnum); //qui
|
|
if (r._memo_data)
|
|
{
|
|
init_memo(r._memo_data->recno(), r._memo_data->file());
|
|
*_memo_data = *r._memo_data;
|
|
}
|
|
memcpy(_rec, r._rec, _length);
|
|
strcpy(_tab, r._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) //qui
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
CHECK( _memo_data->recno() > 0, "Maiale! Non fare le GO con _recno < 0 " );
|
|
TCodeb_handle cb_handle = prefix().get_handle(file);
|
|
DB_go( cb_handle, _memo_data->recno());
|
|
for( int i = _memo_data->last( ); i > 0; i = _memo_data->pred( i ) )
|
|
{
|
|
if (_memo_data->is_dirty(i))
|
|
DB_memowrite( cb_handle, r->Fd[ i ].Name, ( char * )( const char * )_memo_data->row( i ) );
|
|
}
|
|
*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
|
|
{
|
|
__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
|
|
{
|
|
return (RecDes*)&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();
|
|
int p = findfld(recd, fieldname);
|
|
|
|
if (p != FIELDERR)
|
|
return (TFieldtypes) recd->Fd[p].TypeF;
|
|
else
|
|
return _nullfld;
|
|
}
|
|
|
|
|
|
int TRectype::length(const char* fieldname) const
|
|
{
|
|
const RecDes * recd = rec_des();
|
|
int p = findfld(recd, fieldname);
|
|
|
|
if (p != FIELDERR)
|
|
return(recd->Fd[p].Len);
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
int TRectype::ndec(const char* fieldname) const
|
|
|
|
{
|
|
const RecDes * recd = rec_des();
|
|
int p = findfld(recd, fieldname);
|
|
|
|
if (p != FIELDERR)
|
|
return(recd->Fd[p].Dec);
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
|
|
bool TRectype::exist(const char* fieldname) const
|
|
{
|
|
const bool ok = findfld(rec_des(), 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
|
|
{
|
|
static TFixed_string tmp(_isam_string, sizeof(_isam_string));
|
|
const RecDes * recd = rec_des();
|
|
const int nf = findfld(recd, fieldname);
|
|
const RecFieldDes& fd = recd->Fd[nf];
|
|
if (nf == FIELDERR)
|
|
{
|
|
unknown_field(fieldname);
|
|
tmp.cut(0);
|
|
}
|
|
else
|
|
{
|
|
__getfieldbuff(fd.Len, fd.TypeF, _rec + fd.RecOff, _isam_string);
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
#ifndef FOXPRO
|
|
|
|
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)
|
|
{
|
|
int orig = _memo_data->file();
|
|
if (orig)
|
|
{
|
|
TCodeb_handle cb_handle = prefix().get_handle(orig);
|
|
CHECKD(cb_handle >= 0, "Can't read memo from file ", orig); //qui
|
|
DB_go(cb_handle, _memo_data->recno()); //qui
|
|
_memo_data->add(DB_memoptr(orig, 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
|
|
{
|
|
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);
|
|
}
|
|
|
|
|
|
void TRectype::put(const char* fieldname, long val)
|
|
{
|
|
sprintf(_isam_string, "%ld", val);
|
|
put_str( fieldname, _isam_string);
|
|
}
|
|
|
|
void TRectype::put(const char* fieldname, TTextfile& txt)
|
|
{
|
|
long val = get_long(fieldname);
|
|
const bool isnew = val == 0;
|
|
|
|
TFilename fname;
|
|
int logicnum = num();
|
|
TIsam_handle isam_handle = prefix().open_isamfile(logicnum, fname);
|
|
|
|
TMemo_file memo(fname);
|
|
|
|
prefix().close_isamfile(isam_handle);
|
|
|
|
const long id = memo.set_field(txt, isnew ? FIELDERR : val);
|
|
if (isnew) val = id;
|
|
|
|
sprintf(_isam_string, "%ld", val);
|
|
put_str( fieldname, _isam_string);
|
|
}
|
|
|
|
|
|
void TRectype::put(const char* fieldname, word val)
|
|
{
|
|
sprintf(_isam_string, "%u", val);
|
|
put_str( fieldname, _isam_string);
|
|
}
|
|
|
|
void TRectype::put(const char* fieldname, const real& val)
|
|
{
|
|
put_str( fieldname, val.string());
|
|
setempty(FALSE);
|
|
}
|
|
|
|
void TRectype::put(const char* fieldname, const TCurrency& val)
|
|
{
|
|
put_str( fieldname, val.get_num().string());
|
|
setempty(FALSE);
|
|
}
|
|
|
|
void TRectype::put(const char* fieldname, const TDate& val)
|
|
{
|
|
put_str( fieldname, val.string(full));
|
|
}
|
|
|
|
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)
|
|
{
|
|
char s[2] = { val ? 'X' : ' ', '\0'};
|
|
put_str( fieldname, s);
|
|
}
|
|
|
|
#endif // FOXPRO
|
|
|
|
|
|
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') // VERIFICRE COL REPOSITORY
|
|
{
|
|
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::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;
|
|
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)
|
|
|
|
{
|
|
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;
|
|
}
|
|
strcpy(_tab, rec._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)
|
|
{
|
|
/* const int err = f._read(*this, _isnext, lockop);
|
|
*this = f.curr();
|
|
return err; */
|
|
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);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
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();
|
|
if (ok) // Test qualunque per usare {}
|
|
{
|
|
TConfig ini(ininame, "Transaction");
|
|
ini.set("Action", action);
|
|
ini.set("Mode", "A");
|
|
fill_transaction(ini);
|
|
}
|
|
ok = ::dispatch_transaction(*this, ininame);
|
|
::remove(ininame);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TRecfield (campo/sottocampo di un record)
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void TRecfield::set(int from, int to)
|
|
{
|
|
const RecDes* rd = _rec->rec_des();
|
|
const int nf = findfld(rd, _name);
|
|
if (nf == FIELDERR)
|
|
{
|
|
NFCHECK("File n. %d unknown field %s", _rec->num(), _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 + 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)
|
|
{
|
|
char buff[32];
|
|
sprintf(buff, "%d", i);
|
|
__putfieldbuff( _len, _dec, _type, buff, _p);
|
|
_rec->setempty(FALSE);
|
|
return i;
|
|
}
|
|
|
|
|
|
long TRecfield::operator =(long l)
|
|
{
|
|
char buff[32];
|
|
sprintf(buff, "%ld", l);
|
|
__putfieldbuff( _len, _dec, _type, buff, _p);
|
|
_rec->setempty(FALSE);
|
|
return l;
|
|
}
|
|
|
|
|
|
#ifndef FOXPRO
|
|
|
|
const real& TRecfield::operator =(const real& r)
|
|
{
|
|
char buff[80];
|
|
strcpy(buff, r.string());
|
|
__putfieldbuff( _len, _dec, _type, buff, _p);
|
|
_rec->setempty(FALSE);
|
|
return r;
|
|
}
|
|
|
|
#endif // FOXPRO
|
|
|
|
|
|
const TDate& TRecfield::operator =(const TDate& d)
|
|
{
|
|
char buff[16];
|
|
strcpy(buff, (const char*)d);
|
|
__putfieldbuff( _len, _dec, _type, buff, _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;
|
|
}
|
|
|