b28b209af4
ne' meno che mai funzionanti git-svn-id: svn://10.65.10.50/trunk@1493 c028cbd2-c16b-5b4b-a496-9718f37d4682
739 lines
16 KiB
C++
Executable File
739 lines
16 KiB
C++
Executable File
#include <text.h>
|
|
#include <fstream.h>
|
|
#include <ctype.h>
|
|
#include <applicat.h>
|
|
|
|
static char TEXT_TMP[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;
|
|
case 'i':
|
|
return italic;
|
|
case 'b':
|
|
return bold;
|
|
case 'u':
|
|
return underlined;
|
|
case 't':
|
|
return tabbed;
|
|
default:
|
|
return normal;
|
|
}
|
|
}
|
|
|
|
|
|
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(TEXT_TMP, sizeof(TEXT_TMP), _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(TEXT_TMP, lin);
|
|
strcat(TEXT_TMP, "\n");
|
|
}
|
|
}
|
|
|
|
fprintf(newf, "%s", TEXT_TMP);
|
|
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 (TEXT_TMP, sizeof (TEXT_TMP), _instr);
|
|
TEXT_TMP[strlen (TEXT_TMP) - 1] = '\0';
|
|
TString & ts = (TString &) _page[(int) (i - _page_start)];
|
|
ts = TEXT_TMP;
|
|
if (_interactive)
|
|
{
|
|
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 == '<' && *(sp) == '@')
|
|
{
|
|
// merge field if rel != NULL;
|
|
// else fill with whitespace
|
|
TToken_string id(80, '@');
|
|
sp++;
|
|
while ((ch = *sp++) != '>')
|
|
id << ch;
|
|
// id contains tokenstring separated by @
|
|
// but with casinations for possible lack of spacing
|
|
// add spaces if needed
|
|
for (int i = 0; i < id.len(); i++)
|
|
{
|
|
if (id[i] == '@' && id [i+1] == '@')
|
|
{
|
|
id.insert(" ", i+1);
|
|
i+= 2;
|
|
}
|
|
}
|
|
// parse string
|
|
int len;
|
|
TString80 file;
|
|
TString16 field;
|
|
TString80 format;
|
|
char just;
|
|
|
|
file = id.get();
|
|
format = id.get();
|
|
len = (int)id.get_long();
|
|
just = id.get_char();
|
|
|
|
int pos = 0;
|
|
if ((pos = file.find("->")) == -1)
|
|
error_box("field specification error");
|
|
else
|
|
{
|
|
file.cut(pos);
|
|
field = file.mid(pos+2);
|
|
}
|
|
|
|
if (len == 0) len = id.len();
|
|
|
|
TString256 txt;
|
|
TFieldtypes type;
|
|
|
|
if (_rel != NULL)
|
|
{
|
|
// retrieve file and field
|
|
if (atoi(file) == 0)
|
|
{
|
|
// tabella
|
|
TLocalisamfile& t = _rel->lfile(file);
|
|
txt = t.get(field);
|
|
type = t.curr().type(field);
|
|
}
|
|
else
|
|
{
|
|
TLocalisamfile& f = _rel->lfile(atoi(file));
|
|
txt = f.get(field);
|
|
type = f.curr().type(field);
|
|
}
|
|
// apply format to date and number
|
|
switch (type)
|
|
{
|
|
case _longfld:
|
|
case _realfld:
|
|
{
|
|
real r(txt);
|
|
txt = r.string(format);
|
|
}
|
|
break;
|
|
case _datefld:
|
|
{
|
|
TDate dd(txt);
|
|
TFormatted_date d(dd, format);
|
|
txt = d.string();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// justify as requested
|
|
if (txt.len() < len)
|
|
{
|
|
switch(type)
|
|
{
|
|
case _longfld:
|
|
case _realfld:
|
|
txt.right_just(len);
|
|
break;
|
|
default:
|
|
txt.left_just(len);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
txt.left_just(len);
|
|
}
|
|
// ficca il testo cola' dove si puote
|
|
for (int k = 0; k < txt.len(); k++)
|
|
TEXT_TMP[ndx++] = txt[k];
|
|
}
|
|
|
|
if (ch == '@' || (ch == '$' && *(sp) == '['))
|
|
{
|
|
if (!first && p >= pos)
|
|
{
|
|
_styles[_item++] = stl;
|
|
TEXT_TMP[ndx] = '\0';
|
|
_line.add (TEXT_TMP);
|
|
ndx = 0;
|
|
}
|
|
while (ch && (ch == '@' || (ch == '$' && *sp == '[')))
|
|
{
|
|
if (ch == '@') // font style change ?
|
|
{
|
|
const char c = *sp++;
|
|
|
|
style sss = _trans_style (c);
|
|
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;
|
|
TEXT_TMP[ndx++] = ch;
|
|
}
|
|
p++;
|
|
}
|
|
_styles[_item++] = stl;
|
|
TEXT_TMP[ndx] = '\0';
|
|
_line.add(TEXT_TMP);
|
|
_item = 0;
|
|
}
|
|
|
|
const char *TTextfile::line(long j, long pos, int howmuch)
|
|
{
|
|
if (_cur_line != j)
|
|
read_line (j);
|
|
*TEXT_TMP = '\0';
|
|
_line.restart ();
|
|
for (int i = 0; i < _line.items (); i++)
|
|
strcat (TEXT_TMP, (const char *) _line.get ());
|
|
if (howmuch != -1)
|
|
{
|
|
if (((unsigned int)pos+howmuch) < strlen(TEXT_TMP))
|
|
TEXT_TMP[pos+howmuch] = '\0';
|
|
}
|
|
return strlen(TEXT_TMP) > (word)pos ? &(TEXT_TMP[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("ribuokt",line[i]) != NULL)
|
|
{
|
|
skip +=2; i++; cnt--;
|
|
}
|
|
else if (ch == '$' && line[i] == '[')
|
|
{
|
|
skip +=3; i++; cnt--;
|
|
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(TEXT_TMP, (const char*)(*tp));
|
|
return TEXT_TMP;
|
|
}
|
|
|
|
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 ()) != NULL)
|
|
{
|
|
x += strlen (c);
|
|
stl = _styles[nd++];
|
|
if ((x - 1) >= pos)
|
|
break;
|
|
}
|
|
}
|
|
return stl;
|
|
}
|
|
|
|
int TTextfile::get_style (int pos)
|
|
{
|
|
const long x = get_attribute(pos) & ~tabbed;
|
|
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()
|
|
{
|
|
const char* l = _line.get(_item);
|
|
if (l == NULL)
|
|
return NULL;
|
|
_item++;
|
|
return strcpy(TEXT_TMP, l);
|
|
}
|
|
|
|
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]))
|
|
TEXT_TMP[x2++] = s[(int) x++];
|
|
}
|
|
TEXT_TMP[x2] = '\0';
|
|
return TEXT_TMP;
|
|
}
|
|
|
|
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))
|
|
{
|
|
if (_interactive)
|
|
{
|
|
_page.add (new TString(l), int(_lines - _page_start - 1));
|
|
_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,
|
|
bool interactive):
|
|
_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),
|
|
_interactive(interactive), _rel(NULL)
|
|
|
|
{
|
|
// open file & build index
|
|
if (file == NULL || *file <= ' ')
|
|
{
|
|
_filename.temp("txtf");
|
|
_istemp = TRUE;
|
|
}
|
|
for (int i = 0; i < pagesize; i++)
|
|
_page.add(new TString(132));
|
|
_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 (TEXT_TMP, sizeof (TEXT_TMP), _instr) == NULL)
|
|
break;
|
|
// if (TEXT_TMP[strlen(TEXT_TMP)-1] == '\n')
|
|
// TEXT_TMP[strlen(TEXT_TMP)-1] = '\0';
|
|
// if ((_lines) < (_page_start + _page_size))
|
|
// {
|
|
// TString *ll = new TString (TEXT_TMP);
|
|
// _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);
|
|
}
|