2016-09-09 13:58:28 +00:00
|
|
|
|
#include <printer.h>
|
|
|
|
|
#include <relation.h>
|
|
|
|
|
#include <text.h>
|
|
|
|
|
#include <window.h>
|
|
|
|
|
#include <xvtility.h>
|
|
|
|
|
|
|
|
|
|
#define TEXT_TMP_SIZE 1024
|
|
|
|
|
static TString _TEXT_TMP(TEXT_TMP_SIZE);
|
|
|
|
|
static char* TEXT_TMP = (char*)(const char*)_TEXT_TMP;
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
|
|
|
|
TWait_cursor hourglass;
|
|
|
|
|
|
|
|
|
|
// fa i dovuti replace anche sul disco (solo replace di linee esistenti)
|
|
|
|
|
long line = 0l;
|
|
|
|
|
|
|
|
|
|
fclose(_index);
|
|
|
|
|
remove(_indname);
|
|
|
|
|
|
|
|
|
|
const TString oldfile(_filename);
|
|
|
|
|
_filename.temp("txtf");
|
|
|
|
|
|
|
|
|
|
FILE* newf = fopen(_filename, "a+");
|
|
|
|
|
|
|
|
|
|
if ((_index = fopen(_indname, "w+b")) == NULL || newf == NULL)
|
|
|
|
|
{
|
|
|
|
|
NFCHECK("Impossibile aprire files temporanei");
|
|
|
|
|
freeze();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fseek(_instr, 0l, SEEK_SET);
|
|
|
|
|
rewind(_instr);
|
|
|
|
|
|
|
|
|
|
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, TEXT_TMP_SIZE, _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+");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
if (_page_start != 0l)
|
|
|
|
|
{
|
|
|
|
|
fseek (_index, _page_start * (long) sizeof (long), SEEK_SET);
|
|
|
|
|
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, TEXT_TMP_SIZE, _instr);
|
|
|
|
|
TEXT_TMP[strlen (TEXT_TMP) - 1] = '\0';
|
|
|
|
|
TString & ts = (TString &) _page[(int) (i - _page_start)];
|
|
|
|
|
CHECK(ts.size() > 0, "Corrupted string");
|
|
|
|
|
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
|
|
|
|
|
const char * save_sp = sp;
|
|
|
|
|
|
|
|
|
|
TToken_string id(80, '@');
|
|
|
|
|
sp++;
|
|
|
|
|
bool terminated = FALSE;
|
|
|
|
|
while ((ch = *sp++) != '>' && !terminated)
|
|
|
|
|
if (ch != '\0')
|
|
|
|
|
id << ch;
|
|
|
|
|
else terminated = TRUE;
|
|
|
|
|
if (!terminated) // Prosegue normalmente 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
|
|
|
|
|
const int txtlen = txt.len();
|
|
|
|
|
for (int k = 0; k < txtlen; k++)
|
|
|
|
|
TEXT_TMP[ndx++] = txt[k];
|
|
|
|
|
} // see (!terminated) above
|
|
|
|
|
else // Restore sp pointer
|
|
|
|
|
{
|
|
|
|
|
sp = save_sp;
|
|
|
|
|
ch = '<';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ch == '@' || (ch == '$' && *(sp) == '['))
|
|
|
|
|
{
|
|
|
|
|
if (!first && p >= pos)
|
|
|
|
|
{
|
|
|
|
|
CHECKD(ndx < TEXT_TMP_SIZE, "Bad TEXT_TMP index ", ndx);
|
|
|
|
|
_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++;
|
|
|
|
|
if (c == '@')
|
|
|
|
|
{
|
|
|
|
|
_styles[_item++] = stl;
|
|
|
|
|
_line.add("@");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
CHECKD(ndx < TEXT_TMP_SIZE, "Bad TEXT_TMP index ", ndx);
|
|
|
|
|
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';
|
|
|
|
|
FOR_EACH_TOKEN(_line, l)
|
|
|
|
|
strcat (TEXT_TMP, l);
|
|
|
|
|
|
|
|
|
|
if (howmuch >= 0)
|
|
|
|
|
{
|
|
|
|
|
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 text(txt);
|
|
|
|
|
if (!casesens)
|
|
|
|
|
text.lower();
|
|
|
|
|
if (regexp && !text.ends_with("*"))
|
|
|
|
|
text << '*';
|
|
|
|
|
|
|
|
|
|
TString lin(512);
|
|
|
|
|
for (long i = from; down ? (i < lines()) : (i >= 0); down ? i++ : i--)
|
|
|
|
|
{
|
|
|
|
|
lin = line(i);
|
|
|
|
|
if (!casesens)
|
|
|
|
|
lin.lower();
|
|
|
|
|
if (regexp)
|
|
|
|
|
{
|
|
|
|
|
for (ret = 0; lin[ret]; ret++)
|
|
|
|
|
{
|
|
|
|
|
if (lin.mid(ret).match(text))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = lin.find(text);
|
|
|
|
|
if (ret >= 0)
|
|
|
|
|
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
|
2020-06-17 10:22:27 +02:00
|
|
|
|
// @flag FALSE | Se non e' riuscito ad aggiungere la riga
|
2016-09-09 13:58:28 +00:00
|
|
|
|
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 ()
|
|
|
|
|
{
|
|
|
|
|
if (_isopen)
|
|
|
|
|
{
|
|
|
|
|
fclose (_instr);
|
|
|
|
|
fclose (_index);
|
|
|
|
|
_instr = _index = NULL;
|
|
|
|
|
_isopen = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TTextfile::print ()
|
|
|
|
|
{
|
|
|
|
|
printer().print_txt(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// @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
|
2017-05-23 17:46:53 +00:00
|
|
|
|
TPoint * to, // @parm Punto a cui terminare di scrivere il testo
|
|
|
|
|
int size) // @parm lunghezza della riga (0 = variabile, > 0 fissa)
|
2016-09-09 13:58:28 +00:00
|
|
|
|
{
|
|
|
|
|
FILE* fp = fopen(path, "w");
|
|
|
|
|
if (fp != NULL)
|
|
|
|
|
{
|
|
|
|
|
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);
|
2017-05-23 17:46:53 +00:00
|
|
|
|
|
|
|
|
|
TString8 frm("%s\n");
|
2016-09-09 13:58:28 +00:00
|
|
|
|
|
2017-05-23 17:46:53 +00:00
|
|
|
|
if ( size > 0)
|
|
|
|
|
frm.format("%%%ds\n", -size);
|
|
|
|
|
fprintf(fp, frm, (const char *) s);
|
2016-09-09 13:58:28 +00:00
|
|
|
|
}
|
|
|
|
|
fclose (fp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
warning_box ("Impossibile scrivere il file %s; scrittura fallita", path);
|
|
|
|
|
return fp != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// @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
|
2017-05-23 17:46:53 +00:00
|
|
|
|
TPoint * to, // @parm Punto a cui terminare di scrivere il testo
|
|
|
|
|
int size) // @parm lunghezza della riga (0 = variabile, > 0 fissa)
|
2016-09-09 13:58:28 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
2017-05-23 17:46:53 +00:00
|
|
|
|
if (size > 0)
|
|
|
|
|
s.rpad(size);
|
|
|
|
|
|
2016-09-09 13:58:28 +00:00
|
|
|
|
arr.add(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determina il tipo di una stringa: 0=ignoto; 1=stringa; 2=numero
|
|
|
|
|
static int str_type(TString& str)
|
|
|
|
|
{
|
|
|
|
|
str.rtrim();
|
|
|
|
|
if (str.blank())
|
|
|
|
|
return 0;
|
|
|
|
|
bool is_string = false;
|
|
|
|
|
bool is_number = true;
|
|
|
|
|
for (int i=0; str[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
const char c = str[i];
|
|
|
|
|
if (c < '\0' || isalnum(c))
|
|
|
|
|
is_string = true;
|
|
|
|
|
if (strchr("0123456789,.", c) == NULL)
|
|
|
|
|
is_number = false;
|
|
|
|
|
}
|
|
|
|
|
if (is_number)
|
|
|
|
|
{
|
|
|
|
|
str.strip(".");
|
|
|
|
|
str.replace(',', '.');
|
|
|
|
|
const real r(str);
|
|
|
|
|
str = r.stringe();
|
|
|
|
|
}
|
|
|
|
|
return is_number ? 2 : (is_string ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_text_line(TString& str)
|
|
|
|
|
{
|
|
|
|
|
const int l = str.trim().len();
|
|
|
|
|
if (l >= 64)
|
|
|
|
|
{
|
|
|
|
|
const char c = str[0];
|
|
|
|
|
if (strchr("_-=", c) != NULL && str[l/2] == c && str[l-1] == c)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TTextfile::write_xls(const TFilename& xls)
|
|
|
|
|
{
|
|
|
|
|
const TPrinter& pr = printer();
|
|
|
|
|
int headerlen = pr.headersize();
|
|
|
|
|
const int footerlen = pr.footersize();
|
|
|
|
|
const int pagelen = pr.formlen();
|
|
|
|
|
TString str;
|
|
|
|
|
|
|
|
|
|
int tabstart = 1;
|
|
|
|
|
int tabstop = pagelen - footerlen;
|
|
|
|
|
if (_lines < tabstop) tabstop = _lines;
|
|
|
|
|
|
|
|
|
|
int header_end = 12;
|
|
|
|
|
if (headerlen > 3)
|
|
|
|
|
header_end = headerlen;
|
|
|
|
|
if (header_end > tabstop)
|
|
|
|
|
header_end = tabstop;
|
|
|
|
|
|
|
|
|
|
for (long j = 1; j < header_end; j++)
|
|
|
|
|
{
|
|
|
|
|
read_line(j);
|
|
|
|
|
str = piece();
|
|
|
|
|
if (is_text_line(str))
|
|
|
|
|
{
|
|
|
|
|
if (tabstart <= 1)
|
|
|
|
|
tabstart = j+1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tabstop = j;
|
|
|
|
|
headerlen = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tabstart <= 1 && headerlen > 0)
|
|
|
|
|
tabstart = headerlen;
|
|
|
|
|
if (tabstart < 2)
|
|
|
|
|
tabstart = 2;
|
|
|
|
|
|
|
|
|
|
TTabulator tab;
|
|
|
|
|
for (long j = tabstart; j < tabstop; j++)
|
|
|
|
|
{
|
|
|
|
|
read_line(j);
|
|
|
|
|
int x = 0;
|
|
|
|
|
for (const char* cp = piece(); cp; cp = piece())
|
|
|
|
|
{
|
|
|
|
|
str = cp;
|
|
|
|
|
const int len = str.len();
|
|
|
|
|
if (str_type(str) > 0)
|
|
|
|
|
tab.add_field(x, str.len());
|
|
|
|
|
x += len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tab.sort();
|
|
|
|
|
|
|
|
|
|
TToken_string riga(256, '\t');
|
|
|
|
|
|
|
|
|
|
TString8 ext = pr.get_form_name().ext(); ext.lower();
|
|
|
|
|
const bool is_rep = ext == "frm" || ext == "rep";
|
|
|
|
|
|
|
|
|
|
ofstream out(xls);
|
|
|
|
|
for (long j = 0; j < _lines; j++)
|
|
|
|
|
{
|
|
|
|
|
const int row = j % pagelen;
|
|
|
|
|
|
|
|
|
|
if (is_rep)
|
|
|
|
|
{
|
|
|
|
|
// Esporto la testata solo nella prima pagina e lascio il footer perch<63> nei form <20> variabile in lunghezza
|
|
|
|
|
if (row < headerlen && j >= pagelen)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Esporto la testata solo nella prima pagina ed il footer solo nell'ultima
|
|
|
|
|
if ((row < headerlen && j >= pagelen) || (row >= pagelen-footerlen && row < _lines-pagelen))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
read_line(j);
|
|
|
|
|
riga.cut(0);
|
|
|
|
|
int x = 0;
|
|
|
|
|
for (const char* cp = piece(); cp; cp = piece())
|
|
|
|
|
{
|
|
|
|
|
str = cp;
|
|
|
|
|
const int len = str.len();
|
|
|
|
|
const int st = str_type(str);
|
|
|
|
|
if (st > 0)
|
|
|
|
|
{
|
|
|
|
|
int idx, pos;
|
|
|
|
|
if (tab.find_column(x, str.len(), idx, pos))
|
|
|
|
|
{
|
|
|
|
|
const char* old = riga.get(pos);
|
|
|
|
|
if (old && *old)
|
|
|
|
|
str.insert(old);
|
|
|
|
|
riga.add(str, pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
x += len;
|
|
|
|
|
}
|
|
|
|
|
if (riga.full())
|
|
|
|
|
out << riga << endl;
|
|
|
|
|
}
|
|
|
|
|
return xls.exist();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TTextfile::destroy ()
|
|
|
|
|
{
|
|
|
|
|
CHECK(_istemp, "destroy() chiamata su testo permanente!");
|
|
|
|
|
if (_page.items () > 0)
|
|
|
|
|
{
|
|
|
|
|
if (_index)
|
|
|
|
|
fclose (_index);
|
|
|
|
|
if (_instr)
|
|
|
|
|
fclose (_instr);
|
|
|
|
|
_filename.fremove();
|
|
|
|
|
_indname.fremove();
|
|
|
|
|
_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)
|
|
|
|
|
{
|
|
|
|
|
cantwrite_box (_filename);
|
|
|
|
|
freeze ();
|
|
|
|
|
}
|
|
|
|
|
_isopen = TRUE;
|
|
|
|
|
// _page.destroy ();
|
|
|
|
|
_spots.destroy ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TTextfile ::TTextfile (const char *file, int pagesize, direction preferred,
|
|
|
|
|
bool interactive):
|
|
|
|
|
_page (pagesize), _dirty_lines(pagesize), _page_start (0l), _page_end (-1l), _page_size (pagesize),
|
|
|
|
|
_lines (0l), _cur_line (-1), _filename (file), _index (NULL),
|
|
|
|
|
_direction (preferred), _item (0), _line (256), _hotspots (4), _dirty (FALSE),
|
|
|
|
|
_istemp (FALSE), _accept (TRUE), _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)
|
|
|
|
|
{
|
|
|
|
|
cantwrite_box(_filename);
|
|
|
|
|
freeze ();
|
|
|
|
|
}
|
|
|
|
|
if (!_istemp)
|
|
|
|
|
while (!feof(_instr))
|
|
|
|
|
{
|
|
|
|
|
const long l = ftell (_instr);
|
|
|
|
|
fwrite (&l, sizeof (long), 1, _index);
|
|
|
|
|
if (ferror(_index) || ferror(_instr))
|
|
|
|
|
{
|
|
|
|
|
cantwrite_box(_indname);
|
|
|
|
|
freeze();
|
|
|
|
|
}
|
|
|
|
|
if (fgets (TEXT_TMP, TEXT_TMP_SIZE, _instr) == NULL)
|
|
|
|
|
break;
|
|
|
|
|
_lines++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TTextfile::~TTextfile ()
|
|
|
|
|
{
|
|
|
|
|
if (_index)
|
|
|
|
|
fclose (_index);
|
|
|
|
|
if (_instr)
|
|
|
|
|
fclose (_instr);
|
|
|
|
|
if (_istemp) remove ((const char *) _filename);
|
|
|
|
|
remove ((const char *) _indname);
|
|
|
|
|
}
|
2021-03-07 23:03:09 +01:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// TTracciatoInvio
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TTracciatoInvio::add_field(const char* name, InvioFieldType type, int len, int dec)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case AN:
|
|
|
|
|
break;
|
|
|
|
|
case CB:
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (len == 0)
|
|
|
|
|
len = 1;
|
|
|
|
|
type = NU;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case CF:
|
|
|
|
|
type = AN;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
len = 16;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
case PI:
|
2021-03-07 23:03:09 +01:00
|
|
|
|
case CN:
|
|
|
|
|
type = NU;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
len = 11;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case DA:
|
|
|
|
|
type = NU;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
len = 4;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
case D6:
|
|
|
|
|
type = NU;
|
|
|
|
|
len = 6;
|
|
|
|
|
break;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
case DT:
|
|
|
|
|
type = NU;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
len = 8;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
case NP:
|
|
|
|
|
type = NU;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
case NU:
|
|
|
|
|
break;
|
|
|
|
|
case PN:
|
|
|
|
|
case PR:
|
|
|
|
|
type = AN;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
len = 2;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case QU:
|
|
|
|
|
CHECK(len > dec + 1, "numero di decimali incoerente");
|
2021-03-16 13:36:05 +01:00
|
|
|
|
break;
|
|
|
|
|
case FV:
|
|
|
|
|
len = strlen(name);
|
|
|
|
|
// CHECK(strlen(name) == len, "lunghezza campo fisso incoerente");
|
|
|
|
|
break;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
default:
|
|
|
|
|
CHECK(false, "tipo campo sospetto");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TFieldInvio* info = new TFieldInvio;
|
|
|
|
|
info->_desc = name;
|
|
|
|
|
info->_type = type;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
info->_pos = _len + 1;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
info->_len = len;
|
|
|
|
|
info->_dec = dec;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
_len += len;
|
|
|
|
|
_fields.add(name, info);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& TTracciatoInvio::field(const char * name) const
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TFieldInvio* info = (TFieldInvio*)_fields.objptr(name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
#ifdef DBG
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (info == nullptr)
|
|
|
|
|
fatal_box("Non esiste il campo %s sul tipo record %c", name, _tipo);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
#endif
|
|
|
|
|
return *info;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TTracciatoInvio::zero(TString& buffer)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
|
|
|
|
buffer.fill(' ', TOTAL_SIZE);
|
|
|
|
|
char* ptr = buffer.get_buffer();
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
|
|
|
|
FOR_EACH_ASSOC_OBJECT( _fields, hash, name, obj)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& info = (const TFieldInvio&)_fields[name];
|
2021-03-07 23:03:09 +01:00
|
|
|
|
if (info._type == NU || info._type == CB || info._type == DA || info._type == DT || info._type == CN)
|
|
|
|
|
memset(ptr + info._pos - 1, '0', info._len);
|
2021-03-16 13:36:05 +01:00
|
|
|
|
else
|
|
|
|
|
if (info._type == FV)
|
|
|
|
|
buffer.overwrite(info._desc, info._pos -1, info._len);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
buffer[0] = _tipo;
|
|
|
|
|
buffer.overwrite("A\r\n", TOTAL_SIZE - 3);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TTracciatoInvio::TTracciatoInvio(char tipo) : _tipo(tipo), _len(0)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
|
|
|
|
if (strchr("ABCEFHJZ[", tipo) == NULL)
|
|
|
|
|
NFCHECK("Tipo record non valido: %c", tipo);
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field("Tipo record", AN, 1); // 1
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TTracciatoInvio::~TTracciatoInvio()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
/*
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// TTracciatiInvio
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
TTracciatiInvio _trcInvio;
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TTracciatiInvio & tracciati() { return _trcInvio; }
|
|
|
|
|
|
|
|
|
|
class TTracciatiInvio : public TObject
|
|
|
|
|
{
|
|
|
|
|
TArray _trc;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
const TTracciatoInvio* tracciato(TTracciatoInvio * trc);
|
|
|
|
|
const TTracciatoInvio& tracciato(TRecordInvio & rec);
|
|
|
|
|
|
|
|
|
|
int tipo2pos(int tipo) const;
|
|
|
|
|
bool exist(int tipo) const { return _trc.objptr(tipo2pos(tipo)) != nullptr; }
|
|
|
|
|
|
|
|
|
|
void destroy();
|
|
|
|
|
|
|
|
|
|
TTracciatiInvio();
|
|
|
|
|
virtual ~TTracciatiInvio();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TTracciatiInvio & tracciati();
|
|
|
|
|
|
|
|
|
|
const TTracciatoInvio * TTracciatiInvio::tracciato(TTracciatoInvio * trc)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
char tipo = trc->tipo();
|
|
|
|
|
int pos = tipo2pos(tipo);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (!exist(tipo))
|
|
|
|
|
_trc.add(trc, pos);
|
|
|
|
|
return (const TTracciatoInvio*)_trc.objptr(pos);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TTracciatoInvio& TTracciatiInvio::tracciato(TRecordInvio & rec)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
char tipo = rec.tipo_record();
|
|
|
|
|
int pos = tipo2pos(tipo);
|
|
|
|
|
|
|
|
|
|
if (!exist(tipo))
|
|
|
|
|
_trc.add(rec.add_tracciato(), pos);
|
|
|
|
|
return *(const TTracciatoInvio*)_trc.objptr(pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TTracciatiInvio::tipo2pos(int tipo) const
|
|
|
|
|
{
|
|
|
|
|
CHECK((tipo >= 'A' && tipo <= 'Z') || tipo == '[', "Tipo record non valido");
|
|
|
|
|
return tipo - 'A';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TTracciatiInvio::destroy()
|
|
|
|
|
{
|
|
|
|
|
_trc.destroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TTracciatiInvio::TTracciatiInvio()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TTracciatiInvio::~TTracciatiInvio()
|
|
|
|
|
{
|
|
|
|
|
destroy(); // Non viene mai chiamato!
|
|
|
|
|
}
|
|
|
|
|
*/
|
2021-03-07 23:03:09 +01:00
|
|
|
|
|
|
|
|
|
TTracciatoInvioFileDati::TTracciatoInvioFileDati(const TRectype& rec)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < rec.items(); i++)
|
|
|
|
|
{
|
|
|
|
|
const TString16 fieldname(rec.rec_des().Fd[i].Name);
|
|
|
|
|
TFieldtypes t = rec.type(fieldname);
|
|
|
|
|
|
|
|
|
|
switch (t)
|
|
|
|
|
{
|
|
|
|
|
case _nullfld:
|
|
|
|
|
break;
|
|
|
|
|
case _alfafld: // @emem Campo di tipo alfanumerico
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, AN, rec.length(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _intfld: // @emem Campo di tipo intero
|
|
|
|
|
case _longfld: // @emem Campo di tipo intero lungo
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, NU, rec.length(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _realfld: // @emem Campo di tipo reale (vedi <c real>)
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, QU, rec.length(fieldname), rec.ndec(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _datefld: // @emem Campo di tipo data (vedi <c TDate>)
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, DT, rec.length(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _wordfld: // @emem Campo di tipo intero senza segno
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, NU, rec.length(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _charfld: // @emem Campo di tipo carattere
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, AN, 1);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _boolfld: // @emem Campo di tipo booleano
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, CB, rec.length(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _intzerofld: // @emem Campo di tipo intero zero filled
|
|
|
|
|
case _longzerofld: // @emem Campo di tipo intero lungo zero filled
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, NU, rec.length(fieldname));
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
case _memofld:
|
2021-03-16 13:36:05 +01:00
|
|
|
|
add_field(fieldname, AN, 512);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// TRecordInvio
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TRecordInvio::read_from(istream& ins)
|
|
|
|
|
{
|
|
|
|
|
_buffer.fill(' ', TOTAL_SIZE);
|
|
|
|
|
ins.read(_buffer.get_buffer(), TOTAL_SIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TRecordInvio::set(const TFieldInvio& fld, const char* val)
|
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TString str(val); // Ci sono campi di 100 caratteri!
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
if (fld._type == AN)
|
|
|
|
|
str.upper();
|
|
|
|
|
if (fld._type == QU)
|
|
|
|
|
{
|
|
|
|
|
str.replace(".", ",");
|
|
|
|
|
int dotpos = str.find(".");
|
|
|
|
|
|
|
|
|
|
if (dotpos < 0)
|
|
|
|
|
str << ".";
|
|
|
|
|
dotpos = str.find(".");
|
|
|
|
|
int dec = fld._dec - (str.len() - dotpos - 1);
|
|
|
|
|
while (dec > 0) str << '0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int lenstr = str.len();
|
|
|
|
|
|
|
|
|
|
if (lenstr > fld._len)
|
|
|
|
|
{
|
|
|
|
|
#ifdef DBG
|
|
|
|
|
NFCHECK("Campo troppo lungo: '%s' (max. %d)", val, fld._len);
|
|
|
|
|
#endif
|
|
|
|
|
if (fld._type == QU)
|
|
|
|
|
{
|
|
|
|
|
str.ltrim(lenstr - fld._len);
|
|
|
|
|
lenstr = fld._len;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
str.cut(lenstr = fld._len);
|
|
|
|
|
}
|
|
|
|
|
if (lenstr != fld._len)
|
|
|
|
|
{
|
|
|
|
|
str.trim();
|
|
|
|
|
if (fld._type == NU)
|
|
|
|
|
str.right_just(fld._len, '0');
|
|
|
|
|
else
|
|
|
|
|
str.left_just(fld._len);
|
|
|
|
|
}
|
|
|
|
|
_buffer.overwrite(str, fld._pos - 1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, const char* val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = tracciato().field(name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
set(fld, val);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, int val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = tracciato().field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS(fld._type == NU, "Invalid numeric field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
TString16 str; str.format("%d", val);
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
set(fld, str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, long val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = tracciato().field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS(fld._type == NU, "Invalid numeric field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
TString16 str; str.format("%ld", val);
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
set(fld, str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, const real& val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = tracciato().field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS(fld._type == NU, "Invalid numeric field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
const char* str = val.string(fld._len, 0);
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
set(fld, str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, const TDate& val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = tracciato().field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS(fld._type == NU && (fld._len == 6 || fld._len == 8),
|
|
|
|
|
"Invalid date field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
const char* str;
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
if (fld._len == 8)
|
|
|
|
|
str = val.string(full, '\0', full, full, gma_date);
|
|
|
|
|
else
|
|
|
|
|
str = val.string(brief, '\0', full, full, gma_date);
|
|
|
|
|
set(fld, str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, char val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = get_field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS(fld._type == AN && fld._len == 1, "Invalid char field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
const char str[2] = { val, '\0' };
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
set(fld, str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
void TRecordInvio::set(const char* name, bool val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = get_field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS((fld._type == CB || fld._type == NU) && fld._len == 1, "Invalid boolean field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
set(fld, val ? "1" : "0");
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const char* TRecordInvio::get(const char* name, TString& str) const
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = get_field(name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
str = _buffer.mid(fld._pos - 1, fld._len);
|
|
|
|
|
return str.trim();
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
int TRecordInvio::get_int(const char* name) const
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TString16 str; get(name, str);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
return atoi(str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
char TRecordInvio::get_char(const char* name) const
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TFieldInvio& fld = get_field(name);
|
|
|
|
|
|
|
|
|
|
CHECKS(fld._type == AN, "Invalid char field ", name);
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
return _buffer[fld._pos - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calcola i blocchi necessari per contenere la stringa val
|
|
|
|
|
int TRecordInvio::calculate_blocks(const char* val) const
|
|
|
|
|
{
|
|
|
|
|
// Il primo blocco contiene 16 caratteri, gli altri solo 15 perche' c'e' anche il +
|
|
|
|
|
int blocks = 1;
|
|
|
|
|
if (val && *val)
|
|
|
|
|
{
|
|
|
|
|
const int len = strlen(val);
|
|
|
|
|
if (len > FIELD_SIZE)
|
|
|
|
|
blocks += (len - FIELD_SIZE - 1) / (FIELD_SIZE - 1) + 1;
|
|
|
|
|
}
|
|
|
|
|
return blocks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TRecordInvio::tipo_record(char tipo)
|
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
_buffer[0] = tipo;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
const TRecordInvio& TRecordInvio::operator = (const TRecordInvio& rec)
|
|
|
|
|
{
|
|
|
|
|
_buffer = rec._buffer;
|
|
|
|
|
if (tipo_record() != rec.tipo_record())
|
|
|
|
|
{
|
|
|
|
|
safe_delete(_tracciato);
|
|
|
|
|
tracciato();
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Azzera tutti i campi non posizionali
|
2021-03-07 23:03:09 +01:00
|
|
|
|
void TRecordInvio::azzera_campi_non_posizionali()
|
|
|
|
|
{
|
|
|
|
|
CHECK(ha_campi_non_posizionali(), "Impossibile azzerare un record senza campi non posizionali");
|
|
|
|
|
char* buf = _buffer.get_buffer() + HEADER_SIZE;
|
|
|
|
|
memset(buf, ' ', USEABLE_SIZE);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
// Aggiunge un campo non posizionale ai record
|
2021-03-07 23:03:09 +01:00
|
|
|
|
bool TRecordInvio::np_put(const char* code, const char* val)
|
|
|
|
|
{
|
|
|
|
|
CHECK(ha_campi_non_posizionali(), "Impossibile aggiungere campi non posizionali");
|
|
|
|
|
CHECKS(code && strlen(code) == CODE_SIZE, "Invalid field code ", code);
|
|
|
|
|
//CHECKS(val && *val, "Can't add empty field ", code);
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
bool ok = true;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (val && *val)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
// Cerca il primo posto libero
|
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
|
|
for (pos = HEADER_SIZE; pos < HEADER_SIZE + USEABLE_SIZE; pos += BLOCK_SIZE)
|
|
|
|
|
{
|
|
|
|
|
if (_buffer[pos] == ' ')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
const int free_blocks = (USEABLE_SIZE - pos) / BLOCK_SIZE;
|
|
|
|
|
const int needed_blocks = calculate_blocks(val);
|
|
|
|
|
bool ok = free_blocks >= needed_blocks;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
TString80 str(val); str.upper();
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
|
|
|
|
if (!ok) // Se non ci sono abbastanza blocchi liberi
|
|
|
|
|
{
|
|
|
|
|
ok = true;
|
|
|
|
|
change_record();
|
|
|
|
|
pos = HEADER_SIZE;
|
|
|
|
|
if (str.len() > USEABLE_SIZE)
|
|
|
|
|
str.cut(USEABLE_SIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int lenstr = str.len();
|
|
|
|
|
|
2021-03-07 23:03:09 +01:00
|
|
|
|
for (int i = 0; i < lenstr; )
|
|
|
|
|
{
|
|
|
|
|
_buffer.overwrite(code, pos);
|
|
|
|
|
pos += CODE_SIZE;
|
|
|
|
|
int maxlen = FIELD_SIZE;
|
|
|
|
|
if (i > 0)
|
|
|
|
|
{
|
|
|
|
|
_buffer.overwrite("+", pos);
|
|
|
|
|
pos++;
|
|
|
|
|
maxlen--;
|
|
|
|
|
}
|
|
|
|
|
const TString& substr = str.mid(i, maxlen);
|
|
|
|
|
_buffer.overwrite(substr, pos);
|
|
|
|
|
pos += maxlen;
|
|
|
|
|
i += maxlen;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_put(const char* code, long val)
|
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TString16 str;
|
|
|
|
|
|
|
|
|
|
str.format("%16ld", val);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
return np_put(code, str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_put(const char* code, const real& val)
|
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (!val.is_zero())
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
|
|
|
|
const TString& str = val.stringa(16, 2);
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
|
|
|
|
return np_put(code, str);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
2021-03-16 13:36:05 +01:00
|
|
|
|
return true;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_put(const char* code, char val)
|
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (val > ' ')
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
|
|
|
|
const char str[2] = { val, '\0' };
|
2021-03-16 13:36:05 +01:00
|
|
|
|
|
|
|
|
|
return np_put(code, str);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
2021-03-16 13:36:05 +01:00
|
|
|
|
return true;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_put(const char* code, const TDate& date)
|
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
if (date.ok())
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
|
|
|
|
TString16 str;
|
|
|
|
|
str.format("%8s%02d%02d%04d", "", date.day(), date.month(), date.year());
|
2021-03-16 13:36:05 +01:00
|
|
|
|
return np_put(code, str);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
2021-03-16 13:36:05 +01:00
|
|
|
|
return true;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_put(const char* code, bool cb)
|
|
|
|
|
{
|
|
|
|
|
if (cb)
|
|
|
|
|
{
|
|
|
|
|
TString16 str; str.format("%16d", 1);
|
2021-03-16 13:36:05 +01:00
|
|
|
|
return np_put(code, str);
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
2021-03-16 13:36:05 +01:00
|
|
|
|
return true;
|
2021-03-07 23:03:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_get(int pos, TString& key, TString& val) const
|
|
|
|
|
{
|
|
|
|
|
CHECK(ha_campi_non_posizionali(), "Impossibile leggere campi non posizionali");
|
|
|
|
|
|
|
|
|
|
const int n = HEADER_SIZE + pos * BLOCK_SIZE;
|
|
|
|
|
bool ok = false;
|
|
|
|
|
if (n < HEADER_SIZE + USEABLE_SIZE)
|
|
|
|
|
{
|
|
|
|
|
ok = _buffer[n] > ' ';
|
|
|
|
|
if (ok)
|
|
|
|
|
{
|
|
|
|
|
key = _buffer.mid(n, CODE_SIZE);
|
|
|
|
|
val = _buffer.mid(n + CODE_SIZE, FIELD_SIZE);
|
|
|
|
|
#ifdef DBG
|
|
|
|
|
if (key == "AU001036")
|
|
|
|
|
int cazzone = atoi(val);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::np_get_real(int pos, TString& key, real& val) const
|
|
|
|
|
{
|
|
|
|
|
TString16 str;
|
|
|
|
|
const bool ok = np_get(pos, key, str);
|
|
|
|
|
if (ok && str.full())
|
|
|
|
|
{
|
|
|
|
|
str.replace(',', '.');
|
|
|
|
|
val = real(str);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
val = ZERO;
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TRecordInvio::valid() const
|
|
|
|
|
{
|
|
|
|
|
const char tipo = tipo_record();
|
|
|
|
|
const bool ok = (tipo > ' ') && (strchr("ABEHJZ", tipo) != NULL);
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:36:05 +01:00
|
|
|
|
TRecordInvio::TRecordInvio(const TRectype& rec) : _buffer(TOTAL_SIZE, ' '), _tracciato(nullptr)
|
2021-03-07 23:03:09 +01:00
|
|
|
|
{
|
2021-03-16 13:36:05 +01:00
|
|
|
|
}
|