campo-sirio/include/text.cpp
guy 76d2e43293 default.url Aggiunto supporto per l'italiano
printer.cpp    Vietao il registra di configurazioni utente
text.cpp       Modificati include inutili
text.h         Cambiati valori di un enum per compatibilita con release 4.5
viswin.cpp     Tolto bottone di chiusura
window.cpp     Aggiunti controlli sulla chiusura/distruzione delle finestre.


git-svn-id: svn://10.65.10.50/trunk@3804 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-10-21 10:42:45 +00:00

902 lines
22 KiB
C++
Executable File

#include <ctype.h>
#include <regexp.h>
#include <relation.h>
#include <text.h>
#include <window.h>
#include <xvtility.h>
static char TEXT_TMP[513];
class _HotSpot : public TObject
{
public:
// TArray _spots; // tokenstrings
char _bg, _fg;
_HotSpot (char fg, char bg)
{
_fg = fg;
_bg = bg;
}
virtual ~ _HotSpot ()
{
}
};
// @doc EXTERNAL
// @mfunc Permette di settare gli hot_spot
void TTextfile::set_hotspots (
char fg, // @parm Colore di foreground da utilizzare per l'hotspot
char bg) // @parm Colore di background da utilizzare per l'hotspot
// @comm Aggiunge all'array gli hotspots relativi alla pagina in memoria
// (come <c TToken_string> con x<pipe>y<pipe>text)
{
_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()
{
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+");
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);
}
}
}
}
// @doc EXTERNAL
// @mfunc Legge il testo formattato
void TTextfile::read_line (
long n, // @parm Numero della linea da leggere
long pos, // @parm Numero della colonna da leggere (mai utilizzata)
bool pg) // @parm Fa si' che se la linea non e' nella pagina corrente non si faccia nulla,
// diversamente rilegge una nuova pagina dal file.
{
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++;
bool terminated = FALSE;
while ((ch = *sp++) != '>' && !terminated)
if (ch != '\0')
id << ch;
else terminated = TRUE;
if (terminated) break; // Esce dal ciclo se non trova la matching >
// 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();
TString txt(512);
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;
}
// @doc EXTERNAL
// @mfunc Ritorna la stringa di caratteri senza formattazione
//
// @rdesc Ritorna la stringa di caratteri ed eventualmente con i campi sostituiti
// se la relazione non e' NULL
const char *TTextfile::line(
long j, // @parm Riga di cui ritornare la stringa
long pos, // @parm Colonna di cui ritornare la stringa
int howmuch) // @parm Numero di caratteri utili della stringa da ritornare (default -1)
// @comm Se <p howmuch> assume valore -1 ritorna tutta la pagina
{
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]) : "";
}
// @doc EXTERNAL
// @mfunc Cerca una stringa di testo all'interno di una riga
//
// @rdesc Ritorna la posizione in cui e' stato rintracciato il testo. Ritorna -1 se non e' stato
// trovato il testo passato.
long TTextfile::search(
const char* txt, // @parm Testo da cercare
int& ret, // @parm Intero in cui posizionare la posizne del carattere
long from, // @parm Posizione all'interno della riga da cui iniziare la ricerca (default 0)
bool down, // @parm Indica se la ricerca va effettuata all'indietro:
//
// @flag TRUE | Ricerca dalla posizione indicata all'inizio della riga (default)
// @flag FALSE | Ricerca dalla posizione indicata alla fine della riga
bool casesens, // @parm Indica se ricerca il testo con criterio case sensitive (default FALSE)
bool regexp) // @parm indica se considerare la stringa un'espressione regolare (def. FALSE)
// @comm Cerca in una riga per volta rispettando i formati
{
TString lin(512); TString80 text(txt);
if (!casesens)
text.lower();
for (long i = from; down ? (i < lines()) : (i >= 0); down ? i++ : i--)
{
lin = line(i);
if (regexp)
{
if (match(txt, lin))
return i;
}
else
{
if (!casesens) lin.lower();
if ((ret = lin.find(text)) != -1)
return i;
}
}
return -1l;
}
// @doc EXTERNAL
// @mfunc Sostituisce un testo all'interno di una riga
//
// @rdesc Ritorna la posizione in cui e' stato sostituito il testo. Ritorna -1 se non e' stata
// fatto nessuna operazione di sostituzione.
int TTextfile::replace(
long l, // @parm Numero della riga nella quale sostituire il testo
const char* txt, // @parm Test da inserire nella riga
int pos, // @parm Posizione nella quale inserire il testo (default 0)
int len) // @parm Lunghezza del testo da sostituire (default 0)
{
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;
}
// @doc EXTERNAL
// @mfunc Ritorna la stringa di caratteri con la formattazione
//
// @rdesc La stringa ritornata ha la formattazione (ovvere tutti i @codes, in modo che anche
// la printer la possa utilizzare)
const char *TTextfile::line_formatted(
long j) //parm Numero della riga da ritornare
{
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;
}
// @doc EXTERNAL
// @mfunc Ritorna lo stile del piece
//
// @rdesc Ritorna un numero (vedi <t style>) indicante lo stile
int TTextfile::get_style (
int pos) // @parm Posizione del carattere di cui ritornare lo stile (default -1)
// @comm Se viene passato a <p pos> valore -1 ritorna lo stile di tutta la piece, altrimente
// solamente quello del carattere selezionato.
{
const long x = get_attribute(pos) & ~tabbed;
return (int) (x & 0x0000ffff);
}
// @doc EXTERNAL
// @mfunc Ritorna il colore di background del piece
//
// @rdesc Ritorna il codice del colore, NULL se il carattere non esiste
char TTextfile::get_background (
int pos) // @parm Posizione del carattere di cui conoscere il colore di background (default -1)
// @comm Se <p pos> e' minore di 0 ritorna il colore dell'intero piece, altrimenti solamente
// quello del carattere selezionato.
//
// @xref <mf TTextfile::get_foreground>
{
long x = get_attribute (pos);
return (char) (x >> 24);
}
// @doc EXTERNAL
// @mfunc Ritorna il colore di foreground del piece
//
// @rdesc Ritorna il codice del colore, NULL se il carattere non esiste
char TTextfile::get_foreground (
int pos) // @parm Posizione del carattere di cui conoscere il colore di background (default -1)
// @comm Se <p pos> e' minore di 0 ritorna il colore dell'intero piece, altrimenti solamente
// quello del carattere selezionato.
//
// @xref <mf TTextfile::get_bakcground>
{
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);
}
// @doc EXTERNAL
// @mfunc Ritorna la parola alla posizione indicata
//
// @rdesc Stringa indicante la parola cercate
const char *TTextfile::word_at (
long x, // @parm Numero della parola da ritornare
long y) // @parm Numero della linea su cui cercare la parole
{
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;
}
// @doc EXTERNAL
// @mfunc Aggiunge una riga al text (con i formati del caso)
//
// @rdesc Ritorna il risultato dell'operazione:
//
// @flag TRUE | Se la riga e' stat aggiuntac correttamente
// @flag FALSE | Se non e' riuscot ad aggiungere la riga
bool TTextfile::append (
const char *l) // @parm Riga da aggiungere
{
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
}
// @doc EXTERNAL
// @mfunc Scrive il testo (non formattato) su file
//
// @rdesc Ritorna il risultato dell'operazione di scrittura
//
// @flag TRUE | Se e' riuscito a scrivere il testo
// @flag FALSE | Se ha avuto qualche problema nella gestione del file in cui scrivere
bool TTextfile::write (
const char *path, // @parm Nome del file in cui scrivere il testo
TPoint * from, // @parm Punto da cui iniziare a scrivere il testo
TPoint * to) // @parm Punto a cui terminare di scrivere il testo
{
bool ok = FALSE;
FILE *fp;
if ((fp = fopen (path, "w")) != NULL)
{
ok = TRUE;
TString s(512);
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;
}
// @doc EXTERNAL
// @mfunc Scrive il testo da punto a punto (non formattato) su string_array
void TTextfile::write(
TString_array& arr, // @parm Array in cui scrivere il testo
TPoint * from, // @parm Punto da cui iniziare a scrivere il testo
TPoint * to) // @parm Punto a cui terminare di scrivere il testo
{
arr.destroy();
TString s(512);
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);
arr.add(s);
}
}
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);
}