#define __ISAM_CPP #define _CRT_SECURE_NO_WARNINGS 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #include #include #endif #include #include #include #include #include #define RECLOCKTYPES 0xFF00 #define READTYPES 0x00FF #define INVFLD 255 bool __field_changed = FALSE; #define NOALLOC (char **) -1 HIDDEN bool __autoload = TRUE; // @doc INTERNAL //////////////////////////////////////////////////////////////////////////////////////////////////// // Funzioni C //////////////////////////////////////////////////////////////////////////////////////////////////// int hashfun(const char *s) { int l = strlen(s); unsigned short temp = 0, *pw = (unsigned short *) s; const unsigned short * end = (unsigned short *) (s + (l - 1)); while ((char *) pw < (char *) end) { temp ^= *pw; pw++; } if (l & 1) temp ^= (unsigned short ) (8192 + s[l - 1]); l = (short) (temp % (MaxFields - 3)); CHECKS(l >= 0, "Negative remainder on ", s); return(l); } int findfld(const RecDes *recd, const char *s) { short stp = hashfun(s); for (byte i = 0 ; i < MaxFields; i++) { if (stp + i >= MaxFields) stp -= MaxFields; byte p = stp + i; const int fp = recd->SortFd[p]; if (fp == INVFLD) return(FIELDERR); const int cmp = strcmp(recd->Fd[fp].Name, s); if (cmp == 0) return (int) fp; else if (cmp > 0) return(FIELDERR); } return(FIELDERR); } void __getfieldbuff(byte l, byte t, const char * recin, TString& s) { CHECK(recin, "Can't read from a Null record"); if (t != _alfafld && t != _datefld) { if (t == _intzerofld || t == _longzerofld) { byte i = 0; for (char* c = (char*)recin; *c == ' ' && i < l; c++, i++) *c = '0'; if (i == l) l = 0; } else { while ((*recin == ' ') && (l)) { recin++; l--; } if ((t != _realfld) && (t != _charfld)) { while ((*recin == '0') && (l)) { recin++; l--; } } } } if (l) { while(l > 0 && recin[l - 1] == ' ') l--; if (l) s.strncpy(recin, l); } s.cut(l); if (l) { if (t == _datefld) { const TDate dt(s); s = dt.string(full); } else { if (t == _boolfld) { const char ok = toupper(*s); if (ok == 'T' || ok == 'Y' || ok == 'S' || ok == 'X') s = "X"; else s.spaces(1); } } } } void __putfieldbuff(byte l, byte d, byte t, const char* s, char* recout) { CHECK(recout, "Can't write null record" ); TString80 s2; if (t == _datefld) { if (s && *s && strlen(s) != 8) { const TDate dt(s); s2 << dt.date2ansi(); s = s2.get_buffer(); } } else if (t == _boolfld) { s2 = (*s && strchr("1STXY", toupper(*s)) != NULL) ? "T" : "F"; s = s2.get_buffer(); } else if (t == _realfld) { real r(s); s2 = r.string(l, d); s = s2.get_buffer(); } int len = strlen(s); const bool exceeded = len > l; if ((t == _intfld) || (t == _longfld) || (t == _wordfld) || (t == _realfld) || (t == _intzerofld) || (t == _longzerofld) ) { if (len == 0 || exceeded) { s2 = "0"; s = s2.get_buffer(); len = 1; } __field_changed = FALSE; const char c = (t == _intzerofld || t == _longzerofld) ? '0' : ' '; for (int i = l - len - 1; i >= 0; i--) { __field_changed |= (recout[i] != c); recout[i] = c; } if (!__field_changed) { __field_changed = memcmp(s, recout, l) != 0; if (!__field_changed) return; } strncpy(&recout[l-len], s, len) ; } else { if (exceeded) len = l; /* // Il codice seguente e' completamente errato in quanto tutti i prefissi ingannano il test! // La stringa vuota e' prefisso di qualsiasi stringa // per cui l'azzeramento di un campo risulta sempre impossibile! __field_changed = memcmp(s, recout, len) != 0; if (!__field_changed) return; */ __field_changed = TRUE; // Per ora e' meglio cosi' strncpy(recout, s, len) ; for (int i = l - 1; i >= len; i--) recout[i] = ' '; } } struct TCallbackFileinfo { TString16 _var; TFilename _app; }; HIDDEN int find_relapp(TConfig& cfg, void* jolly) { TCallbackFileinfo& info = *((TCallbackFileinfo*)jolly); if (cfg.exist(info._var)) { info._app = cfg.get(info._var); return info._app.not_empty(); } return FALSE; } bool get_relapp(int logicnum, TString& app) { TConfig ini(CONFIG_GENERAL); TCallbackFileinfo fi; fi._var.format("Edit_%d", logicnum); ini.for_each_paragraph(find_relapp, &fi); if (fi._app.not_empty()) app = fi._app; return app.not_empty(); } struct TCallbackTableinfo { TString16 _var1, _var2, _var3; TString4 _module; TFilename _tabapp, _relapp; }; HIDDEN int find_tabapp(TConfig& cfg, void* jolly) { TCallbackTableinfo& info = *((TCallbackTableinfo*)jolly); if (cfg.exist(info._var1)) { info._tabapp = cfg.get(info._var1); if (info._tabapp.not_empty()) return 1; } if (cfg.get_paragraph().compare(info._module, 2, TRUE) == 0) { if (cfg.exist(info._var2)) { info._relapp = cfg.get(info._var2); if (info._relapp.not_empty()) return 2; } if (info._var3.full() && cfg.exist(info._var3)) { info._relapp = cfg.get(info._var3); if (info._relapp.not_empty()) return 3; } } return 0; } bool get_tabapp(const char* tabname, TString& app) { TConfig ini(CONFIG_GENERAL, "Main"); TCallbackTableinfo fi; TTable t(tabname); fi._var1.format("Edit_%s", t.name()); fi._var2.format("Edit_%d", t.num()); fi._var3.format("Edit_%d", t.num() == LF_TABCOM ? LF_TAB : LF_TABCOM); fi._module = t.module(); ini.for_each_paragraph(find_tabapp, &fi); app = fi._tabapp; if (app.empty()) app = fi._relapp; if (app.empty()) { app = "ba3 -0"; if (!fi._module.starts_with("ba")) // Compatibility mode :-( { const TString& tp = ini_get_string(CONFIG_STUDIO, fi._module, "TabPrg"); if (tp.full()) app = tp; } } app << ' ' << tabname; return tabname && *tabname > ' '; } //////////////////////////////////////////////////////////////////////////////////////////////////// // Funzioni implementate per la gestione file dati tramite Codebase //////////////////////////////////////////////////////////////////////////////////////////////////// // Inizio(@) // @doc INTERNAL // @func Ritorna una Token_string con in nome dell'indice int get_table_names( int logicnum, // @parm Numero logico del file di cui riconoscere l'indice TToken_string& i_names, // @parm Token_string in cui inserire il nome dell'indice int mode) // @comm Ritorna il nome con il prefisso corrente { TFilename f = prefix().get_filename(logicnum); i_names.cut(0); if (mode & 1) i_names = f; if (mode & 2) { f.ext("cdx"); i_names.add(f); } if (mode & 4) { f.ext("fpt"); if (f.exist()) i_names.add(f); } return i_names.items(); } // Converte un errore di codebase in un errore isam #ifdef DBG HIDDEN int cb_error = NOERR; #endif int get_error(int err) { // Codici negativi HIDDEN int error_codes_g[] = {-1,_isnotopen,-1,-1,-1,_islocked,-1,-1,-1,-1,-1,-1,_isfilefull, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,_iskeynotfound,_ispatherr,-1,-1,_isdupkey}; // Codici da 0 a 9 HIDDEN int error_codes_ra[] = {NOERR,NOERR,_iskeynotfound,_iseof,_isbof,_isnrecerr} ; // Codici da 10 a ... HIDDEN int error_codes_rb[] = {-1,-1,_isreinsert,-1,-1,_islocked,-1,_isalropen,_iskeyerr } ; int isamerr = NOERR; #ifdef DBG if (err <= 200 || err >= 230) cb_error = err; #endif if (err > 0) { if (err >= 10) { if (err > 80 || error_codes_rb[err/10]==-1) isamerr = err; else isamerr = error_codes_rb[err/10]; } else isamerr = error_codes_ra[err]; } else if (err < 0) { if (err == -1) { #ifdef DBG int ierr = DB_get_error(); #endif isamerr = _isnotopen; } else { int ierr = DB_get_error(); if (ierr == 0) ierr = -err; // DB_get_error already called if (ierr < 0) ierr = -ierr; if (ierr > 340 || error_codes_g[ierr/10]==-1) isamerr = -ierr; else isamerr = error_codes_g[ierr/10]; } } DB_zero_error(); return isamerr; } // Used also by varrec bool rec_has_memo(const RecDes& rd) { for( int i = rd.NFields - 1; i >= 0; i--) if (rd.Fd[i].TypeF == _memofld) return true; return false; } HIDDEN bool lf_has_memo(int lffile) { return rec_has_memo(prefix().get_recdes(lffile)); } HIDDEN void browse_null(char *start, int nc) { for (int i = nc - 1; i >= 0 ; i--) // Anche il primo byte(deletion flag) deve essere cambiato. nc comprende il primo byte if (start[i] == '\0') start[i] = ' '; } // Traduce l'espressione chiave di CodeBase HIDDEN int __build_key(const RecDes& recd, int numkey, const RecType recin, char *key, bool build_x_cb) /* *recd; descrittore record */ /* numkey; numero chiave */ /* recin; buffer contenente il record */ /* *key; valore della chiave */ /* build_x_cb flag di costruzione per codebase */ { CHECKD(numkey > 0, "Can't build key ", numkey); const char null_char = -1; key[0] = '\0'; if (numkey-- <= recd.NKeys) { int l = 0; for (int i = 0; i < recd.Ky[numkey].NkFields; i++) { const KeyDes& kd = recd.Ky[numkey]; const bool upp = kd.FieldSeq[i] > MaxFields; const int nf = upp ? kd.FieldSeq[i] - MaxFields : kd.FieldSeq[i]; const RecFieldDes& rf = recd.Fd[nf]; const TFieldtypes f = (TFieldtypes) rf.TypeF; int off, len; if (kd.FromCh[i] == 255) { off = rf.RecOff; len = rf.Len; } else { off = rf.RecOff + kd.FromCh[i]; len = kd.ToCh[i] - kd.FromCh[i] + 1; } if ((l + len) > 255) { key[0] = '\0'; return(_iskeylenerr); } if (f == _boolfld) { const bool on = *(recin + off) > ' ' && strchr("STXY", *(recin + off)) != NULL; key[l] = on ? 'T' : 'F'; } else strncpy((key + l), (recin + off), len); if (recin[off] == '\0') { memset(key + l, ' ', len); if ((f == _intfld) || (f == _longfld) || (f == _wordfld) || (f == _intzerofld) || (f == _longzerofld)) key[l + len - 1] = build_x_cb ? '0' : null_char; } else if ((f == _intfld) || (f == _longfld) || (f == _wordfld) || (f == _intzerofld) || (f == _longzerofld)) { int w = l, j = l + len; while (w < j && key[w] == ' ') w++; while (w < j && key[w] == '0') key[w++] = ' '; if (w == j) key[w-1] = build_x_cb ? '0' : null_char; } if (upp) for (int i = l+len-1; i >= l; i--) key[i] = toupper(key[i]); l += len; } // rtrim if (build_x_cb) { for (l--; l>=0 && key[l] == ' '; l--); key[l + 1] = '\0'; } else { for (l--; l>=0 && (key[l] == ' ' || key[l] == null_char); l--); key[l + 1] = '\0'; for (;l >= 0; l--) if (key[l] == null_char) key[l] = '0'; } return(NOERR); } return(_ispatherr); } HIDDEN int cisread(int fhnd, int knum, TRectype& record, int mode, TRecnotype& curr_recno) { CHECKD(fhnd >= 0, "Can't use codebase handle ", fhnd); const int rmode = (mode & READTYPES); const int lmode = (mode & RECLOCKTYPES); // Non usare mai _isnextn o _isprevn, usare il metodo skip! CHECK (rmode !=_isnextn && rmode !=_isprevn, "_isnextn and _isprevn not supported in cisread"); TString256 keystr; char* key = keystr.get_buffer(); int err = NOERR; do { if (rmode>=_isequal && rmode<=_isgteq) { const RecDes& r = record.rec_des(); err=__build_key(r, knum, record.string(),key,TRUE); if (err == NOERR) { err = DB_seek(fhnd,key); if (err == NOERR && rmode == _isgreat) err = DB_next(fhnd); if (err != NOERR) err = get_error(err); } if (rmode != _isequal && err == _iskeynotfound) err = NOERR; } else { if (rmode==_isfirst) err=DB_first(fhnd); else if (rmode==_islast) err=DB_last(fhnd); else if (rmode==_isnext) { if (curr_recno != DB_recno(fhnd)) { const RecDes& r = record.rec_des(); err = __build_key(r, knum, record.string(),key,TRUE); if (err == NOERR) { err = DB_seek(fhnd,key); err = get_error(err); if (err != NOERR && err != _iskeynotfound && err != _iseof) fatal_box("Errore nella next %d : non posso riposizionarmi", err); else if (err == NOERR) err=DB_next(fhnd); } } else err=DB_next(fhnd); } else if (rmode==_isprev) { if (curr_recno != DB_recno(fhnd)) { const RecDes& r = record.rec_des(); err = __build_key(r, knum, record.string(),key,TRUE); if (err == NOERR) { err = DB_seek(fhnd,key); err = get_error(err); if (err != NOERR && err != _iskeynotfound && err != _iseof) fatal_box("Errore nella prev %d : non posso riposizionarmi", err); else if (err == NOERR) err=DB_prev(fhnd); } } else err=DB_prev(fhnd); } else if (rmode==_iscurr) err=DB_go(fhnd,DB_recno(fhnd)); if (err != NOERR) err=get_error(err); } if (err == _iseof) DB_last(fhnd); if (err == NOERR && (lmode == _lock || lmode == _testandlock)) // _lock e _testandlock { err=DB_lock(fhnd); if (err != NOERR) err = get_error(err); if (err == _islocked && lmode == _testandlock) break; } if (err == _islocked) { const RecDes& r = record.rec_des(); record = (const char*)DB_getrecord(fhnd); __build_key(r, knum, record.string(), key, TRUE); message_box("Codice %s in uso da parte\ndi un altro utente.", key); if (lmode != _lock) break; } } while (err ==_islocked); if (err == NOERR && lmode == _unlock) { err=DB_unlock(fhnd); if (err != NOERR) err = get_error(err); } curr_recno = DB_recno(fhnd); record = (const char *)DB_getrecord(fhnd); return err; } //////////////////////////////////////////////////////////////////////////////////////////////////// // Funzioni implementate per la gestione file dati tramite Codebase //////////////////////////////////////////////////////////////////////////////////////////////////// // Fine(@) // @doc EXTERNAL // @func Setta il valore della variabile

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; } /////////////////////////////////////////////////////////// // 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

// % si riferisce ai dati comuni // $ si riferisce ai dati di ditta corrente // # si riferisce al direttorio indicato da PATHPREF.INI { if (descname && *descname) { TTrec r; ifstream f(descname); f >> r; const int err=DB_build(name, &r.rec()) ; if (err != NOERR) fatal_box("Non posso creare il file %s : errore n.ro %d", name, err); } _lasterr = NOERR; TFilename filename(name); CHECK(filename.full(),"Must define the file to open!"); _logicnum = prefix().get_handle(filename); _current = new TRectype(this); } TBaseisamfile::~TBaseisamfile() { if (_current) delete _current; } TCodeb_handle TBaseisamfile::handle(int key) const { return prefix().get_handle(_isam_handle, key > 0 ? key : _curr_key); } TRecnotype TBaseisamfile::items() const { return DB_reccount(handle()); } const char* TBaseisamfile::name() const { TString& tmp = get_tmp_string(); tmp.format("%d", num()); return tmp; } const char* TBaseisamfile::module() const { TFilename app; curr().get_relapp(app); if (app.full()) return app.left(2); return "ba"; } const char* TBaseisamfile::filename() const { const int n = _isam_handle > 0 ? _isam_handle : num(); TString& tmp = get_tmp_string(); tmp = prefix().get_filename(n); tmp << ".dbf"; return tmp; } const char* TBaseisamfile::description() { const int n = _isam_handle > 0 ? _isam_handle : num(); const FileDes& d = prefix().get_filedes(n); return d.Des; } TRecnotype TBaseisamfile::eod() const { return items(); } void TBaseisamfile::set_curr(TRectype * curr) { CHECK(curr != NULL, "You must set a valid current record"); CHECK(num() == curr->num(), "You must set a coherent current record"); if (_current != NULL) delete _current; _current = curr; } void TBaseisamfile::setkey(int nkey) { _curr_key = nkey; } int TBaseisamfile::getkey() const { return _curr_key; } int TBaseisamfile::first(word lockop) { return TBaseisamfile::read(curr(), _isfirst, lockop); } int TBaseisamfile::last(word lockop) { return TBaseisamfile::read(curr(), _islast, lockop); } int TBaseisamfile::next(word lockop) { return TBaseisamfile::read(curr(), _isnext, lockop); } int TBaseisamfile::prev(word lockop) { return TBaseisamfile::read(curr(), _isprev, lockop); } int TBaseisamfile::reread(word lockop) { return TBaseisamfile::reread(curr(), lockop); } int TBaseisamfile::reread(TRectype& rec, word lockop) { return rec.read(*this, _iscurr, lockop); } int TBaseisamfile::skip(TRecnotype nrec, word lockop) { if (nrec == 0) return NOERR; curr().setdirty(); const int fhnd = handle(); // controllo se mi sono spostato dall'ultima lettura if (_recno != DB_recno(fhnd)) { _lasterr = DB_go(fhnd, _recno); if (_lasterr != NOERR) { _lasterr = get_error(_lasterr); if (_lasterr != _islocked) fatal_box("Errore nella skip %d : non posso riposizionarmi", _lasterr); } } _lasterr=DB_skip(fhnd, nrec); if (_lasterr != NOERR) _lasterr = get_error(_lasterr); while (_lasterr ==_islocked) { const RecDes& r = prefix().get_recdes(num()); TString256 key; __build_key(r, _curr_key, curr().string(), key.get_buffer(), TRUE); message_box("Codice %s in uso da parte\ndi un altro utente.\nSkipping", (const char*)key); _lasterr = cisread(fhnd, getkey(), curr(),_iscurr + lockop, _recno); } _recno = DB_recno(fhnd); if (curr().has_memo()) curr().init_memo(_recno, _isam_handle); return _lasterr; } // funzione di lettura dei file int TBaseisamfile::_read(TRectype& rec, word op, word lockop) { const TCodeb_handle fhnd = handle(); rec.setdirty(); _lasterr = cisread(fhnd, getkey(), rec, op + lockop, _recno); // _recno = DB_recno(fhnd); // Gia' fatto nella cisread if(rec.has_memo()) rec.init_memo(_recno, _isam_handle); if (_lasterr == NOERR) { if (lockop == _lock || lockop == _testandlock) prefix().lock_record(_isam_handle, _recno); else if (lockop == _unlock) prefix().unlock_record(_isam_handle, _recno); } return _lasterr; } int TBaseisamfile::read(TRectype& rec, word op, word lockop) { _lasterr=rec.read(*this, op, lockop); return _lasterr; } int TBaseisamfile::read(word op, word lockop) { return TBaseisamfile::read(curr(), op, lockop); } int TBaseisamfile::readat(TRectype& rec, TRecnotype nrec, word lockop) { return rec.readat(*this, nrec, lockop); } int TBaseisamfile::readat(TRecnotype nrec, word lockop) { return TBaseisamfile::readat(curr(), nrec, lockop); } int TBaseisamfile::_readat(TRectype& rec, TRecnotype nrec, word lockop) { const int fhnd = handle(); rec.setdirty(); _lasterr = DB_go(fhnd, nrec); if (_lasterr != NOERR) _lasterr = get_error(_lasterr); else rec = (const char*)DB_getrecord(fhnd); _recno = DB_recno(fhnd); if (rec.has_memo()) rec.init_memo(_recno, _isam_handle); return _lasterr; } int TBaseisamfile::_write(const TRectype& rec) { CHECK(!rec.empty(), "Can't write an empty record"); // Controlla che la chiave sia piena TString256 key; __build_key(rec.rec_des(), 1, rec.string(), key.get_buffer(), true); if (key.blank()) return _iskeyerr; if (dongle().demo() && items() > 979L) return _isfilefull; // Forza l'uso della chiave principale (per chiavi duplicate?) const int fhnd = handle(_curr_key > 0 ? 1 : 0); const int dst_len = DB_reclen(fhnd); if (dst_len != rec.len()) NFCHECK("Record size mismatch on file %d: RecDes=%d, DB_reclen=%d", _logicnum, rec.len(), dst_len); browse_null(rec.string(), dst_len); memcpy(DB_getrecord(fhnd), rec.string(), dst_len); _lasterr = DB_add(fhnd); _recno = DB_recno(fhnd); if (_lasterr == NOERR) { if (rec.has_memo()) ((TRectype&)rec).write_memo(_isam_handle, _recno ); } else _lasterr = get_error(_lasterr); return _lasterr; } int TBaseisamfile::write(const TRectype& rec) { return rec.write(*this); } int TBaseisamfile::write() { return TBaseisamfile::write(curr()); } int TBaseisamfile::write_rewrite(const TRectype& rec) { return rec.write_rewrite(*this); } int TBaseisamfile::write_rewrite() { return TBaseisamfile::write_rewrite(curr()); } int TBaseisamfile::rewrite_write(const TRectype& rec) { return rec.rewrite_write(*this); } int TBaseisamfile::rewrite_write() { return TBaseisamfile::rewrite_write(curr()); } int TBaseisamfile::_rewrite(const TRectype& rec) { CHECK(!rec.empty(), "Can't write an empty record"); TRectype save_rec(rec); // Forza l'uso della chiave principale (per chiavi duplicate?) const int fhnd = handle(1); _lasterr = cisread(fhnd, 1, save_rec, _isequal + _nolock, _recno); // Si Posiziona per sicurezza... if (_lasterr == NOERR) { const int len = DB_reclen(fhnd); if (len != save_rec.len()) NFCHECK("Record size mismatch on file %d: RecDes=%d, DB_reclen=%d", _logicnum, save_rec.len(), len); browse_null(rec.string(), len); if (memcmp(rec.string(), save_rec.string(), len) != 0) { memcpy(DB_getrecord(fhnd), rec.string(), len); _lasterr = DB_rewrite(fhnd); if (_lasterr == NOERR) rec_cache(_logicnum).notify_change(); else _lasterr = get_error(_lasterr); } else DB_unlock(fhnd); // non vale la pena farlo sempre ? _recno = DB_recno(fhnd); prefix().unlock_record(_isam_handle, _recno); if (_lasterr == NOERR) { if (curr().has_memo()) ((TRectype&)rec).write_memo(_isam_handle, _recno); } } return _lasterr; } int TBaseisamfile::rewrite(const TRectype& rec) { return rec.rewrite(*this); } int TBaseisamfile::rewrite() { return TBaseisamfile::rewrite(curr()); } int TBaseisamfile::rewriteat(const TRectype& rec, TRecnotype nrec) { const int fhnd = handle(); if ((_lasterr=DB_go(fhnd,nrec))== NOERR) { browse_null(rec.string(),DB_reclen(fhnd)); memcpy(DB_getrecord(fhnd),rec.string(),DB_reclen(fhnd)); _lasterr=DB_rewrite(fhnd); if (_lasterr != NOERR) _lasterr = get_error(_lasterr); } else _lasterr = get_error(_lasterr); _recno = DB_recno(fhnd); if(_lasterr == NOERR) { if (curr().has_memo()) ((TRectype &)rec).write_memo(_isam_handle, _recno); rec_cache(_logicnum).notify_change(); } return _lasterr; } int TBaseisamfile::rewriteat(TRecnotype nrec) { return TBaseisamfile::rewriteat(curr(),nrec); } int TBaseisamfile::_remove(const TRectype& rec) { CHECK(!rec.empty(), "Can't remove an empty record"); const int fhnd = handle(1); // Forza l'uso della chiave principale (per chiavi duplicate?) TRectype save_rec(rec); _lasterr = cisread(fhnd, 1, save_rec, _isequal + _nolock, _recno); // Si Posiziona per sicurezza... if (_lasterr == NOERR) { _lasterr = DB_delete(fhnd); // Put only deletion flag on record, must remove keys too! if (_lasterr == NOERR) { if (curr().has_memo( )) curr().init_memo(); rec_cache(_logicnum).notify_change(); DB_flush(fhnd); } else _lasterr = get_error(_lasterr); } if (_lasterr != NOERR) DB_recall(fhnd); return _lasterr; } int TBaseisamfile::remove(const TRectype& rec) { return rec.remove(*this); } int TBaseisamfile::remove() { return TBaseisamfile::remove(curr()); } int TBaseisamfile::lock() { const int fhnd = handle(); _lasterr = DB_lockfile(fhnd); if (_lasterr != NOERR) _lasterr = get_error(_lasterr); return _lasterr; } int TBaseisamfile::unlock() { const int fhnd = handle(); _lasterr = DB_unlock(fhnd); if (_lasterr != NOERR) _lasterr = get_error(_lasterr); return (_lasterr); } void TBaseisamfile::indexon() { } void TBaseisamfile::indexoff() { } bool TBaseisamfile::empty() { return items() <= 0; } // @doc EXTERNAL // @mfunc Apre il file isam di base con lock // // @rdesc Ritorna NOERR se e' riuscita ad aprire il file, altrimenti ritorna il numero di errore // generato (vedi ). 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) { TCodeb_handle cb_handle = prefix().get_handle(_isam_handle, _curr_key); const int dbfreclen = DB_reclen(cb_handle); const int trcreclen = prefix().get_reclen(_logicnum); const TRecnotype n = DB_reccount(cb_handle); if (dbfreclen != trcreclen) { TString msg; msg.format("Lunghezza record incoerente sul file %d (%s): file=%d trc=%d", num(), (const char*)filename, dbfreclen, trcreclen); if (n <= 0) { msg << "\nSi consiglia di eliminare il file ed i suoi indici."; error_box(msg); } else fatal_box(msg); } if (prefix().get_recdes(_logicnum).NKeys <= 0) fatal_box("Il file %d (%s) e' senza indici", num(), (const char*)filename); _recno = RECORD_NON_FISICO; setkey(_curr_key); _lasterr = NOERR; } else { TString e_msg; _lasterr = get_error(_isam_handle); if (_lasterr == -60) { if (!filename.exist()) e_msg.format("Il file %d(%s) non esiste, errore %d",num(),(const char*)filename,_lasterr); else e_msg.format("Il file %d(%s) e' aperto in modo esclusivo da un'altra applicazione", num(), (const char*)filename); } if (e_msg.empty()) e_msg.format("Il file %d(%s) non puo' essere aperto, errore %d",num(),(const char*)filename,_lasterr); fatal_box((const char*) e_msg); } return _lasterr; } int TBaseisamfile::_open_ex( unsigned int mode, // @parm Indica il modo di apertura del file (default _manulock) bool index) // @parm Indica se aprire con indici o meno (default TRUE) // @comm Il parametro

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 { _lasterr = get_error(_isam_handle); _isam_handle = 0; } return _lasterr; } int TBaseisamfile::_close() { int err = NOERR; if (prefix_valid()) { err = prefix().close_isamfile(_isam_handle); setstatus(err); } return err; } int TBaseisamfile::is_valid(bool exclusive) { // Ritorna NOERR se il file puo' essere aperto senza errori CHECKD(_isam_handle == 0, "Can't reopen file ", _logicnum); TFilename filename; TIsam_handle isam_handle = prefix().open_isamfile(_logicnum, filename, exclusive, true); TCodeb_handle fhnd = isam_handle > 0 ? prefix().get_handle(isam_handle,1) : isam_handle; int err = NOERR; if (fhnd < 0) err = get_error(fhnd); else { const int trcreclen = prefix().get_reclen(_logicnum); if (trcreclen > 0) { if (DB_tagget(fhnd) == -1) err = _ispatherr; else { const int dbfreclen = DB_reclen(fhnd); if (dbfreclen != trcreclen) { err = _istrcerr; if (_logicnum == LF_CLIFO) error_box("Clifo trc=%d dbf=%d", trcreclen, dbfreclen); } } } else err = _isbadtrc; } if (isam_handle > 0) prefix().close_isamfile(isam_handle); return err; } bool TBaseisamfile::get_relapp(TString& app) const { return curr().get_relapp(app); } bool TBaseisamfile::is_changed_since(long& last) const { bool yes = false; #ifdef WIN32 int fh = 0; ::_sopen_s(&fh, filename(), _O_RDONLY, _SH_DENYNO, _S_IREAD); if (fh > 0) { struct stat stat; if (::fstat(fh, &stat) == 0) { const long tim = long(stat.st_mtime) ^ long(stat.st_size); yes = tim != last; last = tim; } ::_close(fh); } #else struct stat stat; if (lstat(filename(), &stat) == 0) { const long tim = long(stat.st_mtime) ^ long(stat.st_size); yes = tim != last; last = tim; } #endif return yes; } /////////////////////////////////////////////////////////// // TLocalisamfile /////////////////////////////////////////////////////////// // @doc EXTERNAL // @mfunc Costruttore // // @rdesc Ritorna l'oggetto 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 const char* descname) // @parm Indica la descrizione del file : TBaseisamfile(name, descname) { } TLocalisamfile::TLocalisamfile(int logicnum, bool tmpfile) : TBaseisamfile(logicnum) { CHECK(tmpfile == TRUE, "Protected constructor badly used"); } TLocalisamfile::~TLocalisamfile() { close(); } int TLocalisamfile::close() { return TBaseisamfile::_close(); } int TLocalisamfile::open(unsigned int mode) { return TBaseisamfile::_open(mode); } int TLocalisamfile::operator +=(const TRecnotype npos) { skip(npos); return status(); } int TLocalisamfile::operator -=(const TRecnotype npos) { skip(-npos); return status(); } int TLocalisamfile::operator ++() { next(); return status(); } int TLocalisamfile::operator --() { prev(); return status(); } TIsamfile::TIsamfile(int logicnum) : TBaseisamfile(logicnum) { } TIsamfile::~TIsamfile() { close(); } /////////////////////////////////////////////////////////// // TIsamtempfile /////////////////////////////////////////////////////////// TIsamtempfile::TIsamtempfile(int logicnum, const char* radix, bool create, bool autodel) : TLocalisamfile(logicnum, TRUE) { TRecnotype eod = 0; TRecnotype eox = 100; TFilename n; if (radix && *radix) { if (*radix == '%') n = radix + 1; else { n.tempdir(); n.add(radix); } n.ext("dbf"); } else n.temp(NULL, "dbf"); if (!create) { const long sz = fsize(n); if (sz <= 64) fatal_box("Impossibile aprire il file %s", (const char*)n); const long len = curr().len(); eod = eox = sz / len; } CHECK(create == FALSE || create == TRUE, "Il flag di autodel ora si setta con il terzo parametro del costruttore"); _autodel = autodel || (create != FALSE && create != TRUE); n.insert("%", 0); open(n, create, eod, eox); } TIsamtempfile::~TIsamtempfile() { close(); } // @doc EXTERNAL // @mfunc Apre il file // // @rdesc Ritorna NOERR se e' riuscita ad aprire il file, altrimenti ritorna il numero di errore // generato (vedi ). 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

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); } } else { TFilename test = filename; test.ext("dbf"); for (int t = 0; t < 2; t++) { test.ext(t == 0 ? "dbf" : "cdx"); if (!test.exist()) { err = -60; break; } } } if (err == NOERR) { _isam_handle = prefix().open_isamfile(_logicnum, filename, true); TCodeb_handle fhnd = handle(_curr_key = 1); if (fhnd < 0) err = get_error(fhnd); } if (err != NOERR) { filename.ext("dbf"); if (err == -60) { if (!filename.exist()) fatal_box("Apertura file %s : errore n. %d. File non esistente.",(const char*)filename,err); else fatal_box("Apertura file %s : errore n. %d. File aperto in uso esclusivo da un'altra applicazione.",(const char*)filename,err); } else fatal_box("Apertura file %s : errore n. %d ",(const char*)filename,err); } _recno = RECORD_NON_FISICO; setstatus(err); return err; } int TIsamtempfile::close() { TFilename f = filename(); int err = prefix().close_isamfile(_isam_handle); if (err == NOERR && _autodel) { const long c = DB_getconf(); f.ext("dbf"); ::remove(f); if (c & 1) f.ext("fpt"); else f.ext("dbt"); ::remove(f); if (c & 1) // FOXPRO format f.ext("cdx"); if (c & 4) // DBIV format f.ext("mdx"); if (c & 8 || c & 2) // CLIPPER and DBIII format { f.ext("cgp"); FILE* fp=NULL; fopen_s(&fp, f, "r"); char in[16]; while (fgets(in,16,fp)!=NULL) { TFilename a(in); if (c & 8) // DBIII format a.ext("ndx"); else a.ext("ntx"); // CLIPPER format ::remove((const char *)a); } fclose(fp); } ::remove(f); if (curr().has_memo()) // Cancella eventuale file dei memo { f.ext("fpt"); ::remove(f); } } setstatus(err); return err; } /////////////////////////////////////////////////////////// // TExternisamfile /////////////////////////////////////////////////////////// TExternisamfile::TExternisamfile(const char* name, bool exclusive, bool index) : TLocalisamfile(name) { init(name, exclusive, index); } TExternisamfile::TExternisamfile(const char* name, const char* descname, bool exclusive, bool index) : TLocalisamfile(name, descname) { init(name, exclusive, index); } TExternisamfile::~TExternisamfile() { close(); } void TExternisamfile::init(const char* name, bool exclusive, bool index) { _name = name; _name.ext("dbf"); // Espande il nome! const char c = _name[0]; if (c == '%' || c == '$') _name = CAddPref(_name.get_buffer()); else if (c == '#') { _name.ltrim(1); _name.format("%s/%s",__ptprf,(const char*)_name); } open(exclusive, index); } int TExternisamfile::open(bool exclusive, bool index) { _isam_handle = prefix().open_isamfile(_logicnum, _name, exclusive, index); if (_isam_handle > 0) { if (prefix().get_recdes(_logicnum).NKeys <= 0) fatal_box("Il file %d (%s) e' senza indici", num(), (const char*)filename()); _recno = RECORD_NON_FISICO; setkey(1); _lasterr = NOERR; } else { TString e_msg; _lasterr = get_error(_isam_handle); if (_lasterr == -60) { if (!_name.exist()) e_msg.format("Il file %d(%s) non esiste, errore %d",num(),(const char*)_name,_lasterr); else e_msg.format("Il file %d(%s) e' aperto in modo esclusivo da un'altra applicazione", num(), (const char*)_name); } if (e_msg.empty()) e_msg.format("Il file %d(%s) non puo' essere aperto, errore %d",num(),(const char*)_name,_lasterr); fatal_box((const char*) e_msg); } return _lasterr; } int TExternisamfile::close() { return _close(); } int TExternisamfile::zap() { RecDes rd = curr().rec_des(); int err = prefix().close_isamfile(_isam_handle); if (err == NOERR) { err = DB_packfile(TRUE, _name, 0); if (err == NOERR) { TRecnotype peod; err = DB_packindex(TRUE, _name, &rd, &peod, FALSE); } _isam_handle = prefix().open_isamfile(_logicnum, _name); } return err; } const char* TExternisamfile::name() const { return filename(); } /////////////////////////////////////////////////////////// // TSystemisamfile /////////////////////////////////////////////////////////// int TSystemisamfile::build(const TTrec& r) { int err = NOERR; const TDir d(num()); if (r.len() > 0) { TFilename f(filename()); TFilename fname(f); fname.ext(""); // sostituto per _filename f = f.path(); if (!is_not_slash(f.right(1)[0])) f.rtrim(1); if (!dexist(f)) make_dir(f); err=DB_build(fname, &r.rec()); if (err != NOERR) err = get_error(err); setstatus(err); if (err == NOERR && __autoload) { TFilename lf; lf.format("%sstd/lf%04d.txt", __ptprf, num()); if (fexist(lf)) load(lf, '|', '\0', '\n', TRUE, TRUE); } } else { NFCHECK("Can't create a file with empty field info"); setstatus(_isbadtrc); } return err; } int TSystemisamfile::build() { TTrec r; r.get(num()); return build(r); } long TSystemisamfile::size(TRecnotype eox) { return 51200L; } #ifndef FOXPRO // @doc INTERNAL // @mfunc Esegue la conversione del file // // @rdesc Ritorna il rusultato dell'operazione // // @flag TRUE | Se la conversione e' stata effettuata correttamente // @flag FALSE | Se h stato rilevato un errore durante la conversione (viene emesso un ) int TSystemisamfile::exec_convapp( long flev, // @parm Livello a cui aggiornare l'archivio const bool before) // @parm Indica se viene chiamata prima o dopo la conversione { const char * const v = before ? "BCNV" : "ACNV"; int err = 0; if (flev == 0) flev = 199401; else flev++; TConfig conv(CONFIG_FCONV); TString16 paragraph; TString_array paralist; conv.list_paragraphs(paralist); for (unsigned int l = flev; err == 0 && l <= prefix().get_stdlevel(); l++) { paragraph.format("%06ld", l); if (paralist.find(paragraph) < 0) continue; if (conv.set_paragraph(paragraph) && conv.exist(v, num())) { TToken_string s(conv.get(v, NULL, num()), ' '); TFilename f(s.get(0)); f.ext(".exe"); s << ' ' << prefix().get_codditta(); TExternal_app app(s); if (f.exist()) { err = app.run(FALSE, 0x3); // Synchronous Spawn with User TMailbox mail; TMessage* msg = mail.next(TRUE); if (err == 0 && msg != NULL) err = atoi(msg->body()); } if (err && err != 8) return error_box("Impossibile eseguire il programma di %sconversione\ndel livello %ld/%ld\nErrore n.ro %d", before ? "pre" : "post", l / 100, l % 100, err); } } return err; } // @doc INTERNAL // @mfunc Recupera le conversioni logiche da effettuare sul file // // @rdesc Ritorna TRUE se occorre effettuare la conversione sul file bool TSystemisamfile::getlcf( long flev) // @parm livello archivi di partenza della convesione // @comm Recupera le conversioni logiche da effettuare sul file per per passare dal // livello archivi

a quello attuale degli archivi standard. { _flds.destroy(); _exps.destroy(); if (flev == 0) flev = 199401; else flev++; TConfig conv(CONFIG_FCONV); TString16 paragraph; TString_array paralist; conv.list_paragraphs(paralist); for (unsigned int l = flev; l <= prefix().get_stdlevel(); l++) { paragraph.format("%06ld", l); if (paralist.find(paragraph) < 0) continue; if (conv.set_paragraph(paragraph) && conv.exist("F", num())) { TToken_string exprline(conv.get("F", NULL, num())); if (exprline.empty()) return FALSE; TToken_string w("", '='); const char * wexprs = exprline.get(); while (wexprs != NULL) { w = wexprs; TFixed_string fld(w.get()); _flds.add(new TFieldref(fld, 0)); _exps.add(new TExpression(w.get(), _strexpr)); wexprs = exprline.get(); } } } return _flds.items() > 0; } void TSystemisamfile::makelc(TRectype& rec) { for (int i = 0 ; i < _flds.items(); i++) { TFieldref& f = (TFieldref&) _flds[i]; TExpression& e = (TExpression & )_exps[i]; for (int k = 0; k < e.numvar(); k++) e.setvar(k, get(e.varname(k))); f.write(e.as_string(), rec); } } // @doc EXTERNAL // @mfunc Esegue la conversione del tracciato record del file // // @rdesc Ritorna il risulato della conversione, altrimenti il codice di errore generato // (vedi ) int TSystemisamfile::update( const TTrec& newrec, // @parm Nuovo tracciato record con cui aggiornare il file bool interactive) // @parm Indica se riportare i campi personalizzati { //if (newrec.len() == 0) if (newrec.len() <= 8) { // if (interactive) error_box(FR("Il nuovo tracciato per il file %d e' vuoto"), num()); // Fastidioso per Ilaria setstatus(_istrcerr); return status(); } int err = NOERR; TTrec wrec(newrec); TDir dir; dir.get(num(), _unlock, _nordir, _sysdirop); const bool is_com = prefix().is_com(); const bool toconvert = is_com ? dir.is_com() : dir.is_firm(); TTrec oldrec(num(), is_com ? _comdir : _nordir); if (oldrec.fields() < 0 || oldrec.fields() > MaxFields) { if (yesno_box(FR("Il file %d (%s)\n" "ha %d campi ed una lunghezza record di %d" "\nSi desidera azzerare il vecchio tracciato?"), num(), (const char*)filename(), oldrec.fields(), oldrec.len())) { oldrec.zero(); } else { setstatus(_istrcerr); return status(); } } int lenr = wrec.len(); if (lenr != 0) { const long lev = prefix().filelevel(); const bool lcf = getlcf(lev); if (toconvert) { err = exec_convapp(lev, true); // Pre-conversion if (err != NOERR) { setstatus(err); return err; } if (!lcf && wrec == oldrec) { err = exec_convapp(lev, false); // Post-conversion (SOLO se il record e' rimasto uguale) setstatus(err); return err; } } else { if (dir.eox() > 0L) dir.reset_eox(); } const int oldfields = oldrec.fields(); //numero campi del vecchio file const int wfields = wrec.fields(); //numero campi del nuovo file int newfields = wfields; //numero campi del nuovo file compresi quelli personalizzati (_) TToken_string def; //riga del file .trr nome|tipo|lungh|dec for (int j = 0; j < oldfields; j++) { def = oldrec.fielddef(j); const TString16 fname = def.get(0); //nome e basta del campo if (!interactive && fname[0] == '_') { if (wrec.field(fname) == FIELDERR) { if (newfields < MaxFields) { wrec.update_fielddef(newfields++, def); wrec.set_fields(newfields); wrec.rehash(); } else { if(!yesno_box("Il campo %s non verrā preservato: continuare?", (const char*)fname)) return NOERR; } } } } if (wfields < newfields) { wrec.set_fields(newfields); wrec.rehash(); lenr = wrec.len(); } TFilename fname; if (toconvert) fname = filename(); if (toconvert && (dir.eox() > 0L || fname.exist())) { TRecnotype ni = 0L; TFilename tmpfname; tmpfname.temp("tf"); err=DB_build(tmpfname, &wrec.rec()); if (err != NOERR) { err=get_error(err); return (err); } if (dir.eod() > 0 && oldrec.len() > 0) { // Apro il file destinazione in modo esclusivo e senza indici //int tmpnum = num(); //TIsam_handle ishandle = prefix().open_isamfile(tmpnum, tmpfname, true, false); // TCodeb_handle fhnd = ishandle > 0 ? prefix().get_handle(ishandle) : ishandle; TCodeb_handle fhnd = DB_open(tmpfname, 1, 0); if (fhnd < 0) { err = get_error(fhnd); return err; } err = _open_ex(_excllock, false); if (err != NOERR) return err; TString s; s << TR("Aggiornamento") << ' ' << fname; const TRecnotype nitems = items(); TProgress_monitor p(nitems, s, is_power_station()); TExtrectype nrec(wrec); const int nflds = curr().items(); TArray infld, outfld; int j; for (j = 0; j < nflds; j++) { const char* fld_name = curr().fieldname(j); infld.add(new TRecfield(curr(), fld_name), j); if (nrec.exist(fld_name)) outfld.add(new TRecfield(nrec, fld_name), j); } const bool memo_inside = rec_has_memo(nrec.rec_des()); for (int errore = first(); errore == NOERR; errore = next()) { if (!p.add_status()) { err = _iseof; // Simula errore in caso di interruzione break; } ni++; if (curr().isdeleted()) continue; // Shold never happen nrec.zero(); for (j = outfld.last(); j >= 0; j = outfld.pred(j)) { TRecfield* in_fld = (TRecfield*)infld.objptr(j); TRecfield* out_fld = (TRecfield*)outfld.objptr(j); if (in_fld != NULL && out_fld != NULL) { char* fld_val = (char*)(const char*)*in_fld; if (out_fld->type() != _datefld && out_fld->type() != _memofld) { const int l1 = out_fld->len(); const int l2 = strlen(fld_val); if (l1 < l2) { if (out_fld->type() != _alfafld) *fld_val = '\0'; else fld_val[l1] = '\0'; } } *out_fld = fld_val; } } if (lcf) makelc((TRectype &)nrec); browse_null(nrec.string(),lenr); memcpy(DB_getrecord(fhnd),nrec.string(),lenr); err=DB_add(fhnd); if ( err == NOERR && memo_inside) { // nrec.write_memo(ishandle, DB_recno(fhnd)); for (j = outfld.last(); j >= 0; j = outfld.pred(j)) { const TRecfield* in_fld = (const TRecfield*)infld.objptr(j); const TRecfield* out_fld = (const TRecfield*)outfld.objptr(j); if (in_fld != NULL && out_fld != NULL && out_fld->type() == _memofld) { const TFixed_string val(*in_fld); if (val.full()) DB_memowrite(fhnd, out_fld->name(), val); } } DB_flush(fhnd); } if (err != NOERR) err=get_error(err); setstatus(err); } close(); //prefix().close_isamfile(ishandle); DB_close(fhnd); if (err != NOERR) err = get_error(err); if (!p.setstatus(nitems)) err = _iseof; } if (err == NOERR) { long c = DB_getconf(); fname.ext("dbf"); tmpfname.ext("dbf"); fcopy(tmpfname, fname); ::remove(tmpfname); if (c & 1) tmpfname.ext("fpt"); else tmpfname.ext("dbt"); if (tmpfname.exist()) { if (c & 1) fname.ext("fpt"); else fname.ext("dbt"); fcopy(tmpfname, fname); ::remove(tmpfname); } if (c & 1) // FOXPRO format tmpfname.ext("cdx"); if (c & 4) // DBIV format tmpfname.ext("mdx"); if (c & 8 || c & 2) { tmpfname.ext("cgp"); TFilename a; FILE *fp=NULL; fopen_s(&fp, tmpfname,"rb"); while (fgets(a.get_buffer(),16,fp) != NULL) { a.rtrim(1); // Cut \n if (c & 8) // DBIII format a.ext("ndx"); else a.ext("ntx"); // CLIPPER format ::remove(a); } fclose(fp); } ::remove(tmpfname); dir.set_eod(ni); } } if (err==NOERR) { dir.set_len(lenr); dir.put(num(), _nordir, _sysdirop); wrec.put(num()); prefix().update_recdes(num()); if (toconvert) packindex(true); if (err == NOERR) err = exec_convapp(lev, FALSE); // Post - conversion } } setstatus(err); return err; } // @doc EXTERNAL // @mfunc Rimuove fisicamente i record cancellati // // @rdesc Ritorna NOERR se l'operazione di compattamento e' riuscita, altrimenti il codice di // di errore generato (vedi ). int TSystemisamfile::packfile( bool vis, // @parm Indica se visualizzare lo stato dell'operazione bool zap) // @parm Indica se distruggere tutti i records // @xref { TFilename fname = filename(); fname.ext(""); TRecnotype new_eod = 0L; if (!zap) { const int lf = num(); TDir d(lf); // Chi commenta muore! d.get(lf,_nolock, d.is_com() ? _comdir : _nordir, _sysdirop); new_eod = d.eod(); if (d.len() <= 1) // Dati rovinati? { d.set_len(curr().len()); d.put(lf, d.is_com() ? _comdir : _nordir, _sysdirop); } } int err = DB_packfile(vis, fname, new_eod); if (zap && err == NOERR) err = packindex(vis, false); if (err == NOERR && curr().has_memo()) err = DB_packmemo(vis,fname); if (err != NOERR) { err = get_error(err); if (err != NOERR) error_box("Errore in compattamento dati.\nFile %d : %d", num(), err); } setstatus(err); return err; } int TSystemisamfile::zap() { safely_close_closeable_isamfiles(); return packfile(true, true); } // @doc EXTERNAL // @mfunc Rimuove fisicamente gli indici cancellati // // @rdesc Ritorna NOERR se l'operazione di compattamento e' riuscita, altrimenti il codice di // di errore generato (vedi ). 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 { const TTrec r(num()); TDir d(num()); const bool is_com = d.is_com(); d.get(num(),_nolock, is_com ? _comdir : _nordir, _sysdirop); TFilename name = d.filename(); name.ext(""); TRecnotype peod; int err=DB_packindex(vis,name,&r.rec(),&peod,ask); if (err != NOERR) err = get_error(err); if (err != NOERR) { if (vis || ask) error_box("Errore in compattamento indici.\nFile %d : %d", num(),err); } else { if (peod >= 0 && peod != d.eod()) { d.set_eod(peod); d.put(num(), is_com ? _comdir : _nordir); } } setstatus(err); return err; } void TSystemisamfile::update_file() { TFilename fname; int logicnum = _logicnum; int isam_handle = prefix().open_isamfile(logicnum, fname, FALSE, 1); if (isam_handle > 0) { TCodeb_handle cb_handle = prefix().get_handle(isam_handle, 1); const TRecnotype n = DB_reccount(cb_handle); //numero di elementi del file TDir dir; dir.get(_logicnum, _lock, _nordir, _sysdirop); dir.set_eox(n); dir.set_eod(n); dir.put(_logicnum, _nordir, _sysdirop); prefix().close_isamfile(isam_handle); } } int TSystemisamfile::pack(bool vis, bool ask) { int err = packfile(vis); if (err == NOERR) err = packindex(vis, ask); setstatus(err); return err; } // @doc EXTERNAL // @mfunc Importa un file ascii // // @rdesc Ritorna NOERR se l'operazione di lettura e' riuscita, altrimenti il codice di // di errore generato (vedi ). 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) bool indexed) // @parm Indica se indicizzare subito o alla fine // @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 = NULL; fopen_s(&fl, from, "r"); if (fl == NULL) { cantread_box(from); setstatus(2); return 2; } TRecnotype r = 0, e = 0, nitems = 0; TString8 firm, year, attprev("00000"); if (extended) { const TDate d(TODAY); year.format("%04d", d.year()); firm.format("%05ld", prefix().get_codditta()); attprev = cache().get(LF_NDITTE, firm, NDT_CODATTPREV); } fseek(fl, 0L, SEEK_END); nitems = ftell(fl); fclose(fl); err = _open_ex(_excllock, indexed); if (err != NOERR) { TString msg; msg << _logicnum << " (" << name() << ')'; cantread_box(msg); return err; } TScanner f(from); const bool fixedlen = (fs == '\0'); TToken_string s(1024, fixedlen ? char(255) : fs); int nflds = curr().items(); TString_array fld(nflds); TPointer_array fldlen(nflds); int reclen = 0; TString sfd(3); TString s1(256); bool lcf = FALSE; if (f.paragraph("Header")) { int equal; TString key; nflds = 0; while ((equal = f.line().find('=')) > 0) { key = f.token().left(equal); key.trim(); if (key == "File") { const int logic = atoi(f.token().mid(equal+1)); if (logic != num()) { error_box("L'archivio %s e' stato generato dal file %d", from, logic); return _isbadtrc; } } else if (key == "Fields") { TToken_string riga(f.token().mid(equal+1)); TToken_string wfd(32, ','); FOR_EACH_TOKEN(riga, fd) { wfd = fd; wfd.strip_spaces(); fld.add(wfd.get(0)); const int l = wfd.get_int(); fldlen.add_long(l, nflds++); reclen += l; } } } } if (nflds == 0 || fld.items() == 0) { nflds = curr().items(); for (int j = 0; j < nflds; j++) { fld.add(curr().fieldname(j), j); const TString& wfld = fld.row(j); const int l = (curr().type(wfld) == _datefld) ? 10 : curr().length(wfld); fldlen.add_long(l, j); } } if (!f.paragraph("Data")) { error_box("Formato file non valido: manca il paragrafo [Data]"); close(); err = 1; setstatus(err); return err; } if (fd) sfd << fd; int last = NOERR; const char* const fmt = FR("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d"); s1.format(fmt, _logicnum, from, r, e, last); TProgind p(nitems, s1); while(!f.eof()) { if (fixedlen) f.getline(s.get_buffer(reclen+2), reclen+2); else s = f.line(); if (s.empty()) break; if (extended) { int p, i; while ((p = s.find("%yr%")) >= 0) for (i = 0; i < 4; i++) s[p + i] = year[i]; while ((p = s.find("%frm%")) >= 0) for (i = 0; i < 5; i++) s[p + i] = firm[i]; while ((p = s.find("%att%")) >= 0) for (i = 0; i < 5; i++) s[p + i] = attprev[i]; } if ((r + e) % 100 == 0) { s1.format(fmt, _logicnum, from, r, e, last); p.set_text(s1); } if (!p.setstatus((long)f.tellg())) break; zero(); if (fixedlen) { if (s.len() < reclen) { error_box(FR("Record di lunghezza errata: %d invece di %d"), s.len(), reclen); break; } int pos = 0; for (int j = 0; j < nflds; j++) { const int l = fldlen.get_int(j); s1 = s.mid(pos, l); s1.rtrim(); put(fld.row(j), s1); pos += l; } } else { s.restart(); for (int j = 0; j < nflds; j++) { s1 = s.get(); if (fd) { s1.rtrim(1); s1.ltrim(1); } if (curr().type((const TString&) fld[j]) == _memofld) { TString s2 = s1; s1 = esc(s2); } put((const TString&) fld[j], s1); } } int err = write(); if (err == NOERR) r++; else { e++; last = status(); } } s1.format(fmt, _logicnum, from, r, e, last); p.set_text(s1); close(); setstatus(err); // Devo reindicizzare alla fine if (err == NOERR && !indexed) packindex(vis, false); //aggiorna lo sheet con i nuovi valori di EOX EOD caricati if (err == NOERR) update_file(); return err; } // @doc EXTERNAL // @mfunc Importa un file ascii // // @rdesc Ritorna NOERR se l'operazione di lettura e' riuscita, altrimenti il codice di // di errore generato (vedi ). int TSystemisamfile::overwrite( 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) // @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 = NULL; fopen_s(&fl, from, "r"); if (fl == NULL) { error_box("Impossibile aprire il file %s",from); clearerr(fl); setstatus(2); return 2; } TRecnotype r = 0, e = 0, nitems = 0; TString16 firm, year, attprev("00000"); fseek(fl, 0L, SEEK_END); nitems = ftell(fl); fclose(fl); err = _open_ex(_excllock); if (err != NOERR) { error_box("Impossibile aprire il file %d in modo esclusivo", _logicnum); return err; } TScanner f(from); bool fixedlen = (fs == '\0'); TToken_string s(1024, fixedlen ? char(255) : fs); int nflds = curr().items(); TString_array fld(nflds); TString_array keyfld(nflds); TAssoc_array vals; int len[MaxFields]; TString sfd(3); TString s1(256); bool lcf = FALSE; if (f.paragraph("Header")) { int equal; TString key; nflds = 0; while ((equal = f.line().find('=')) > 0) { key = f.token().left(equal); key.trim(); if (key == "Version") { const unsigned int level = atoi(f.token().mid(equal+1)); if (level > prefix().filelevel()) { const unsigned int stdlevel = prefix().get_stdlevel(); error_box(FR("L'archivio %s e' stato generato con gli archivi di livello %ld%/%ld.\n Il livello attuale e' %ld/%ld.\n Convertire gli archivi e ripetere l' operazione."), from, level/100, level%100, stdlevel/100, stdlevel%100); } lcf = getlcf(level); } else if (key == "File") { const int logic = atoi(f.token().mid(equal+1)); if (logic != num()) error_box("L'archivio %s e' stato generato dal file %d", from, logic); } else if (key == "Fields") { TToken_string riga(f.token().mid(equal+1)); TToken_string wfd(32, ','); FOR_EACH_TOKEN(riga, fd) { wfd = fd; wfd.strip_spaces(); fld.add(wfd.get(0)); len[nflds++] = wfd.get_int(); } const RecDes& rd = curr().rec_des(); const KeyDes& kd = rd.Ky[0]; for (int i = 0 ; i < kd.NkFields; i++) { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = rd.Fd[nf]; keyfld.add(rf.Name); } } } } if (nflds == 0 || fld.items() == 0) { nflds = curr().items(); for (int j = 0; j < nflds; j++) { fld.add(curr().fieldname(j), j); const TString & wfld = fld.row(j); int l = 0; switch (curr().type(wfld)) { case _datefld: l = 10; break; default : l = curr().length(wfld); break; } len[j] = l; } } if (!f.paragraph("Data")) { error_box("Formato file non valido: manca il paragrafo [Data]"); close(); err = 1; setstatus(err); return err; } if (fd) sfd << fd; int last = NOERR; s1.format("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d", _logicnum, from, r, e, last); TProgind p(nitems, s1, true, true, 78); long pos = 16*nflds; for (s = f.line(); s.not_empty() && !p.iscancelled(); s = f.line()) { if ((r + e) % 50 == 0) { s1.format("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d", _logicnum, from, r, e, last); p.set_text(s1); } pos += s.len()+2; p.setstatus(pos); zero(); vals.destroy(); if (fixedlen) { int pos = 0; for (int j = 0; j < nflds; j++) { const TString & fldname = fld.row(j); s1 = s.mid(pos,len[j]); s1.rtrim(); vals.add(fldname, s1); pos += len[j]; } } else { s.restart(); for (int j = 0; j < nflds; j++) { const TString & fldname = fld.row(j); s1 = s.get(); if (fd) { s1.rtrim(1); s1.ltrim(1); } if (curr().type(fldname) == _memofld) { TString s2 = s1; s1 = esc(s2); } vals.add(fldname, s1); } } FOR_EACH_ARRAY_ROW(keyfld, r0, kfldname) { const TString * value = (const TString *) vals.objptr(*kfldname); if (value != NULL) put(*kfldname, *value); } const bool nuovo = read() != NOERR; if (nuovo) zero(); FOR_EACH_ASSOC_STRING(vals, obj, fldname, value) put(fldname, value); const int err = nuovo ? write() : rewrite(); if (err == NOERR) r++; else { e++; last = status(); } } s1.format("Importazione archivio %d da %s\n%6ld records %6ld errori - %3d", _logicnum, from, r, e, last); p.set_text(s1); close(); setstatus(err); //aggiorna lo sheet con i nuovi valori di EOX EOD caricati if (err == NOERR) update_file(); return err; } // @doc EXTERNAL // @mfunc Esporta VERSO un file ascii. // // @rdesc Ritorna NOERR se l'operazione di esportazione e' riuscita, altrimenti il codice di // di errore generato (vedi ). 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) const char * filter, // @parm Indica l'espressione filtro SELECTIONFUNCTION select_func, // @parm funzione filtro TObject * filter_obj) // @parm oggetto di filtro // @xref { FILE* f = NULL; fopen_s(&f, to, "w"); if (f == NULL) { setstatus(2); return 2; } if (withdeleted) nkey = 0; int err = ferror(f); open(FALSE, nkey ? TRUE : FALSE); TString s(512); bool fixedlen = (fs == '\0'); int nflds = curr().items(); TString_array fld(nflds); TBit_array rjust(nflds); int len[MaxFields]; int j; for (j = 0; j < nflds; j++) { fld.add(curr().fieldname(j), j); const TString & wfld = fld.row(j); const TFieldtypes t = curr().type(wfld); rjust.set(j, t == _intfld || t == _longfld || t == _realfld || t == _wordfld || t == _intzerofld || t == _longzerofld); len[j] = (t == _datefld) ? 10 : curr().length(wfld); if (fixedlen && t == _memofld) { error_box(TR("Non e' possibile scaricare a lunghezza fissa un file con campi memo")); return _isbadtrc; } } TRecnotype i = 0; const TRecnotype nitems = items(); s.format(FR("Esportazione %s"), filename()); TProgind p(nitems, s, TRUE, TRUE, 70); TString s1, sfld; fprintf(f, "[Header]\nVersion=%ld\nFile=%d", (long) prefix().filelevel(), num()); for (int k = 0; k < nflds; k++) { if ((k % 10) == 0) fprintf(f, "\nFields="); else fprintf(f, "|"); fprintf(f, "%s,%d", (const char *) (const TString&) fld[k], len[k]); } fprintf(f, "\n\n[Data]\n"); if (nkey) { setkey(nkey); for ( first(); status() == NOERR && !p.iscancelled(); next(), i++) { p.setstatus(i + 1); if (filter && *filter) { TToken_string filter_str(filter); TString16 fname; bool skip = false; while (!skip && !(fname=filter_str.get()).empty()) { const char* fval = filter_str.get(); const TString& cmp = get(fname); skip = cmp != fval; } skip |= (select_func != NULL) && (select_func(curr(), filter_obj) == false); if (skip) continue; } s.cut(0); for (j = 0; j < nflds; j++) { const TString& fname = fld.row(j); if (fixedlen) { s1 = get(fname); if (rjust[j]) s1.right_just(len[j]); else s1.left_just(len[j]); } else { s1.cut(0); if (j && fs) s1 << fs; if (fd) s1 << fd; sfld = get(fname); switch (curr().type(fname)) { case _intfld: case _longfld: case _intzerofld: case _longzerofld: case _realfld: if (real::is_null(sfld)) sfld.cut(0); break; case _memofld: if (sfld.full()) { int p = 0; while ((p = sfld.find('\n', 0)) >= 0) { sfld.overwrite("\\", p); sfld.insert("n", p+1); } } else sfld.cut(0); break; default: // strfld, charfld, boolfld if (sfld.blank()) sfld.cut(0); break; } s1 << sfld; if (fd) s1 << fd; } s << s1; } if (fs) // Elimina tutti i campi vuoti a fine record { int i; for (i = s.len()-1; i >= 0 && s[i] == fs; i--); s.cut(i+1); } fprintf(f, "%s%c", (const char*) s, rs); } } else { for (i = 0; i < nitems && !p.iscancelled(); i++) { zero(); p.setstatus(i + 1); readat(i + 1); if (filter && *filter) { TToken_string filter_str(filter); TString16 fname; bool skip = FALSE; while (!skip && !(fname=filter_str.get()).empty()) { const char* fval = filter_str.get(); const TString& cmp = get(fname); skip = cmp != fval; } if (skip) continue; } s=""; if (withdeleted || curr().valid()) { for (j = 0; j < nflds; j++) { if (fixedlen) { s1 = get((const TString&)fld[j]); if (rjust[j]) s1.right_just(len[j]); else s1.left_just(len[j]); } else { s1 = ""; if (j && fs) s1 << fs; if (fd) s1 << fd; sfld = get((const TString&)fld[j]); if (curr().type((const TString&) fld[j]) == _memofld) { int p = 0; while ((p = sfld.find('\n', 0)) >= 0) { sfld.overwrite("\\", p); sfld.insert("n", p+1); } } s1 << sfld; if (fd) s1 << fd; } s << s1; } fprintf(f, "%s%c", (const char*) s, rs); } } } p.setstatus(nitems); close(); fclose(f); setstatus(err); return err; } int TSystemisamfile::dump( const char* to, // @parm Nome del file verso quale esportare TToken_string & field_list, // @parm Lista dei campi int nkey, // @parm Numero della chiave di ordinamento con cui scaricare i dati (defualt 1) char fs, // @parm Carattere seperatore di campo (defualt ) char fd, // @parm Carattere delimitatore di campo (default '\\0') char rs, // @parm Carattere separatore di record (default '\\n') bool vis, // @parm Indica se visualizzare lo stato dell'operazione (defualt TRUE) bool withdeleted,// @parm Indica se scaricare anche i record cancellati (dafault FALSE) const char * filter, // @parm Indica l'espressione filtro SELECTIONFUNCTION select_func, // @parm funzione filtro TObject * filter_obj) // @parm oggetto di filtro // @xref { FILE* f = NULL; fopen_s(&f, to, "w"); if (f == NULL) { setstatus(2); return 2; } if (withdeleted) nkey = 0; int err = ferror(f); open(FALSE, nkey ? TRUE : FALSE); TString s(512); bool fixedlen = (fs == '\0'); int nflds = curr().items(); TString_array fld(nflds); TBit_array rjust(nflds); int len[MaxFields]; int j = 0; FOR_EACH_TOKEN(field_list, str) { const TString16 fldname(str); fld.add(fldname); const TFieldtypes t = curr().type(fldname); rjust.set(j, t == _intfld || t == _longfld || t == _realfld || t == _wordfld || t == _intzerofld || t == _longzerofld); len[j++] = (t == _datefld) ? 10 : curr().length(fldname); if (fixedlen && t == _memofld) return error_box(TR("Non č possibile scaricare a lunghezza fissa un file con campi memo")); } TRecnotype i = 0; const TRecnotype nitems = items(); s.format(FR("Esportazione %s"), filename()); TProgind p(nitems, s, TRUE, TRUE, 70); TString s1, sfld; fprintf(f, "[Header]\nVersion=%ld\nFile=%d", (long) prefix().filelevel(), num()); FOR_EACH_ARRAY_ROW(fld, k, el) { if ((k % 10) == 0) fprintf(f, "\nFields="); else fprintf(f, "|"); const TString & fldname =fld.row(k); fprintf(f, "%s,%d", (const char *) fldname, len[k]); } fprintf(f, "\n\n[Data]\n"); if (nkey) { setkey(nkey); for ( first(); status() == NOERR && !p.iscancelled(); next(), i++) { bool skip = false; p.setstatus(i + 1); if (filter && *filter) { TToken_string filter_str(filter); TString16 fname; while (!skip && !(fname=filter_str.get()).empty()) { const char* fval = filter_str.get(); const TString& cmp = get(fname); skip = cmp != fval; } } skip |= (select_func != NULL) && (select_func(curr(), filter_obj) == false); if (skip) continue; s = ""; FOR_EACH_ARRAY_ROW(fld, j, el) { const TString & fldname =fld.row(j); if (fixedlen) { s1 = get(fldname); if (rjust[j]) s1.right_just(len[j]); else s1.left_just(len[j]); } else { s1 = ""; if (j && fs) s1 << fs; if (fd) s1 << fd; sfld = get(fldname); if (curr().type(fldname) == _memofld) { int p = 0; while ((p = sfld.find('\n', 0)) >= 0) { sfld.overwrite("\\", p); sfld.insert("n", p+1); } } s1 << sfld; if (fd) s1 << fd; } s << s1; } fprintf(f, "%s%c", (const char*) s, rs); } } else { for (i = 0; i < nitems && !p.iscancelled(); i++) { zero(); p.setstatus(i + 1); readat(i + 1); if (filter && *filter) { TToken_string filter_str(filter); TString16 fname; bool skip = FALSE; while (!skip && !(fname=filter_str.get()).empty()) { const char* fval = filter_str.get(); const TString& cmp = get(fname); skip = cmp != fval; } if (skip) continue; } s=""; if (withdeleted || curr().valid()) { FOR_EACH_ARRAY_ROW(fld, j, el) { const TString & fldname = fld.row(j); if (fixedlen) { s1 = get(fldname); if (rjust[j]) s1.right_just(len[j]); else s1.left_just(len[j]); } else { s1 = ""; if (j && fs) s1 << fs; if (fd) s1 << fd; sfld = get(fldname); if (curr().type(fldname) == _memofld) { int p = 0; while ((p = sfld.find('\n', 0)) >= 0) { sfld.overwrite("\\", p); sfld.insert("n", p+1); } } s1 << sfld; if (fd) s1 << fd; } s << s1; } fprintf(f, "%s%c", (const char*) s, rs); } } } p.setstatus(nitems); close(); fclose(f); setstatus(err); return err; } #endif // FOXPRO void TBaseisamfile::recover() { } //////////////////////////////////////////////////////////// // Memo data //////////////////////////////////////////////////////////// void TMemo_data::init(TRecnotype recno, TIsam_handle file) { CHECK(file > 0 || recno < 0, "Valid memo recno with NULL memo file"); // verificare _recno = recno; _isamfile = file; } void TMemo_data::destroy() { TString_array::destroy(); _dirty.reset(); _recno = RECORD_NON_FISICO; _isamfile = 0; } void TMemo_data::copy(const TMemo_data& m) { TString_array::operator=(m); _dirty = m._dirty; _recno = m._recno; _isamfile = m._isamfile; } //////////////////////////////////////////////////////////// // TRectype //////////////////////////////////////////////////////////// void TRectype::init(int logicnum) { _logicnum = logicnum; CHECK(_logicnum > 0,"Impossibile costruire un record di un file esterno"); _length = prefix().get_reclen(logicnum); _rec = new char [_length]; *_tab = '\0'; if (_length > 0) zero(); else setempty(TRUE); if (_length > 0 && lf_has_memo(logicnum)) init_memo(RECORD_NON_FISICO); } TRectype::TRectype(int logicnum) : _memo_data(NULL) { init(logicnum); } TRectype::TRectype(const TBaseisamfile* i) : _memo_data(NULL) { init(i->num()); } TRectype::TRectype(const TRectype& r) : _memo_data(NULL) { init(r._logicnum); if (r._memo_data) { init_memo(r._memo_data->recno(), r._memo_data->file()); *_memo_data = *r._memo_data; } memcpy(_rec, r._rec, _length); memcpy(_tab, r._tab, sizeof(_tab)); setempty(r.empty()); } TRectype::~TRectype() { if (_rec != NULL) delete _rec; if (_memo_data != NULL ) delete _memo_data; } void TRectype::unknown_field(const char* name) const { static int last_file = 0; if (_logicnum != last_file) { #ifdef DBG NFCHECK("Il campo '%s' non appartiene al file %d", name, _logicnum); #else fatal_box("Database non convertito.\nIl campo '%s' non appartiene al file %d", name, _logicnum); #endif last_file = _logicnum; } } void TRectype::write_memo(TIsam_handle file, const TRecnotype recno) { const RecDes& r = rec_des( ); TIsam_handle orig = _memo_data->file(); if (orig && (file != orig || recno != _memo_data->recno())) { TCodeb_handle cb_orig = prefix().get_handle(orig); DB_go(cb_orig, _memo_data->recno()); for(int i = r.NFields - 1; i >= 0; i--) { if (r.Fd[i].TypeF == _memofld) { if (_memo_data->objptr(i) == NULL) { const char* memo = DB_memoptr(cb_orig, r.Fd[i].Name); if (memo && *memo) _memo_data->add(memo, i); } _memo_data->set_dirty(i); } } } CHECKD(recno >= 0, "Maiale! Non fare le GO con _recno < 0: ", recno); const TCodeb_handle cb_handle = prefix().get_handle(file); DB_go( cb_handle, recno); FOR_EACH_ARRAY_ROW_BACK((*_memo_data), i, memo) { if (_memo_data->is_dirty(i)) DB_memowrite(cb_handle, r.Fd[i].Name, *memo); } DB_flush(cb_handle); *this = (const char*)DB_getrecord(cb_handle); init_memo(recno, file); } void TRectype::init_memo(TRecnotype recno, TIsam_handle file) { if (_memo_data == NULL) _memo_data = new TMemo_data; else _memo_data->destroy(); _memo_data->init(recno, file); } void TRectype::settab(const char *tab) { strcpy(_tab, tab); zero(); } TObject* TRectype::dup() const { TRectype* o = new TRectype(*this); return o; } const char* TRectype::build_key(int num) const { TString& tmp = get_tmp_string(256); __build_key(rec_des(), num, string(), tmp.get_buffer(), TRUE); return tmp; } const char* TRectype::last_key_field(int key) const { const KeyDes& kd = rec_des().Ky[key]; const int last = kd.NkFields-1; const bool upp = kd.FieldSeq[last] > MaxFields; const int nf = upp ? kd.FieldSeq[last] - MaxFields : kd.FieldSeq[last]; const RecFieldDes& rf = rec_des().Fd[nf]; return rf.Name; } // @doc EXTERNAL // @mfunc Confronta le chiavi di due record // // @rdesc Ritorna il risultato di una : // // @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 { /* Vecchio modo con molte operazioni su stringhe e molte chiamate a rec_des()! TString256 key1 = build_key(key); TString256 key2 = rec.build_key(key); if (skip_last > 0) { const KeyDes& kd = rec_des()->Ky[key-1]; const int last = kd.NkFields-1; CHECKD(last >= skip_last, "Can't ignore so many fields in key: ", skip_last); for (int l = 0; l < skip_last; l++) { int nf = kd.FieldSeq[last-l]; if (nf > MaxFields) nf -= MaxFields; const RecFieldDes& rf = rec_des()->Fd[nf]; key1.rtrim(rf.Len); key2.rtrim(rf.Len); } } const int res = strcmp(key1, key2); */ const char* key1 = build_key(key); const char* key2 = rec.build_key(key); int res = 0; if (skip_last > 0) { int maxlen = 0; const RecDes& rd = rec_des(); const KeyDes& kd = rd.Ky[key-1]; const int last = kd.NkFields-skip_last; for (int l = 0; l < last; l++) { const int nf = kd.FieldSeq[l] % MaxFields; const RecFieldDes& rf = rd.Fd[nf]; maxlen += rf.Len; } res = strncmp(key1, key2, maxlen); } else res = strcmp(key1, key2); return res; } HIDDEN bool fld_empty(const char* s, int len, bool /* number */) { if (s && *s && len > 0) { for (; len; s++, len--) if (*s != ' ') return false; } return true; } HIDDEN int fld_cmp(const char* a, const char* b, int len, bool number) { int res = memcmp(a, b, len); if (res == 0) return res; int i = 0; if (number) // Aggiunta del 11-02-2014: ignoro spazi e zeri iniziali dei numeri for (; i < len && (*a==' ' || *a=='0') && (*b==' ' || *b=='0'); b++, a++, i++); for (; i < len && *a == *b; b++, a++, i++); if (i == len) return 0; res = *a - *b; if (number) { b -= i; i = 0; } return fld_empty(b, len - i, number) ? 0 : res; } /////////////////////////////////////////////////////////// // TRectype (record di un file) /////////////////////////////////////////////////////////// const RecDes& TRectype::rec_des() const { return prefix().get_recdes(_logicnum); } int TRectype::items() const { return rec_des().NFields; } const char* TRectype::start(int nf) const { return string() + rec_des().Fd[nf].RecOff; } // Confronto tra record: Attenzione i campi vuoti di s non vengono confrontati! int TRectype::compare(const TSortable& s) const { const TRectype& br = (const TRectype&) s; int res = 0; if (br.empty()) return UNDEFINED; const RecDes& rd = rec_des(); for (int i = 0; i < rd.NFields; i++) { const char* b = br.start(i); const char* a = start(i); const byte typ = rd.Fd[i].TypeF; const int sz = rd.Fd[i].Len; const bool number = (typ == _intfld) || (typ == _realfld) || (typ == _longfld) || (typ == _wordfld) || (typ == _intzerofld) || (typ == _longzerofld) || (typ == _datefld) ; if (fld_empty(b, sz, number)) continue; res = ::fld_cmp(a, b, sz, number); if (res) return res; } return 0; } // Confronto stretto bool TRectype::is_equal(const TRectype& r) const { char* r1 = new char[_length]; char* r2 = new char[_length]; memcpy(r1, _rec, _length); memcpy(r2, r._rec, _length); browse_null(r1, _length); browse_null(r2, _length); if (has_memo()) { const RecDes& rd = rec_des(); for(int i = rd.NFields - 1; i >= 0; i--) { if (rd.Fd[i].TypeF == _memofld) { memset(r1+rd.Fd[i].RecOff, ' ', rd.Fd[i].Len); memset(r2+rd.Fd[i].RecOff, ' ', rd.Fd[i].Len); } } } bool yes = memcmp(r1, r2, _length) == 0; delete r1; delete r2; if (yes && has_memo()) { const RecDes& rd = rec_des(); for(int i = rd.NFields - 1; yes && i >= 0; i--) { if (rd.Fd[i].TypeF == _memofld) yes = get(rd.Fd[i].Name) == r.get(rd.Fd[i].Name); } } return yes; } TFieldtypes TRectype::type(const char* fieldname) const { const RecDes& recd = rec_des(); const int p = findfld(&recd, fieldname); return p != FIELDERR ? (TFieldtypes)recd.Fd[p].TypeF : _nullfld; } int TRectype::length(const char* fieldname) const { const RecDes& recd = rec_des(); const int p = findfld(&recd, fieldname); return p != FIELDERR ? recd.Fd[p].Len : 0; } int TRectype::ndec(const char* fieldname) const { const RecDes& recd = rec_des(); const int p = findfld(&recd, fieldname); return p != FIELDERR ? recd.Fd[p].Dec : 0; } bool TRectype::exist(const char* fieldname) const { return findfld(&rec_des(), fieldname) != FIELDERR; } const char* TRectype::fieldname(int i) const { const RecDes& recd = rec_des(); return i >= 0 && i < recd.NFields ? recd.Fd[i].Name : NULL; } const TString& TRectype::get_str(const char* fieldname) const { const RecDes& recd = rec_des(); const int nf = findfld(&recd, fieldname); if (nf != FIELDERR) { const RecFieldDes& fd = recd.Fd[nf]; TString& tmp = get_tmp_string(fd.Len + (fd.TypeF == _datefld ? 2 : 0)); __getfieldbuff(fd.Len, fd.TypeF, _rec + fd.RecOff, tmp); return tmp; } else unknown_field(fieldname); return EMPTY_STRING; } const TString& TRectype::get(const char* fieldname) const { if (_memo_data && type(fieldname) == _memofld) { const RecDes& recd = rec_des(); const int index = findfld(&recd, fieldname); if ( _memo_data->objptr( index )) return _memo_data->row( index ); if (_memo_data->recno() >= 0L) { const TIsam_handle orig = _memo_data->file(); if (orig) { CHECKD(orig >= LF_EXTERNAL || orig == num(), "Invalid isam handle ", orig); TCodeb_handle cb_handle = prefix().get_handle(orig, -1); CHECKD(cb_handle >= 0, "Can't read memo from file ", orig); if (DB_recno(cb_handle) != _memo_data->recno()) DB_go(cb_handle, _memo_data->recno()); _memo_data->add(DB_memoptr(cb_handle, fieldname), index); } else NFCHECK("Valid memo recno with null memo file"); } else _memo_data->add("", index); return _memo_data->row(index); } return get_str(fieldname); } int TRectype::get_int(const char* fieldname) const { return atoi(get_str(fieldname)); } long TRectype::get_long(const char* fieldname) const { return atol(get_str(fieldname)); } word TRectype::get_word(const char* fieldname) const { return (word)atoi(get_str(fieldname)); } real TRectype::get_real(const char* fieldname) const { const real r(get_str(fieldname)); return r; } char TRectype::get_char(const char* fieldname) const { return get_str(fieldname)[0]; } bool TRectype::get_bool(const char* fieldname) const { const char c = get_char(fieldname); return (c == 'X') || (c == '1'); } TDate TRectype::get_date(const char* fieldname) const { const TDate d(get_str(fieldname)); return d; } void TRectype::put(const char* fieldname, int val) { char tmp[16]; _itoa_s(val, tmp, 10); put_str(fieldname, tmp); } void TRectype::put(const char* fieldname, long val) { char tmp[16]; _ltoa_s(val, tmp, 10); put_str(fieldname, tmp); } void TRectype::put(const char* fieldname, word val) { put(fieldname, (int)val); } void TRectype::put(const char* fieldname, const real& val) { put_str( fieldname, val.string()); } void TRectype::put(const char* fieldname, const TCurrency& val) { put_str( fieldname, val.get_num().string()); } void TRectype::put(const char* fieldname, const TDate& val) { put( fieldname, val.date2ansi()); } void TRectype::put(const char* fieldname, char val) { const char w[2] = { val, '\0' }; put_str( fieldname, w); } void TRectype::put(const char* fieldname, bool val) { put(fieldname, val ? 'X' : ' '); } void TRectype::put_str(const char* fieldname, const char* val) { const RecDes& recd = rec_des(); const int nf = findfld(&recd, fieldname); if (nf == FIELDERR) { unknown_field(fieldname); return; } const RecFieldDes& fd = recd.Fd[nf]; const TFieldtypes ft = TFieldtypes(fd.TypeF); if (val == NULL) val = ""; if (ft == _boolfld) val = (*val && strchr("1STXY", toupper(*val)) != NULL) ? "T" : "F"; if (*val == '\0') { TRecfield f(*this, fieldname); if (*f.pos() == '\0') return; } if (ft == _memofld) { _memo_data->add(val, nf); _memo_data->set_dirty(nf); } else { __putfieldbuff(fd.Len, fd.Dec, ft, val, _rec + fd.RecOff); } setempty(FALSE); } void TRectype::add(const char* fieldname, const real& val) { if (!val.is_zero()) { real k = get_real(fieldname); k += val; put(fieldname, k); } } void TRectype::zero(const char* fieldname) { if (*_tab && strcmp(fieldname , "COD") == 0) put("COD", _tab); else { const RecDes& recd = rec_des(); const int nf = findfld(&recd, fieldname); if (nf == FIELDERR) unknown_field(fieldname); else { const int recoff = recd.Fd[nf].RecOff; char * p = _rec + recoff; const byte len = recd.Fd[nf].Len; const byte dec = recd.Fd[nf].Dec; const TFieldtypes type = (TFieldtypes) recd.Fd[nf].TypeF; switch (type) { case _datefld: __putfieldbuff(len, dec, _datefld, "", p); break; case _memofld: __putfieldbuff(len, dec, _memofld, "", p); _memo_data->add("", nf); _memo_data->set_dirty(nf); break; default: memset(p, ' ', len); if ((type == _intfld) || (type == _longfld) || (type == _wordfld)) *(p + len - 1) = '0'; else if (type == _realfld) { if (dec) { memset(p + len - dec - 2, '0', dec + 2); *(p + len - dec - 1) = '.'; } else *(p + len - 1) = '0'; } break; } } } } void TRectype::zero(char c) { memset(_rec, c, len()); recall(); if (*_tab) put("COD", _tab); if(has_memo()) init_memo( RECORD_NON_FISICO ); setempty(true); } // Certified 99% TRectype& TRectype::operator =(const TRectype& rec) { CHECK(num() == rec.num(), "Can't assign records of different file"); memcpy(_rec, rec._rec, _length); // Copy contents if (rec._memo_data) { init_memo(rec._memo_data->recno(), rec._memo_data->file()); *_memo_data = *rec._memo_data; } memcpy(_tab, rec._tab, sizeof(_tab)); setempty(rec.empty()); // Copy emptiness status return *this; } // Certified 100% TRectype& TRectype::operator =(const TBaseisamfile& f) { return *this = f.curr(); } // Certified 50% int TRectype::read(TBaseisamfile& f, word op, word lockop) { int err = f._read(*this,op,lockop); return err; } int TRectype::readat(TBaseisamfile& f, TRecnotype nrec, word lockop) { return f._readat(*this,nrec,lockop); } // Certified 100% int TRectype::next(TBaseisamfile& f,word lockop) { return read(f, _isnext, lockop); } // Certified 100% int TRectype::prev(TBaseisamfile& f,word lockop) { return read(f, _isprev, lockop); } int TRectype::first(TBaseisamfile& f,word lockop) { return read(f, _isfirst, lockop); } int TRectype::last(TBaseisamfile& f,word lockop) { return read(f, _islast, lockop); } // Certified ??% int TRectype::write(TBaseisamfile& f) const { return f._write(*this); } // Certified ??% int TRectype::rewrite(TBaseisamfile& f) const { return f._rewrite(*this); } int TRectype::write_rewrite(TBaseisamfile& f) const { int err = write(f); if (err == NOERR) f._read((TRectype&)*this, _iscurr, _unlock); // Sblocca record 19-09-2012 (andrebbe nella _write) else err = rewrite(f); return err; } int TRectype::rewrite_write(TBaseisamfile& f) const { int err = rewrite(f); if (err != NOERR) { err = write(f); if (err == NOERR) f._read((TRectype&)*this, _iscurr, _unlock); // Sblocca record 19-09-2012 (andrebbe nella _write) } return err; } // Certified ??% int TRectype::remove(TBaseisamfile& f) const { return f._remove(*this); } void TRectype::renum_key(const char* field, const char* val) { if (strchr(field, '[') != NULL) // Accept CODTAB[6,10] { const TFieldref fref(field, 0); TString80 str = val; if (real::is_natural(val)) str.right_just(fref.len(*this), '0'); fref.write(str, *this); } else put(field, val); } // Certified 99% TRectype& TRectype::operator =(const char* rec) { if (rec && *rec) { memcpy(_rec, rec, _length); setempty(false); } else zero(); return *this; } const char* TRectype::key(int numkey) const { TString& tmp = get_tmp_string(256); __build_key(rec_des(), numkey, _rec, tmp.get_buffer(), false); return tmp; } void TRectype::fill_transaction(TConfig& cfg, int row) const { TString16 p; p << num(); if (row > 0) p << ',' << row; cfg.set_paragraph(p); for (int f = items()-1; f >= 0; f--) { const char* name = fieldname(f); const char* value = get(name); cfg.set(name, value); } } bool TRectype::send_mail(const char* action) const { TWait_cursor hourglass; bool ok = ::can_dispatch_transaction(*this); if (ok) { TFilename ininame; ininame.temp("msg", "ini"); if (ok) // Dummy test per {} { TConfig ini(ininame, "Transaction"); ini.set("Action", action); ini.set("Mode", "A"); fill_transaction(ini); } ok = ::dispatch_transaction(*this, ininame); ininame.fremove(); } return ok; } bool TRectype::get_relapp(TString& app) const { if (*_tab) { TString4 cod(_tab); switch (num()) { case LF_TABCOM: cod.insert("%"); break; case LF_TABGEN: cod.insert("^"); break; case LF_TABMOD: { TModule_table mod(_tab); return mod.get_relapp(app); } break; default : break; } return ::get_tabapp(cod, app); } return ::get_relapp(num(), app); } bool TRectype::edit(int logicnum, const char* alternate_key_fields, const char* hint) const { bool ok = false; if (logicnum <= 0) logicnum = num(); TRectype r(logicnum); if (*_tab) r.settab(_tab); TString app = hint; if (app.blank()) r.get_relapp(app); if (app.full()) { const RecDes& recd = r.rec_des(); // Descrizione del record della testata const KeyDes& kd = recd.Ky[0]; // Elenco dei campi della chiave 1 TToken_string key_labels; for (int i = 0; i < kd.NkFields; i++) { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = recd.Fd[nf]; key_labels.add(rf.Name); } TToken_string key_fields(alternate_key_fields); if (key_fields.empty_items()) key_fields = key_labels; TFilename ininame; ininame.temp("lnk", "ini"); { TConfig ini(ininame, "Transaction"); ini.set("Action", "LINK"); TString8 p; p << logicnum; ini.set_paragraph(p); FOR_EACH_TOKEN(key_labels, tok) { const TString16 name(tok); const TString& value = get(key_fields.get()); ini.set(name, value); } } app << " -i" << ininame; TExternal_app a(app); ok = a.run() == 0; if (ok) { xvt_sys_sleep(500); const TString& result = ini_get_string(ininame, "Transaction", "Result"); ok = result == "OK"; } xvt_fsys_remove_file(ininame); if (ok) rec_cache(logicnum).notify_change(); } return ok; } bool TRectype::set_edit_info(const char* ut, const char* dt, const char* or) { bool ok = false; if (num() >= LF_TABCOM) { // Se esiste un campo alfanumerioco UT* if (ut && *ut && type(ut) == _alfafld) { const int len = length(ut); TString80 usr = user(); TString80 s; xvt_sys_get_user_name(s.get_buffer(), s.size()); const int at = s.find('@'); if (at > 0 ) s.cut(at); // Windows 8.1 / 10.0 user profile if (usr.len()+s.len()+1 <= len) usr << ':' << s; xvt_sys_get_host_name(s.get_buffer(), s.size()); if (usr.len()+s.len()+1 <= len) usr << '@' << s; put(ut, usr); // Scrivi utente corrente ok = true; // Se esiste un campo data DT* if (dt && *dt && type(dt) == _datefld) { const TDate oggi(TODAY); put(dt, oggi); // Scrivi data odierna // Se esisnte un campo long OR* if (or && *or && (type(or) == _longfld || type(or) == _longzerofld)) put(or, daytime()); // Scrivi ora attuale HHMMSS } } } return ok; } bool TRectype::set_modify_info() { bool done = false; if (num() >= LF_LVPASPLAN && exist("UTULAGG")) // Lavanderie done = set_edit_info("UTULAGG", "DTULAGG", "ORULAGG"); else if (exist("UTENTE")) done = set_edit_info("UTENTE", "DATAAGG", NULL); return done; } bool TRectype::set_creation_info() { bool done = set_modify_info(); if (num() >= LF_LVPASPLAN && exist("UTCREAZ")) // Lavanderie done |= set_edit_info("UTCREAZ", "DTCREAZ", "ORCREAZ"); return done; } /////////////////////////////////////////////////////////// // TRecfield (campo/sottocampo di un record) /////////////////////////////////////////////////////////// TRecfield::TRecfield(TRectype& rec, const char* name, int from, int to) { _rec = &rec; const TFixed_string fname(name); const int colon = fname.find(':'); if (colon > 0) { _name.strncpy(name, colon); _sub_field = name+colon+1; _sub_field << '='; // ??????????????? } else _name = name; const RecDes& rd = _rec->rec_des(); const int nf = findfld(&rd, _name); if (nf == FIELDERR) { _sub_field = _name; _p = _rec->string(); _len = 0; _dec = 0; _type = _alfafld; } else { if (from < 0) { NFCHECK("Invalid Start %d", from); from = 0; } _p = _rec->string() + rd.Fd[nf].RecOff; _dec = rd.Fd[nf].Dec; _type = (TFieldtypes)rd.Fd[nf].TypeF; if (_sub_field.empty()) { _p += from; if (to >= 0) { CHECKS(_type == _memofld || (from <= to && to <= rd.Fd[nf].Len), "Invalid Range on field ", (const char *)_name); _len = to - from + 1; } else _len = rd.Fd[nf].Len - from; } else { CHECK(_type == _memofld, "You can use Subfields only with Memo"); _from = from; _to = to; if (_type == _memofld) _len = 0; else _len = rd.Fd[nf].Len; } } CHECKS(colon < 0 || _type == _memofld, "SubField on non memo field: ", name); } void TRecfield::put_subfield(const char* s) { if (_name == _sub_field) return; const TString& str = _rec->get(_name); int p = str.find(_sub_field); if (p == 0 || (p > 0 && str[p - 1] < ' ')) { p += _sub_field.len(); int e = str.find('\n', p); if (_to > 0 && p + _to < e) e = p + _to; p += _from; if (p < e) { TString val(s); if (_to > 0) { val.left(e - p + 1); val.rpad(e - p + 1); } TString out = str.left(p); out << val << str.mid(e); // ? e + 1 _rec->put(_name, out); } } } int TRecfield::operator =(int i) { TString16 buff; buff << i; if (_sub_field.empty()) __putfieldbuff( _len, _dec, _type, buff, _p); else put_subfield(buff); _rec->setempty(FALSE); return i; } long TRecfield::operator =(long l) { TString16 buff; buff << l; if (_sub_field.empty()) __putfieldbuff( _len, _dec, _type, buff, _p); else put_subfield(buff); _rec->setempty(false); return l; } const real& TRecfield::operator =(const real& r) { const char* buff = r.string(); if (_sub_field.empty()) __putfieldbuff( _len, _dec, _type, buff, _p); else put_subfield(buff); _rec->setempty(FALSE); return r; } const TDate& TRecfield::operator =(const TDate& d) { const TString16 buff = d.stringa(); if (_sub_field.empty()) __putfieldbuff( _len, _dec, _type, buff, _p); else put_subfield(buff); _rec->setempty(FALSE); return d; } const char* TRecfield::operator =(const char* s) { if (_sub_field.empty()) { if (_type == _memofld) _rec->put(_name, s); else __putfieldbuff( _len, _dec, _type, s, _p); } else put_subfield(s); _rec->setempty(FALSE); return s; } void TRecfield::setptr(TRecnotype r) { if (_p == NULL) return; bool n = r < 0; unsigned char* wp = (unsigned char*) _p; if (n) r = -r; while(wp - (unsigned char*) _p <= 3) { *wp = r && 0x000000FF; r >>= 8; wp++; } if (n) *wp += 128; } void TRecfield::get_subfield(TString& s) const { const TString& str = _rec->get(_name); if (_name == _sub_field) s = str; else { int p = str.find(_sub_field); if (p == 0 || (p > 0 && str[p - 1] < ' ')) { p += _sub_field.len(); int e = str.find('\n', p); if (e < 0) e = str.len(); // L'ultima variabile non termina con \n if (_to > 0 && p + _to < e) e = p + _to; p += _from; if (p < e) s = str.sub(p, e); else s.cut(0); } else s.cut(0); } } TRecfield::operator int() const { TString16 tmp; if (_sub_field.empty()) { if (_type == _intfld || _type == _intzerofld || _type == _longfld || _type == _longzerofld) tmp.strncpy(_p, _len); else __getfieldbuff( _len, _type, _p, tmp); } else get_subfield(tmp); return atoi(tmp); } TRecfield::operator long() const { TString16 tmp; if (_sub_field.empty()) { if (_type == _longfld || _type == _longzerofld || _type == _intfld || _type == _intzerofld) tmp.strncpy(_p, _len); else __getfieldbuff( _len, _type, _p, tmp); } else get_subfield(tmp); return atol(tmp); } TRecfield::operator const real() const { TString80 tmp; if (_sub_field.empty()) { if (_type == _realfld) tmp.strncpy(_p, _len); else __getfieldbuff( _len, _type, _p, tmp); } else get_subfield(tmp); return real(tmp); } TRecfield::operator TDate() const { TString16 tmp; if (_sub_field.empty()) { if (_type == _datefld) { tmp.strncpy(_p, 8); return TDate(atol(tmp)); } __getfieldbuff(_len, _type, _p, tmp); } else get_subfield(tmp); return TDate(tmp); } TRecfield::operator const char*() const { TString& tmp = get_tmp_string(max(_len, 50)); if (_sub_field.empty()) { if (_type == _memofld) return _rec->get(_name); __getfieldbuff(_len, _type, _p, tmp); } else get_subfield(tmp); return tmp; } TRecnotype TRecfield::ptr() const { if (_p == NULL) return(RECORD_NON_FISICO); unsigned char* wp = (unsigned char*) _p + 3; TRecnotype r = *wp; bool n = r > 127; if (n) r -= 128; while(wp-- > (unsigned char*) _p) r = (r << 8) + *wp; return n ? -r : r; }