Files correlati : Ricompilazione Demo : [ ] Commento : Aggiornamento periodico del main trunk con riporti del best of 1.5 git-svn-id: svn://10.65.10.50/trunk@7959 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			748 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			748 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <time.h>
 | |
| 
 | |
| #include <prefix.h>
 | |
| #include <recarray.h>
 | |
| #include <tabutil.h>
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TRecord_Array
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| TRecord_array::TRecord_array(const TRectype& r, const char* numfield, int first)
 | |
|              : _file(r.num()), _num(numfield), _offset(first - 1)
 | |
| { 
 | |
|   read(r); 
 | |
| } 
 | |
| 
 | |
| TRecord_array::TRecord_array(int logicnum, const char* numfield, int first)
 | |
|              : _file(logicnum), _num(numfield), _offset(first - 1)
 | |
| {
 | |
|   set_key(new TRectype(logicnum));
 | |
| } 
 | |
| 
 | |
| TRecord_array::TRecord_array(const TRecord_array& a)
 | |
| {
 | |
|   copy(a);
 | |
| }
 | |
| 
 | |
| TRecord_array::~TRecord_array()
 | |
| {
 | |
| }
 | |
| 
 | |
| void TRecord_array::set_key(TRectype* r)
 | |
| {                                                                     
 | |
|   CHECK(r != NULL, "TRecord_array can't have a null key");
 | |
|   CHECK(r->num() == _file, "Bad key record");
 | |
| 
 | |
|   if (_data.objptr(0) != r)
 | |
|     _data.add(r, 0);                      // Setta il nuovo campo chiave
 | |
|   if (rows() > 0)
 | |
|   {
 | |
|     const RecDes* recd = r->rec_des();    // Descrizione del record della testata
 | |
|     const KeyDes& kd = recd->Ky[0];       // Elenco dei campi della chiave 1
 | |
|     // Copia tutti i campi chiave, tranne l'ultimo, in tutti i records
 | |
|     TString val;
 | |
|     for (int i = kd.NkFields-2; i >= 0; i--)
 | |
|     {                        
 | |
|       const int nf = kd.FieldSeq[i] % MaxFields;
 | |
|       const RecFieldDes& rf = recd->Fd[nf];  
 | |
|       val = r->get(rf.Name);
 | |
|       renum_key(rf.Name, val);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| const TRectype& TRecord_array::key() const 
 | |
| {
 | |
|   TRectype* r = (TRectype*)_data.objptr(0);
 | |
|   CHECK(r, "TRecord_array lost its key");
 | |
|   return *r; 
 | |
| }
 | |
| 
 | |
| bool TRecord_array::exist(int n) const
 | |
| { 
 | |
|   const int i = n > 0 ? n - _offset : -1;
 | |
|   TObject* r = _data.objptr(i);
 | |
|   return r != NULL;
 | |
| }  
 | |
| 
 | |
| // @doc EXTERNAL
 | |
| 
 | |
| // @mfunc Ritorna la riga <p r>-esima; se tale riga non esiste e se <p create> assume il valore TRUE la riga viene creata
 | |
| //
 | |
| // @rdesc Ritorna un TRectype alla riga cercata o eventualemete il reference della nuova creata,
 | |
| //    NULL nel caso non esista e non venga creata.
 | |
| TRectype& TRecord_array::row(
 | |
|           int n,  // @parm Numero della riga da creare
 | |
|           bool create)  // @parm Indica se creare una nuova riga se non esiste:
 | |
|       //
 | |
|       // @flag TRUE | Se la riga <p n> non esiste viene creata
 | |
|       // @flag FALSE | Se la riga <p n> non esiste non viene creata
 | |
| 
 | |
| // @comm Nel caso <p create> sia TRUE e venga richiesta una riga non esistente si crea un nuovo
 | |
| //   record copiando la chiave.
 | |
| {                    
 | |
|   const int i = n >= 0 ? n - _offset : -1;
 | |
|   TRectype* r = (TRectype*)_data.objptr(i);
 | |
|   if (r == NULL && create)
 | |
|   {
 | |
|     r = (TRectype*)key().dup();                 // Crea nuovo record copiando la chiave
 | |
|     n = _data.add(r, i) + _offset;                    // Riassegna n se era negativo!
 | |
|     char str[16]; sprintf(str, "%d", n);
 | |
|     r->renum_key(_num, str);                    // Aggiorna campo numero riga
 | |
|   }
 | |
|   CHECKD(r && n > 0, "Bad record number ", n);  
 | |
|   return *r;
 | |
| }
 | |
| 
 | |
| // @doc EXTERNAL
 | |
| 
 | |
| // @mfunc Rinumera il campo chiave in seguito a reinsert
 | |
| //
 | |
| // @rdesc Ritorna se e' stato rinumerato il campo chiave
 | |
| bool TRecord_array::renum_key(
 | |
|      const char* field,   // @parm Campo della chiave a cui assegnare un nuovo valore
 | |
|      const TString& num)  // @parm Nuovo valore da assegnare al campo
 | |
|         // @parm long | num | Nuovo valore da assegnare al campo
 | |
| 
 | |
| // @syntax bool renum_key(const char* field, const TString& num);
 | |
| // @syntax bool renum_key(const char* field, long num);
 | |
| 
 | |
| {      
 | |
|   CHECKS(_num != field, "You can't renumber field ", field);
 | |
|   
 | |
|   for (int i = _data.last(); i >= 0; i--)
 | |
|   {
 | |
|     TRectype* r = (TRectype*)_data.objptr(i);
 | |
|     if (r != NULL)
 | |
|       r->renum_key(field, num);
 | |
|   }  
 | |
|   
 | |
|   return TRUE; 
 | |
| }
 | |
| 
 | |
| bool TRecord_array::renum_key(const char* field, long num)
 | |
| {   
 | |
|   CHECKS(num > 0, "Null key value for field: ", field);
 | |
|   TString16 n; n << num;
 | |
|   return renum_key(field, n);
 | |
| }
 | |
| 
 | |
| 
 | |
| int TRecord_array::rec2row(const TRectype& r) const
 | |
| {
 | |
|   CHECK(r.num() == _file, "Incompatible record");
 | |
|   const int n = atoi(r.get(_num)) - _offset;    // Non e' detto che sia un int!
 | |
|   CHECKD(n >= 0 && n < 30000, "Bad line number in record ", n + _offset);
 | |
|   return n;
 | |
| }
 | |
| 
 | |
| int TRecord_array::insert_row(TRectype* r)
 | |
| {      
 | |
|   const int nr = rec2row(*r);
 | |
|   CHECK(nr > 0, "You cannot insert a new key");
 | |
|   const bool shift = exist(nr);
 | |
|   _data.insert(r, nr);
 | |
|   if (shift)                     
 | |
|   {                             
 | |
|     for (int f = _data.last(); f > nr; f = _data.pred(f))         
 | |
|     {    
 | |
|       char n[16]; 
 | |
|       TRectype & rec = row(f, FALSE);
 | |
|       
 | |
|       sprintf(n, "%ld", (long)_offset + f);
 | |
|       rec.renum_key(_num, n);
 | |
|     }
 | |
|   }
 | |
|   return nr;
 | |
| }
 | |
| 
 | |
| int TRecord_array::add_row(TRectype* r)
 | |
| {               
 | |
|   const int nr = rec2row(*r);
 | |
|   if (nr==0)
 | |
|     set_key(r);
 | |
|   else
 | |
|     _data.add(r, nr);
 | |
|   return nr;
 | |
| }
 | |
| 
 | |
| 
 | |
| // @doc EXTERNAL
 | |
| 
 | |
| // @mfunc Elimina le righe vuote
 | |
| void TRecord_array::pack()
 | |
| {                       
 | |
|   _data.pack();
 | |
|   
 | |
|   for (int i = _data.last(); i > 0; i--)
 | |
|   {
 | |
|     TRectype* r = (TRectype*)_data.objptr(i);
 | |
|     if (r != NULL)
 | |
|     {
 | |
|       TString16 n; n << i+_offset;
 | |
|       r->renum_key(_num, n);
 | |
|     }  
 | |
|   }  
 | |
| } 
 | |
| 
 | |
| 
 | |
| // @doc EXTERNAL
 | |
| 
 | |
| // @mfunc Cancella una riga
 | |
| //
 | |
| // @rdesc Ritorna se e' riuscito ad eliminare la riga
 | |
| bool TRecord_array::destroy_row(
 | |
|      int r,   // @parm Numero della riga da eliminare
 | |
|      bool pack) // @parm Indica se compattare gli elementi dell'array (default FALSE)
 | |
|     // @parm const TRectype& | r | Record da eliminare
 | |
| 
 | |
| // @syntax bool destroy_row(int n, bool pack);
 | |
| // @syntax bool destroy_row(const TRectype& r, bool pack);
 | |
| 
 | |
| {                       
 | |
|   CHECKD(r > _offset, "Can't destroy row ", r);
 | |
|   const int index = r - _offset;
 | |
|   const bool ok = _data.destroy(index, pack);
 | |
|   
 | |
|   if (ok && pack)
 | |
|   {
 | |
|     for (int i = _data.size()-1; i >= index; i--)
 | |
|     {
 | |
|       TRectype* r = (TRectype*)_data.objptr(i);
 | |
|       if (r != NULL)
 | |
|       {
 | |
|         TString16 n; n << i+_offset;
 | |
|         r->renum_key(_num, n);
 | |
|       }  
 | |
|     }  
 | |
|   }
 | |
|   return ok;
 | |
| } 
 | |
| 
 | |
| void TRecord_array::destroy_rows()
 | |
| {                      
 | |
|   for (int i = _data.last(); i > 0; i = _data.pred(i))
 | |
|     _data.destroy(i);
 | |
| } 
 | |
| 
 | |
| // @doc EXTERNAL
 | |
| 
 | |
| // @mfunc Confronta i campi della chiave 1 scartando l'ultimo
 | |
| //
 | |
| // @rdesc Ritorna il risulato del confronto:
 | |
| //
 | |
| // @flag TRUE | Se i campi sono uguali
 | |
| // @flag FALSE | Se i campi sono diversi
 | |
| bool TRecord_array::good(
 | |
|      const TRectype& rec) const  // @parm Record di cui confrontare i campi
 | |
| {                                
 | |
|   const bool yes = key().same_key(rec, 1, 1);
 | |
|   return yes;
 | |
| }
 | |
| 
 | |
| int TRecord_array::read(TRectype* filter)
 | |
| {            
 | |
|   CHECK(filter != NULL, "You can't specify NULL as filter ");
 | |
|   CHECKD(filter->num() == _file, "Bad key record ", filter->num());
 | |
|   CHECKS(filter->get(_num).empty(), "You can't specify in the filter the field ", (const char*)_num);
 | |
| 
 | |
|   _data.destroy();
 | |
|   set_key(filter);    
 | |
|   int err = NOERR;
 | |
|   if (!filter->empty())
 | |
|   {
 | |
|     TLocalisamfile f(_file);
 | |
|     TRectype* rec = (TRectype*)filter->dup();
 | |
|     err = rec->read(f, _isgteq);
 | |
|     for (int e = err; e == NOERR && good(*rec); e = rec->next(f))
 | |
|     {
 | |
|       add_row(rec);
 | |
|       rec = (TRectype*)(key().dup());
 | |
|     }  
 | |
|     delete rec;
 | |
|   } 
 | |
|   else 
 | |
|     err = _iskeynotfound;
 | |
|   return err;  
 | |
| }
 | |
| 
 | |
| // @doc EXTERNAL
 | |
| 
 | |
| // @mfunc Copia un record array
 | |
| //
 | |
| // @rdesc Copia il record array passato in quello corrente
 | |
| TRecord_array& TRecord_array::copy(
 | |
|      const TRecord_array& a) // @parm Record_array da copiare
 | |
| {
 | |
|   _file = a._file;
 | |
|   _data = a._data;
 | |
|   _offset = a._offset;
 | |
|   _num = a._num;
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| int TRecord_array::read(const TRectype& filter)
 | |
| { 
 | |
|   TRectype* f = (TRectype*)filter.dup();
 | |
|   return read(f);  
 | |
| }
 | |
| 
 | |
| int TRecord_array::remove_from(int pos) const
 | |
| {                 
 | |
|   int err = NOERR;
 | |
| 
 | |
|   TRectype* rec = (TRectype*)key().dup();
 | |
|   CHECK(!rec->empty(), "Can't use empty key");
 | |
| 
 | |
|   TLocalisamfile f(_file);
 | |
|   rec->put(_num, pos);
 | |
|   for (int e = rec->read(f, _isgteq); e == NOERR && good(*rec); e = rec->next(f))
 | |
|   {                     
 | |
|     const int found = rec->get_int(_num);
 | |
|     if (found >= pos)
 | |
|     {
 | |
|       err = rec->remove(f);             
 | |
|       if (err != NOERR)
 | |
|         break;
 | |
|       pos = found+1;  
 | |
|     }
 | |
|     else
 | |
|       break;    
 | |
|   } 
 | |
|   delete rec;
 | |
| 
 | |
|   return err;
 | |
| }
 | |
| 
 | |
| 
 | |
| int TRecord_array::write(bool re) const
 | |
| {          
 | |
|   const int EOR = 32000;              // End of records on file
 | |
|   int last_on_file = 0;               // Last record found on file
 | |
|   int err = NOERR;
 | |
|     
 | |
|   TLocalisamfile f(_file);
 | |
|   const int u = _data.last();
 | |
| 
 | |
|   //TRectype* rec = (TRectype*)key().dup();
 | |
|   CHECK(u<1 || !key().empty(), "Can't write rows using an empty key");
 | |
|   for (int i = 1; i <= u; i++)
 | |
|   {
 | |
|     const TRectype* r = (TRectype*)_data.objptr(i);
 | |
|     
 | |
|     if (r != NULL) 
 | |
|     {               
 | |
|       if (re)
 | |
|       {
 | |
|         err = r->rewrite(f);     
 | |
|         if (err == _iskeynotfound || err == _iseof || err == _isemptyfile)
 | |
|           err = r->write(f);           
 | |
|         if (err != NOERR) 
 | |
|           break;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         err = r->write(f);     
 | |
|         if (err == _isreinsert)
 | |
|         {
 | |
|           err = r->rewrite(f);           
 | |
|           re = TRUE;
 | |
|         }  
 | |
|         if (err != NOERR) 
 | |
|           break;
 | |
|       }    
 | |
|     }
 | |
|     else
 | |
|     {                    
 | |
|       const int pos = i+_offset;                                       
 | |
|       
 | |
|       // Se pos < last_on_file sicuramente la read fallira' per cui la riga
 | |
|       // non puo' esistere su file: non esistendo nemmeno in memoria non devo
 | |
|       // fare assolutamente nulla!
 | |
|       if (pos >= last_on_file)                // Puo' esistere su file?
 | |
|       {
 | |
|         TRectype* rec = (TRectype*)key().dup();
 | |
|         CHECK(!rec->empty(), "TRecord_array has an empty key");
 | |
|         rec->put(_num, pos);
 | |
|         err = rec->read(f, _isgteq);
 | |
|         if (err == NOERR && good(*rec))       // Cerca una riga >= pos sul file
 | |
|         {               
 | |
|           last_on_file = atoi(rec->get(_num));
 | |
|           if (last_on_file == pos)            // La riga c'era ma ora non piu'
 | |
|           {
 | |
|             err = (rec->remove(f));           // Cancello il record indesiderato
 | |
|             if (err != NOERR) 
 | |
|             {         
 | |
|               delete rec;                     // Orrore! Un errore di cancellazione!
 | |
|               break;
 | |
|             }  
 | |
|           }
 | |
|         } 
 | |
|         else
 | |
|           last_on_file = EOR;                 // Sul file non ci sono piu' righe da cancellare
 | |
|         delete rec;   
 | |
|       }  
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Cancella eventuali residui successivi
 | |
|   if (err == NOERR && last_on_file != EOR)
 | |
|     remove_from(i + _offset);
 | |
|   
 | |
|   return err;
 | |
| }
 | |
| 
 | |
| int TRecord_array::remove() const
 | |
| {
 | |
|   return remove_from(1 + _offset);
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TFile_cache
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| TFile_cache::TFile_cache(TLocalisamfile *f , int key)
 | |
|              : _file(NULL), _key(key), _last_firm(-883), 
 | |
|                _test_changes(FALSE), _last_read(0), _limit(0)
 | |
| {    
 | |
|   _filecode << f->num();
 | |
|   init_file(f);
 | |
| }
 | |
| 
 | |
| TFile_cache::TFile_cache(int num, int key)
 | |
|              : _file(NULL), _key(key), _last_firm(-883), 
 | |
|                _test_changes(FALSE), _last_read(0), _limit(0)
 | |
| {    
 | |
|   _filecode << num;
 | |
| }
 | |
| 
 | |
| TFile_cache::TFile_cache(const char* tab, int key)
 | |
|              : _file(NULL), _key(key), _last_firm(-883), 
 | |
|                _test_changes(FALSE), _last_read(0), _limit(0)
 | |
| {
 | |
|   _filecode = tab;
 | |
| }
 | |
| 
 | |
| TFile_cache::~TFile_cache()
 | |
| { 
 | |
|   if (_file != NULL)
 | |
|     delete _file;
 | |
| }
 | |
| 
 | |
| void TFile_cache::init_file(TLocalisamfile* f)
 | |
| {
 | |
|   if (_file != NULL) 
 | |
|   {
 | |
|     delete _file;
 | |
|     _file = NULL;
 | |
|   }
 | |
|    
 | |
|   if (f == NULL)
 | |
|   {
 | |
|     int logicnum = atoi(_filecode);
 | |
|     if (logicnum == 0)
 | |
|     {
 | |
|       _file = new TTable(_filecode);
 | |
|       logicnum = _file->num();
 | |
|     }  
 | |
|     else
 | |
|     {
 | |
|       _file = new TLocalisamfile(logicnum);
 | |
|     }  
 | |
|   } 
 | |
|   else
 | |
|     _file = f;
 | |
|     
 | |
|   if (_file != NULL)
 | |
|   {
 | |
|     TDir dir; 
 | |
|     dir.get(_file->num(), _nolock, _nordir, _sysdirop);
 | |
|     // Se e' un file comune metti a -1, altrimenti alla ditta corrente
 | |
|     _last_firm = dir.is_com() ? -1 : prefix().get_codditta();
 | |
|     _last_read = 0L;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TFile_cache::test_firm()
 | |
| {             
 | |
|   if (_last_firm < -1)
 | |
|     init_file();
 | |
|  
 | |
|   if (_last_firm >= 0)  // Se e' un file di ditta ...
 | |
|   {                     // ... controlla che non sia cambiata
 | |
|     const long cur_firm = prefix().get_codditta();
 | |
|     if (cur_firm != _last_firm)
 | |
|     {                                             
 | |
|       _last_firm = cur_firm;
 | |
|       _cache.destroy();
 | |
|     }  
 | |
|   }  
 | |
| 
 | |
|   bool flush_needed = FALSE;
 | |
| 
 | |
|   if (_test_changes)
 | |
|   {
 | |
|     if (_file != NULL && _file->is_changed_since(_last_read))
 | |
|       flush_needed = TRUE;
 | |
|   }
 | |
| 
 | |
|   if (_limit > 0 && items() > _limit)
 | |
|     flush_needed = TRUE;
 | |
| 
 | |
|   if (flush_needed)
 | |
|   {
 | |
|     flush();
 | |
|     _cache.destroy();
 | |
|   }
 | |
| 
 | |
|   _last_read = clock();
 | |
| }
 | |
| 
 | |
| void TFile_cache::flush()
 | |
| {
 | |
|   // Needed by read/write cache
 | |
| }
 | |
| 
 | |
| bool TFile_cache::already_loaded(const char* code) const
 | |
| {
 | |
|   return _cache.objptr(code) != NULL;
 | |
| }
 | |
| 
 | |
| bool TFile_cache::already_loaded(long code) const
 | |
| {
 | |
|   TString16 str; str << code;
 | |
|   return already_loaded(str);
 | |
| }
 | |
| 
 | |
| const TObject& TFile_cache::query(const char* code)
 | |
| {               
 | |
|   _error = NOERR;
 | |
|   _code = code;
 | |
| 
 | |
|   test_firm();
 | |
| 
 | |
|   TObject* obj = _cache.objptr(_code);
 | |
|   if (obj == NULL)
 | |
|   {     
 | |
|     TLocalisamfile& f = file();
 | |
|     TRectype& curr = f.curr();
 | |
|     if (_code.not_empty())
 | |
|     {
 | |
|       const RecDes* recd = curr.rec_des();    // Descrizione del record della testata
 | |
|       const KeyDes& kd = recd->Ky[_key-1];    // Elenco dei campi della chiave
 | |
|       for (int i = f.tab() ? 1 :0; i < kd.NkFields; i++)   // Riempie la chiave selezionata
 | |
|       {                        
 | |
|         const int nf = kd.FieldSeq[i] % MaxFields;
 | |
|         const RecFieldDes& rf = recd->Fd[nf];  
 | |
|         const char* val = _code.get();
 | |
|         if (val)
 | |
|           curr.put(rf.Name, val);
 | |
|         else
 | |
|           NFCHECK("Valore del campo chiave %s non specificato per la cache", rf.Name);
 | |
|       }
 | |
|       f.setkey(_key);
 | |
|       _error = f.read();
 | |
|     } else 
 | |
|       _error = _iskeyerr;
 | |
|     switch (_error)
 | |
|     {
 | |
|       case NOERR:
 | |
|         break;
 | |
|       case _iskeynotfound:
 | |
|       case _iseof:
 | |
|       case _isemptyfile:
 | |
|       default:
 | |
|         curr.zero();
 | |
|         break;
 | |
|     }
 | |
|     obj = rec2obj(curr);
 | |
|     _cache.add(_code, obj);
 | |
|   }
 | |
|   
 | |
|   return *obj;
 | |
| }
 | |
| 
 | |
| bool TFile_cache::discard(const char* victim)
 | |
| {
 | |
|   if (victim && *victim)
 | |
|     return _cache.remove(victim);
 | |
|   destroy();
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| int TFile_cache::io_result()
 | |
| {
 | |
|   return _error;
 | |
| }
 | |
| 
 | |
| long TFile_cache::fill()
 | |
| {               
 | |
|   test_firm();
 | |
| 
 | |
|   TLocalisamfile& f = file();
 | |
|   TRectype& curr = f.curr();
 | |
|   const RecDes* recd = curr.rec_des();    // Descrizione del record della testata
 | |
|   const KeyDes& kd = recd->Ky[_key-1];    // Elenco dei campi della chiave
 | |
| 
 | |
|   f.setkey(_key);
 | |
|   for (int err = f.first(); err == NOERR; err = f.next())
 | |
|   {        
 | |
|     _code.cut(0);
 | |
|     for (int i = f.tab() ? 1 :0; i < kd.NkFields; i++)   // Riempie la chiave selezionata
 | |
|     {                        
 | |
|       const int nf = kd.FieldSeq[i] % MaxFields;
 | |
|       const RecFieldDes& rf = recd->Fd[nf];  
 | |
|       const char* val = curr.get(rf.Name);
 | |
|       _code.add(val);
 | |
|     }
 | |
|     TObject* obj = rec2obj(curr);
 | |
|     _cache.add(_code, obj);
 | |
|   }
 | |
| 
 | |
|   // Non serve piu'
 | |
|   delete _file; _file = NULL;
 | |
|   
 | |
|   return _cache.items();
 | |
| }
 | |
|   
 | |
| void TFile_cache::destroy()
 | |
| {
 | |
|   _cache.destroy();
 | |
| }
 | |
| 
 | |
| TLocalisamfile & TFile_cache::file()
 | |
| {
 | |
|   if (_file == NULL)
 | |
|     init_file();
 | |
|   return *_file;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TDecoder
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| TDecoder::TDecoder(int num, const char* outf, int key)
 | |
|         : TFile_cache(num, key), _outf(outf)
 | |
| { }        
 | |
|  
 | |
| TDecoder::TDecoder(const char* tab, const char* outf, int key)
 | |
|         : TFile_cache(tab, key), _outf(outf)
 | |
| { }        
 | |
| 
 | |
| TObject* TDecoder::rec2obj(const TRectype& curr) const
 | |
| {
 | |
|   return new TString(curr.get(_outf));
 | |
| }
 | |
| 
 | |
| const TString& TDecoder::decode(const char* code)
 | |
| { 
 | |
|   const TString& obj = (const TString&)query(code);
 | |
|   return obj;
 | |
| }
 | |
| 
 | |
| const TString& TDecoder::decode(long code)
 | |
| {
 | |
|   char c[16]; 
 | |
|   if (code > 0)
 | |
|     sprintf(c, "%ld", code);
 | |
|   else
 | |
|     c[0] = '\0';
 | |
|   return decode(c);
 | |
| }  
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TRecord_cache
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| TRecord_cache::TRecord_cache(TLocalisamfile *f, int key)
 | |
|              : TFile_cache(f, key)
 | |
| { }        
 | |
| 
 | |
| TRecord_cache::TRecord_cache(int num, int key)
 | |
|              : TFile_cache(num, key)
 | |
| { }        
 | |
|  
 | |
| TRecord_cache::TRecord_cache(const char* tab, int key)
 | |
|              : TFile_cache(tab, key)
 | |
| { }        
 | |
| 
 | |
| TObject* TRecord_cache::rec2obj(const TRectype& curr) const
 | |
| {
 | |
|   return new TRectype(curr);
 | |
| }
 | |
| 
 | |
| const TRectype& TRecord_cache::get(const char* key)
 | |
| {
 | |
|   const TRectype& rec = (const TRectype&)query(key);
 | |
|   return rec;
 | |
| }  
 | |
| 
 | |
| const TString& TRecord_cache::get(const char* key, const char* field)
 | |
| {
 | |
|   return get(key).get(field);
 | |
| }  
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TDB_cache
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| TRecord_cache& TDB_cache::rec_cache(int file)
 | |
| {
 | |
|   CHECKD(file >= LF_USER, "Invalid file ", file);
 | |
|   TRecord_cache* rc = (TRecord_cache*)objptr(file);
 | |
|   if (rc == NULL)
 | |
|   {
 | |
|     rc = new TRecord_cache(file);
 | |
|     rc->set_items_limit(file==LF_TAB || file==LF_TABCOM ? 1024 : 256);
 | |
|     rc->test_file_changes();
 | |
|     add(rc, file);
 | |
|   }
 | |
|   return *rc;
 | |
| }
 | |
| 
 | |
| const TRectype& TDB_cache::get(const char* table, const char* key)
 | |
| {
 | |
|   CHECK(table && *table, "Invalid Table code");
 | |
| 
 | |
|   int file = LF_TAB;
 | |
|   if (*table == '%')
 | |
|   {
 | |
|     file = LF_TABCOM;
 | |
|     table++;
 | |
|   }
 | |
|   TString80 tabkey;
 | |
|   tabkey << table << '|' << key;
 | |
|   return get(file, tabkey);
 | |
| }
 | |
| 
 | |
| bool TDB_cache::discard(int file, const char* key)
 | |
| { 
 | |
|   return rec_cache(file).discard(key); 
 | |
| }
 | |
| bool TDB_cache::discard(const char *table, const char* key)
 | |
| {
 | |
|   CHECK(table && *table, "Invalid Table code");
 | |
| 
 | |
|   int file = LF_TAB;
 | |
|   if (*table == '%')
 | |
|   {
 | |
|     file = LF_TABCOM;
 | |
|     table++;
 | |
|   }
 | |
|   TString80 tabkey;
 | |
|   tabkey << table << '|' << key;
 | |
|   return rec_cache(file).discard(tabkey); 
 | |
| }
 | |
| 
 | |
| TDB_cache& cache()
 | |
| {
 | |
|   static TDB_cache* _frate_cercone = NULL;
 | |
|   if (_frate_cercone == NULL)
 | |
|     _frate_cercone = new TDB_cache;
 | |
|   return *_frate_cercone;
 | |
| }
 | |
| 
 | |
| TRecord_cache& rec_cache(int file) 
 | |
| { return cache().rec_cache(file); }
 |