359 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <memo.h>
 | |
| #include <utility.h>
 | |
| #include <sys/locking.h>
 | |
| 
 | |
| #define HEADER_SIZE (sizeof(long)+sizeof(char))
 | |
| #define INFO_SIZE (sizeof(long)+sizeof(long)) 
 | |
| 
 | |
| // block size used in writes 
 | |
| // must not exceed sizeof(__tmp_string)
 | |
| #define BLOCK_SIZE (1024)
 | |
| // max allowed size for locking is 100k
 | |
| #define MAX_SIZE   (100000l)             
 | |
| 
 | |
| TMemo_file::TMemo_file(const char* a) : 
 | |
| _fname(a), _fp(NULL), _isnew(FALSE)
 | |
| { 
 | |
|   // handles: open file or create               
 | |
|   _fname.ext("mem");  
 | |
|   if (!(_fp = fopen(_fname,"rb+")))
 | |
|   {
 | |
|     _fp = fopen(_fname,"wb+");
 | |
|     _isnew = TRUE;
 | |
|   }
 | |
|   
 | |
|   if (_fp == NULL) 
 | |
|     error_box("File memo %s non creato per errori di disco", (const char *) _fname); 
 | |
| 
 | |
|   // read (write) header
 | |
|   if (_isnew)
 | |
|   {
 | |
|     _id_max = 0; 
 | |
|     fwrite(&_id_max, sizeof(long), 1, _fp);
 | |
|     char eof = 26;  // only to inhibit 'type'
 | |
|     fwrite(&eof, sizeof(char), 1, _fp);    
 | |
|   }
 | |
|   else
 | |
|     fread(&_id_max, sizeof(long), 1, _fp);
 | |
| }
 | |
| 
 | |
| TMemo_file::~TMemo_file()
 | |
| { 
 | |
|   if (_fp) fclose(_fp);
 | |
| }
 | |
| 
 | |
| bool TMemo_file::_find_id(long id)
 | |
| {                                
 | |
|   if (id > _id_max && id < 0)
 | |
|     error_box("File memo inconsistente");
 | |
|   
 | |
|   bool dndir = FALSE /* id > (_id_max/2l) */ ;
 | |
|   
 | |
|   _current = -1l; 
 | |
| 
 | |
|   long pos = dndir ? INFO_SIZE : HEADER_SIZE;
 | |
|   fseek(_fp, pos, dndir ? SEEK_END : SEEK_SET);
 | |
|   
 | |
|   int ok = 0;  
 | |
|   
 | |
|   while (_current < id)
 | |
|   {                                           
 | |
|     // se si va all'indietro, questa non funzia: nonostante
 | |
|     // fflush il file non e' tutto scritto su disco, e fread
 | |
|     // ritorna 0 lasciando tutto al valore precedente
 | |
|     // Perche'? Eh?
 | |
|     fread(&_current, sizeof(long), 1, _fp);  
 | |
|     fread(&_next_ofs, sizeof(long), 1, _fp);    
 | |
|     if (_current < id)                    
 | |
|     { 
 | |
|       long ofs =  dndir ? -_next_ofs-INFO_SIZE-INFO_SIZE :
 | |
|       _next_ofs+INFO_SIZE;
 | |
|       
 | |
|       ok = fseek(_fp, ofs, SEEK_CUR); 
 | |
|     }
 | |
|     if (ok) break;
 | |
|   }               
 | |
|   
 | |
|   _current = ok ? -1l : id;
 | |
|   return _current == id;
 | |
| }  
 | |
| 
 | |
| bool TMemo_file::get_field(TTextfile& t, long id)
 | |
| {          
 | |
|   bool ok = _find_id(id);
 | |
|   if (ok)
 | |
|   {
 | |
|     _current = id;
 | |
|     
 | |
|     // te lo faccio io, poi so' cazzi tua se sbagli
 | |
|     t.destroy();
 | |
|     
 | |
|     TString256 line;
 | |
|     
 | |
|     // block read until done; transfer block to txt 
 | |
|     // block by block
 | |
|     
 | |
|     long size = _next_ofs < BLOCK_SIZE ? _next_ofs : BLOCK_SIZE;  
 | |
|     int  lcnt = 0;
 | |
|     
 | |
|     for (long cnt = 0; cnt < _next_ofs; cnt += size)
 | |
|     {                               
 | |
|       if (fread(__tmp_string, sizeof(char), (int)size, _fp) != (size_t)size)
 | |
|         error_box("%s: unexpected end of file", (const char *) _fname);
 | |
| 
 | |
|       // move block into text
 | |
|       for(long j = 0; j <= size; j++)
 | |
|       {
 | |
|         char ch = j < size ? __tmp_string[j] : '\0';
 | |
|         if (ch == '\n' || j == size)
 | |
|         {
 | |
|           line[lcnt] = '\0';
 | |
|           t.append(line); 
 | |
|           lcnt = 0;
 | |
|         }
 | |
|         else line[lcnt++] = ch;
 | |
|       }
 | |
|       
 | |
|       // size of next read
 | |
|       size = cnt + size < BLOCK_SIZE ? _next_ofs - cnt : BLOCK_SIZE;   
 | |
|     }
 | |
|   }
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| long TMemo_file::set_field(TTextfile& t, long id)
 | |
| { 
 | |
|   bool ok = TRUE; 
 | |
|   long ret = 0;                                             
 | |
|   
 | |
|   // append se -1 o se l'ID e' maggiore dell'ultima presente
 | |
|   bool at_end = id == -1 || (id != -1 && id > _id_max);
 | |
|   // the casinating insertion in the middol
 | |
|   bool in_mid = FALSE;               
 | |
|   
 | |
|   if (!at_end) 
 | |
|   {    
 | |
|     ok = _find_id(id);     
 | |
|     if (!ok)
 | |
|     {
 | |
|       // va inserito al posto di uno scancellato
 | |
|       // vediamo dove
 | |
|       long pos = HEADER_SIZE;
 | |
|       fseek(_fp, pos, SEEK_SET);
 | |
|       
 | |
|       int ok = 0;  
 | |
|       
 | |
|       while (_current < id)
 | |
|       {                                          
 | |
|         fread(&_current,  sizeof(long), 1, _fp);  
 | |
|         fread(&_next_ofs, sizeof(long), 1, _fp);    
 | |
|         if (_current < id)                    
 | |
|         { 
 | |
|           long ofs = _next_ofs+INFO_SIZE;
 | |
|           ok = fseek(_fp, ofs, SEEK_CUR);  
 | |
|         }
 | |
|         else  
 | |
|         {         
 | |
|           // position the luridissim cazz at bighinnin 
 | |
|           // of privius bifor riding ids 
 | |
|           long oo = (long)INFO_SIZE * -1l;
 | |
|           fseek(_fp, oo, SEEK_CUR);
 | |
|           break;
 | |
|         }        
 | |
|         if (ok) error_box("file error in %s", (const char *) _fname);     
 | |
|         in_mid = TRUE;
 | |
|       }  
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   if (at_end)  // the easy case
 | |
|   {
 | |
|     if (id == -1) id = ++_id_max; 
 | |
|     // append test, update info
 | |
|     long cnt = 0l;
 | |
|     fseek(_fp, 0, SEEK_END);
 | |
|     
 | |
|     // lock file 
 | |
| #if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_NT
 | |
|     _locking(_fileno(_fp), _LK_LOCK, MAX_SIZE);
 | |
| #else
 | |
|     locking(fileno(_fp), LK_LOCK, MAX_SIZE);
 | |
| #endif
 | |
| 
 | |
|     fwrite(&id,  sizeof(long), 1, _fp);
 | |
|     // will overwrite later with byte count 
 | |
|     long cpos = ftell(_fp);
 | |
|     fwrite(&id,  sizeof(long), 1, _fp);
 | |
|     
 | |
|     TString256 line;
 | |
|     for (int i = 0; i < t.lines(); i++)
 | |
|     {
 | |
|       line = t.line(i);      
 | |
|       char c;
 | |
|       
 | |
|       for (int k = 0; c = line[k]; k++)
 | |
|       { 
 | |
|         fwrite(&c, sizeof(char), 1, _fp);  
 | |
|         cnt++;
 | |
|       }
 | |
|       if (i < t.lines() - 1)
 | |
|       {
 | |
|         c = '\n';
 | |
|         fwrite(&c, sizeof(char), 1, _fp);  
 | |
|         cnt++;
 | |
|       } 
 | |
|     } 
 | |
|     //                        
 | |
|     fwrite(&id,  sizeof(long), 1, _fp);
 | |
|     fwrite(&cnt, sizeof(long), 1, _fp);
 | |
|     // update count
 | |
|     fseek(_fp, cpos, SEEK_SET);
 | |
|     fwrite(&cnt, sizeof(long), 1, _fp);      
 | |
|     fseek(_fp, 0, SEEK_SET);
 | |
|     fwrite(&_id_max, sizeof(long), 1, _fp);     
 | |
|     
 | |
| #if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_NT
 | |
|     _locking(_fileno(_fp), _LK_UNLCK, MAX_SIZE);
 | |
| #else
 | |
|     locking(fileno(_fp), LK_UNLCK, MAX_SIZE);
 | |
| #endif
 | |
| 
 | |
|     
 | |
|     fflush(_fp);
 | |
|     ret = _find_id(id) ? id : -1;  
 | |
|   }   
 | |
|   else  // the rognous one
 | |
|   {
 | |
|     long to   = ftell(_fp) - INFO_SIZE;
 | |
|     long from = in_mid ? to : to + _next_ofs + (2*INFO_SIZE); 
 | |
|     
 | |
|     TFilename tmp; tmp.temp();                   
 | |
|     FILE* tfp = fopen(tmp, "wb+");
 | |
| 
 | |
|     fseek(_fp, 0, SEEK_SET);   
 | |
|     
 | |
|     long size = BLOCK_SIZE;   
 | |
|     bool stop = FALSE;
 | |
|     
 | |
|     // copy file into temp up to TO pos               
 | |
|     // use 1k blocks for speed
 | |
|     for (int i = 0; !stop; i++)
 | |
|     {
 | |
|       if (to < (BLOCK_SIZE * (i+1)))
 | |
|       {
 | |
|         size = to - i*BLOCK_SIZE;   
 | |
|         stop = TRUE;
 | |
|       }
 | |
|       fread (__tmp_string, sizeof(char), (int)size, _fp); 
 | |
|       fwrite(__tmp_string, sizeof(char), (int)size, tfp); 
 | |
|     }                        
 | |
|     
 | |
|     // write new text and update info
 | |
|     fwrite(&id,  sizeof(long), 1, tfp);
 | |
|     // will overwrite later with byte count 
 | |
|     long cpos = ftell(tfp);
 | |
|     fwrite(&id,  sizeof(long), 1, tfp);
 | |
|     
 | |
|     TString256 line; long cnt = 0l;
 | |
|     for (i = 0; i < t.lines(); i++)
 | |
|     {
 | |
|       line = t.line(i);      
 | |
|       char c;
 | |
|       
 | |
|       for (int k = 0; c = line[k]; k++)
 | |
|       { 
 | |
|         fwrite(&c, sizeof(char), 1, tfp);  
 | |
|         cnt++;
 | |
|       }
 | |
|       if (i < t.lines() - 1)
 | |
|       {
 | |
|         c = '\n';
 | |
|         fwrite(&c, sizeof(char), 1, tfp);  
 | |
|         cnt++;
 | |
|       } 
 | |
|     } 
 | |
|     //                        
 | |
|     fwrite(&id,  sizeof(long), 1, tfp);
 | |
|     fwrite(&cnt, sizeof(long), 1, tfp);  
 | |
|     
 | |
|     // write the rest of the file  
 | |
|     stop = FALSE; 
 | |
|     fseek(_fp, from, SEEK_SET);
 | |
|     for (i = 0; !stop; i++)
 | |
|     {
 | |
|       int size = fread (__tmp_string, sizeof(char), BLOCK_SIZE, _fp); 
 | |
|       if (size) fwrite(__tmp_string, sizeof(char), size, tfp);     
 | |
|       stop = size < BLOCK_SIZE;
 | |
|     }
 | |
|     
 | |
|     // update count
 | |
|     fseek(tfp, cpos, SEEK_SET);
 | |
|     fwrite(&cnt, sizeof(long), 1, tfp);
 | |
|     fclose(tfp);
 | |
|     // move files
 | |
|     fclose(_fp);
 | |
|     fcopy(tmp, _fname);
 | |
|     remove(tmp);
 | |
|     _fp = fopen(_fname, "rb+");
 | |
|     ret = _find_id(id) ? 0 : -1;
 | |
|   } 
 | |
|   
 | |
|   _dirty = TRUE;
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| bool TMemo_file::remove_field(long id)
 | |
| {             
 | |
|   bool ok = _find_id(id);
 | |
|   if (ok)
 | |
|   {        
 | |
|     long to   = ftell(_fp) - INFO_SIZE;
 | |
|     long from = to + _next_ofs + (2*INFO_SIZE); 
 | |
| 
 | |
|     TFilename tmp; tmp.temp();                   
 | |
|     FILE* tfp = fopen(tmp, "wb+");
 | |
| 
 | |
|     fseek(_fp, 0, SEEK_SET);   
 | |
|     
 | |
|     long size = BLOCK_SIZE;   
 | |
|     bool stop = FALSE;
 | |
|     
 | |
|     // copy file into temp up to TO pos               
 | |
|     // use 1k blocks for speed
 | |
|     for (int i = 0; !stop; i++)
 | |
|     {
 | |
|       if (to < (BLOCK_SIZE * (i+1)))
 | |
|       {
 | |
|         size = to - i*BLOCK_SIZE;   
 | |
|         stop = TRUE;
 | |
|       }
 | |
|       fread (__tmp_string, sizeof(char), (int)size, _fp); 
 | |
|       fwrite(__tmp_string, sizeof(char), (int)size, tfp); 
 | |
|     }
 | |
|     // write the rest of the file  
 | |
|     stop = FALSE; 
 | |
|     fseek(_fp, from, SEEK_SET);
 | |
|     for (i = 0; !stop; i++)
 | |
|     {
 | |
|       int size = fread (__tmp_string, sizeof(char), BLOCK_SIZE, _fp); 
 | |
|       if (size) fwrite(__tmp_string, sizeof(char), size, tfp);     
 | |
|       stop = size < BLOCK_SIZE;
 | |
|     }
 | |
|     
 | |
|     // move files
 | |
|     fclose(tfp);
 | |
|     fclose(_fp);
 | |
|     fcopy(tmp, _fname);
 | |
|     remove(tmp);
 | |
|     _fp = fopen(_fname, "rb+");
 | |
|   }
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool TMemo_file::edit_field(long id)  
 | |
| {          
 | |
|   return TRUE;
 | |
| }
 |