#include #include #include #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; }