#include #include #include #include static char mytmpstr[257]; class _HotSpot : public TObject { public: // TArray _spots; // tokenstrings char _bg, _fg; _HotSpot (char fg, char bg) { _fg = fg; _bg = bg; } virtual ~ _HotSpot () { } }; void TTextfile::set_hotspots (char fg, char bg) { _HotSpot *hp = new _HotSpot (fg, bg); _hotspots.add (hp); } style TTextfile::_trans_style (char ch) { switch (ch) { case 'r': return normal; break; case 'i': return italic; break; case 'b': return bold; break; case 'u': return underlined; break; default: return normal; break; } } void TTextfile::_save_changes() { main_app().begin_wait(); // fa i dovuti replace anche sul disco (solo replace di linee esistenti) long line = 0l; fclose(_index); remove(_indname); TString oldfile(_filename); _filename.temp("txtf"); FILE* newf = fopen(_filename, "a+"); if ((_index = fopen(_indname, "w+b")) == NULL || newf == NULL) { yesnofatal_box ("Impossibile aprire files temporanei"); freeze(); return; } fseek(_instr, 0l, SEEK_SET); while (!feof(_instr)) { const long l = ftell(newf); fwrite (&l, sizeof(long), 1, _index); if (ferror(_index) || ferror(newf)) { error_box ("Errore di scrittura file temporaneo: scrittura interrotta"); freeze (); } if (fgets(mytmpstr, sizeof(mytmpstr), _instr) == NULL) break; if (line >= _page_start && line <= _page_end) { TString& lin = (TString&)(_page[(int)(line - _page_start)]); if (_dirty_lines[line - _page_start]) { strcpy(mytmpstr, lin); strcat(mytmpstr, "\n"); } } fprintf(newf, "%s", mytmpstr); line++; } fflush(_index); fclose(_instr); fclose(newf); remove(oldfile); rename(_filename, oldfile); _filename = oldfile; _instr = fopen(_filename, "a+"); main_app().end_wait(); } void TTextfile::_read_page (long n) { if (_dirty_lines.ones() > 0l) { _save_changes(); _dirty_lines.reset(); } switch (_direction) { case down: _page_start = n; break; case up: _page_start = n + _page_size; break; case updown: _page_start = n - (_page_size / 2l); break; } if (_page_start < 0l) _page_start = 0l; if ((_page_start + _page_size) > _lines) _page_end = _lines - 1; else _page_end = _page_start + _page_size - 1; // zap hotspots _spots.destroy (); long l = 0l; fseek (_index, _page_start * (long) sizeof (long), SEEK_SET); if (_page_start != 0l) fread (&l, sizeof (long), 1, _index); fseek (_instr, l, SEEK_SET); for (long i = _page_start; i <= _page_end; i++) { if (feof (_instr)) break; fgets (mytmpstr, sizeof (mytmpstr), _instr); mytmpstr[strlen (mytmpstr) - 1] = '\0'; TString & ts = (TString &) _page[(int) (i - _page_start)]; ts = mytmpstr; TString hcol (6); // find hotspots and compile list int len = 0; const char *cp; read_line (i, 0, FALSE); while (cp = piece ()) { for (int z = 0; z < _hotspots.items (); z++) { _HotSpot & hs = (_HotSpot &) _hotspots[z]; if (hs._fg == get_foreground () && hs._bg == get_background ()) { TToken_string *tts = new TToken_string (50); tts->add (i); // line number tts->add (len); tts->add (len + (int) strlen (cp)); tts->add (cp); tts->add (z); _spots.add (tts); break; } } len += strlen (cp); } } } void TTextfile::read_line (long n, long pos, bool pg) { CHECK (_isopen, "Attempt operation on closed file"); CHECKD (n >= 0 && n < _lines, "Line not present", n); if (pg && !_in_page (n)) _read_page (n); TString *tp = (TString *) _page.objptr (int (n - _page_start)); if (tp == NULL) return; const char *sp = (const char *) (*tp); _item = 0; _line = ""; int ndx = 0, p = 0; bool first = TRUE; _cur_line = n; char ch; int col = ((int) 'w' << 8) | (int) 'n'; long stl = (long) col << 16; while (ch = *sp++) { if (ch == '@' || (ch == '$' && *(sp) == '[')) { if (!first && p >= pos) { _styles[_item++] = stl; mytmpstr[ndx] = '\0'; _line.add (mytmpstr); ndx = 0; } while (ch && (ch == '@' || (ch == '$' && *sp == '['))) { if (ch == '@') // font style change ? { style sss = _trans_style (*sp++); if (sss == normal) stl = (long) col << 16; else stl |= (long) sss; } else if (ch == '$' && *sp == '[') // color change { ++sp; // eat '[' col = *sp++; ++sp; // eat ',' col |= ((int) (*sp++) << 8); ++sp; // eat ']' stl = (stl & 0x0000ffff) | ((long) col << 16); } ch = *sp++; } // while } if (ch && p >= pos) { first = FALSE; mytmpstr[ndx++] = ch; } p++; } _styles[_item++] = stl; mytmpstr[ndx] = '\0'; _line.add(mytmpstr); _item = 0; } const char *TTextfile::line(long j, long pos, int howmuch) { if (_cur_line != j) read_line (j); *mytmpstr = '\0'; _line.restart (); for (int i = 0; i < _line.items (); i++) strcat (mytmpstr, (const char *) _line.get ()); if (howmuch != -1) { if (((unsigned int)pos+howmuch) < strlen(mytmpstr)) mytmpstr[pos+howmuch] = '\0'; } return strlen(mytmpstr) > (word)pos ? &(mytmpstr[pos]) : ""; } long TTextfile::search(const char* txt, int& ret, long from, bool down, bool casesens) { TString256 lin; TString80 text(txt); if (!casesens) text.lower(); for (long i = from; down ? (i < lines()) : (i >= 0); down ? i++ : i--) { lin = line(i); if (!casesens) lin.lower(); if ((ret = lin.find(text)) != -1) return i; } return -1l; } int TTextfile::replace(long l, const char* txt, int pos, int len) { if (_cur_line != l) read_line(l); TString& line = (TString&)_page[int(l-_page_start)]; char ch; int i = 0, cnt = 0, skip = 0; bool sforating = FALSE; // here's a nice casin while(i < 256) { if (!sforating) { ch = line[i++]; if (ch == '\0') sforating = TRUE; else if (ch == '@' && strchr("ribuok",line[i]) != NULL) { skip +=2; i++; } else if (ch == '$' && line[i] == '[') { skip +=3; i++; while(line[i++] != ']') if (line[i] == '\0') return -1; else skip++; } } if (cnt == pos) { line.overwrite(txt, cnt+skip); _dirty_lines.set(l-_page_start); return cnt; } else cnt++; } return -1; } const char *TTextfile::line_formatted(long j) { if (_cur_line != j) read_line (j); TString* tp = (TString*)_page.objptr(int(j-_page_start)); strcpy(mytmpstr, (const char*)(*tp)); return mytmpstr; } long TTextfile::get_attribute (int pos) { long stl = 0; if (pos == -1) { CHECK (_item > 0, "must execute piece() before style()!"); stl = _styles[_item - 1]; } else { int x = 0, nd = 0; const char *c; _line.restart (); while (c = _line.get ()) { x += strlen (c); stl = _styles[nd++]; if ((x - 1) >= pos) break; } } return stl; } int TTextfile::get_style (int pos) { long x = get_attribute (pos); return (int) (x & 0x0000ffff); } char TTextfile::get_background (int pos) { long x = get_attribute (pos); return (char) (x >> 24); } char TTextfile::get_foreground (int pos) { long x = get_attribute (pos); return (char) ((x >> 16) & 0x000000ff); } const char *TTextfile::piece () { if (_item >= _line.items ()) return NULL; return strcpy (mytmpstr, (const char *) _line.get (_item++)); } const char *TTextfile::word_at (long x, long y) { CHECK (_isopen, "Attempt operation on closed file"); TString s (line (y)); int x2 = 0; if (x < s.len ()) { while (isspace (s[(int) x])) { if (x == (s.len () - 1) && y < (_lines - 1l)) { s = line (++y); x = 0l; } else if (x < (s.len () - 1)) x++; else break; } while (isalnum (s[(int) x])) mytmpstr[x2++] = s[(int) x++]; } mytmpstr[x2] = '\0'; return mytmpstr; } bool TTextfile::append (const char *l) { CHECK (_isopen, "Attempt operation on closed file"); if (!_accept) return FALSE; fseek (_instr, 0l, SEEK_END); fseek (_index, 0l, SEEK_END); long cpos = ftell (_instr); fprintf (_instr, "%s\n", l); fwrite (&cpos, sizeof (long), 1, _index); if (ferror (_index) || ferror (_instr)) { error_box ("Errore di scrittura file temporaneo: scrittura interrotta"); freeze (); } fflush (_index); fflush (_instr); _lines++; _dirty = TRUE; if ((_lines) < (_page_start + _page_size)) { TString *ll = new TString (l); _page.add (ll); _page_end++; int len = 0; const char *cp; read_line (_lines - 1); while (cp = piece ()) { for (int z = 0; z < _hotspots.items (); z++) { _HotSpot & hs = (_HotSpot &) _hotspots[z]; if (hs._fg == get_foreground () && hs._bg == get_background ()) { TToken_string *tts = new TToken_string (50); tts->add (_lines - 1l); // line number // tts->add (len); tts->add (len + (int) strlen (cp)); tts->add (cp); tts->add (z); _spots.add (tts); break; } } len += strlen (cp); } return TRUE; } return FALSE; } void TTextfile::close () { CHECK (_isopen,"Attempt operation on closed file"); fclose (_instr); fclose (_index); _instr = _index = NULL; _isopen = FALSE; } void TTextfile::print () { CHECK (_isopen, "Attempt operation on closed file"); warning_box ("Funzione non ancora implementata"); // TBI istanzia una printer inibendo la scelta di video // add all lines (maybe new method: print_txt) // print } bool TTextfile::write (const char *path, TPoint * from, TPoint * to) { bool ok = FALSE; FILE *fp; if ((fp = fopen (path, "w")) != NULL) { ok = TRUE; TString256 s; long starty = from == NULL ? 0l : from->y; int startx = from == NULL ? 0 : (int) from->x; long endy = to == NULL ? _lines - 1l : to->y; int endx = to == NULL ? -1 : (int) to->x; for (long j = starty; j <= endy; j++) { s = line (j); if (j == endy && endx == -1) endx = s.len (); if (j == starty && j == endy) s = s.sub (startx, endx); else if (j == starty) s = s.mid (startx); else if (j == endy) s = s.left (endx); fprintf (fp, "%s\n", (const char *) s); } fclose (fp); } else warning_box ("Impossibile scrivere il file %s; scrittura fallita", path); return ok; } void TTextfile::destroy () { CHECK (_istemp, "destroy() chiamata su testo permanente!"); if (_page.items () > 0) { if (_index) fclose (_index); if (_instr) fclose (_instr); remove ((const char *) _filename); remove ((const char *) _indname); _page_start = _lines = 0l; _page_end = _cur_line = -1l; _accept = TRUE; _instr = fopen (_filename, "a+"); _indname.temp (); _index = fopen (_indname, "w+b"); if (_index == NULL || _instr == NULL) { error_box ("Impossibile aprire files temporanei"); freeze (); } _isopen = TRUE; _page.destroy (); _spots.destroy (); } } TTextfile ::TTextfile (const char *file, int pagesize, direction preferred): _page_size (pagesize), _page (pagesize), _filename (file), _lines (0l), _index (NULL), _page_start (0l), _page_end (-1l), _direction (preferred), _dirty (FALSE), _istemp (FALSE), _item (0), _line (256), _cur_line (-1), _hotspots (4), _accept (TRUE), _dirty_lines(pagesize) { // open file & build index if (file == NULL || *file <= ' ') { _filename.temp("txtf"); _istemp = TRUE; } _isopen = TRUE; _instr = fopen (_filename, "a+"); _indname.temp("txti"); _index = fopen (_indname, "w+b"); if (_index == NULL || _instr == NULL) { yesnofatal_box ("Impossibile aprire files temporanei"); freeze (); } if (!_istemp) while (!feof(_instr)) { const long l = ftell (_instr); fwrite (&l, sizeof (long), 1, _index); if (ferror(_index) || ferror(_instr)) { error_box("Errore di scrittura file temporaneo: scrittura interrotta"); freeze(); } if (fgets (mytmpstr, sizeof (mytmpstr), _instr) == NULL) break; if (mytmpstr[strlen(mytmpstr)-1] == '\n') mytmpstr[strlen(mytmpstr)-1] = '\0'; if ((_lines) < (_page_start + _page_size)) { TString *ll = new TString (mytmpstr); _page.add(ll); _page_end++; // TBI process links } _lines++; } } TTextfile::~TTextfile () { if (_index) fclose (_index); if (_instr) fclose (_instr); if (_istemp) remove ((const char *) _filename); remove ((const char *) _indname); }