#include #include #define __ISAM_CPP #ifndef FOXPRO #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #define RECLOCKTYPES 0xFF00 #define READTYPES 0x00FF #define INVFLD 255 Str80 cprefix; 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) { 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("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); 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; } 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 { if (exceeded) len = l; 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 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; 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; } 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 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 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) { 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) 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 != _iseof) fatal_box("Errore nella next %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); } } 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

void set_autoload_new_files( bool on) // @parm Valore da assegnare // @comm Il valore di

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) { _logicnum = logicnum; _isam_handle = 0; _curr_key = 0; _lasterr = NOERR; _current = new TRectype(this); } // @doc EXTERNAL // @mfunc Reperisce il tracciato dal file stesso. // TBaseisamfile::TBaseisamfile( const char* name, int mode, bool index) // @parm Indica il nome del file // @comm Esiste la possibilita' di codificare i valori di pathpref e prefix in

// % si riferisce ai dati comuni // $ si riferisce ai dati di ditta corrente // # si riferisce al direttorio indicato da PATHPREF.INI { _lasterr = NOERR; TFilename filename(name); // Espande il nome! const char c = filename[0]; if (c == '%' || c == '$') filename = CAddPref(filename.get_buffer()); else if (c == '#') { filename.ltrim(1); filename.format("%s/%s",__ptprf,(const char*)filename); } _logicnum = LF_EXTERNAL; _isam_handle = prefix().open_isamfile(_logicnum, filename, mode == _excllock, index); _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(); const FileDes& d = prefix().get_filedes(n); strcpy(_isam_string, d.SysName); 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.", (const char*)key); _lasterr = cisread(fhnd, getkey(), curr(),_iscurr + lockop, _recno); } if (curr().has_memo()) curr().init_memo(_recno); 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); if(rec.has_memo()) rec.init_memo(_recno); if (lockop && _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); 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) _lasterr = get_error(_lasterr); _recno = DB_recno(fhnd); if (_lasterr == NOERR && rec.has_memo()) ((TRectype &)rec).write_memo( fhnd, _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) _lasterr = get_error(_lasterr); } else DB_unlock(fhnd); _recno = DB_recno(fhnd); if(_lasterr == NOERR && curr().has_memo( )) ((TRectype &)rec).write_memo( fhnd, _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( fhnd, _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"); const int fhnd = handle(1); memcpy(DB_getrecord(fhnd),rec.string(),DB_reclen(fhnd)); if ((_lasterr=cisread(fhnd, 1, (TRectype&)rec, _isequal + _nolock, _recno))==NOERR) { _lasterr = DB_delete(fhnd); // Put only deletion flag on record, must remove keys too! if (_lasterr != NOERR) { _lasterr = get_error(_lasterr); DB_recall(fhnd); } } if(_lasterr == NOERR && curr().has_memo()) curr().memo_recno(); 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 ). 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

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

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) { _recno = RECORD_NON_FISICO; _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

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

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 = 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 { if (prefix().get_reclen(_logicnum) > 0) err = NOERR; else err = _isbadtrc; } if (isam_handle > 0) prefix().close_isamfile(isam_handle); return err; } /////////////////////////////////////////////////////////// // TLocalisamfile /////////////////////////////////////////////////////////// // @doc EXTERNAL // @mfunc Costruttore // // @rdesc Ritorna l'oggetto 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 TLocalisamfile::TLocalisamfile( const char* name, // @parm Nome del file esterno da aprire int mode, bool index) : TBaseisamfile(name, mode, index) { } 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 ). 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 ). 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

sia TRUE allora viene settato automaticamente il valore di

// a TRUE, cioe' viene abilitata l'eliminazione del file in chiusura. { int err = NOERR; TFilename filename; if (radix[0] == '%') filename << &radix[1] ; else filename.temp(radix); filename.ext(""); CHECKS(_isam_handle == 0, "File already open ", (const char*)filename); if (create) { RecDes* r = (RecDes*)&prefix().get_recdes(num()); err = DB_build(filename, r) ; if (err != NOERR) { err = get_error(err); fatal_box("Can't create temp file '%s' num. %d: Error n. %d", (const char*)filename, num(), err); } } _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()) // check for existance 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) { long c = DB_getconf(); f.ext("dbf"); ::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((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(f); } setstatus(err); return err; } /////////////////////////////////////////////////////////// // TExternisamfile /////////////////////////////////////////////////////////// TExternisamfile::TExternisamfile(const char* name, int mode, bool index) : TLocalisamfile(name, mode, index) { } TExternisamfile::~TExternisamfile() { _close(); } 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 ) 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

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, 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 ) 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 = _open_ex(_excllock); if (err != NOERR) return err; err=DB_build(tmpfname, wrec.rec()); if (err != NOERR) { err=get_error(err); 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.first(); j < nflds; j = outfld.succ(j)) { TRecfield& in_fld = (TRecfield&)infld[j]; TRecfield& out_fld = (TRecfield&)outfld[j]; const char* fld_val = in_fld; out_fld = fld_val; } if (lcf) makelc((TRectype &)nrec); browse_null(nrec.string(),lenr/*DB_reclen(fhnd)*/); memcpy(DB_getrecord(fhnd),nrec.string(),lenr/*DB_reclen(fhnd)*/); err=DB_add(fhnd); if ( err == NOERR && nrec.has_memo()) nrec.write_memo(fhnd, 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; } } dir.set_len(lenr); dir.put(num(), _nordir, _sysdirop); wrec.put(num()); prefix().update_recdes(num()); if (toconvert) { if (dir.eox() > 0L) 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 ). int TSystemisamfile::packfile( bool vis, // @parm Indica se visualizzare lo stato dell'operazione bool zap) // @parm Indica se distruggere tutti i records // @xref { 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(), 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 ). 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 { 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=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 ). int TSystemisamfile::load( const char* from, // @parm Nome del file da importare char fs, // @parm Carattere separatore di campo (default ) 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

e' TRUE e trova alcune stringhe col formato %stringa% (es. %frm%) // ne sostituisce i valori (es. ditta corrente). // @xref { int err=NOERR; FILE* fl = fopen(from, "r"); if (fl == NULL) { error_box("Impossibile aprire il file %s",from); return err = 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", prefix().get_codditta()); year.format("%04d", d.year()); ditte.zero(); ditte.put("CODDITTA", firm); if (ditte.read() == NOERR) attprev = ditte.get("CODATTPREV"); } if (fl == NULL) { // Come fa' ad arrivare qui, se fl non puo' essere 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); TFilename filename; TIsam_handle isam_handle = prefix().open_isamfile(_logicnum, filename); int fhnd = handle(isam_handle); if (fhnd < 0) { error_box("Impossibile aprire il file %s", (const char*)filename); return _isnotopen; } TScanner f(from); TToken_string s(1024, fs); bool fixedlen = (fs == '\0'); 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 %s\n%6ld records %6ld errori - %3d", (const char*)filename, 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 %s\n%6ld records %6ld errori - %3d", (const char*)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); } } 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 %s\n%6ld records %6ld errori - %3d", (const char*)filename, r, e, last); p.set_text(s1); prefix().close_isamfile(isam_handle); 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 ). 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 ) 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 { 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); } 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; 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); 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) { _logicnum = logicnum; _length = prefix().get_reclen(logicnum); _rec = new char [_length]; *_tab = '\0'; if (_length > 0) { zero(); if (rec_has_memo(rec_des())) init_memo(RECORD_NON_FISICO); } else setempty(TRUE); } TRectype::TRectype(const TBaseisamfile* i) : _cod(NULL), _memo_data(NULL), _memo_dirty(NULL) { _logicnum = i->num(); _length = prefix().get_reclen(_logicnum); _rec = new char [_length]; *_tab = '\0'; if (_length > 0) { zero(); if (rec_has_memo(rec_des())) init_memo(RECORD_NON_FISICO); } else setempty(TRUE); } TRectype::TRectype(const TRectype& r) : _logicnum(r._logicnum), _cod(NULL), _memo_data(NULL), _memo_dirty(NULL) { 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(int fhnd, const TRecnotype recno) { memo_recno(recno); CHECK( _memo_recno > 0, "Maiale! Non fare le GO con _recno < 0 " ); DB_go( fhnd, _memo_recno ); RecDes *r = rec_des( ); for( int i = _memo_data->last( ); i > 0; i = _memo_data->pred( i ) ) DB_memowrite( fhnd, r->Fd[ i ].Name, ( char * )( const char * )_memo_data->row( i ) ); *this = (const char *) DB_getrecord(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 : // // @flag 0 | Se le due chiavi sono uguali // @flag 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 { 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; } 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 { const RecDes* recd = rec_des(); int p; 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 ) { TFilename fname; int lnum = num(); TIsam_handle isam_handle = prefix().open_isamfile(lnum, fname); TCodeb_handle cb_handle = prefix().get_handle(isam_handle); CHECKD(cb_handle >= 0, "Can't read memo from file ", lnum); DB_go(cb_handle, _memo_recno ); _memo_data->add( DB_memoptr(cb_handle, fieldname ), index ); prefix().close_isamfile(isam_handle); } 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); 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); 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 RecDes* recd = rec_des(); const int nf = findfld(recd, fieldname); if (nf == FIELDERR) unknown_field(fieldname); const TFieldtypes ft = (TFieldtypes)recd->Fd[nf].TypeF; 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(ft == _memofld) { _memo_dirty->set(nf); _memo_data->add(val, nf); } else { __putfieldbuff(recd->Fd[nf].Len, recd->Fd[nf].Dec, ft, 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 50% 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._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; } /////////////////////////////////////////////////////////// // 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; }