e9a34d143f
git-svn-id: svn://10.65.10.50/branches/R_10_00@23179 c028cbd2-c16b-5b4b-a496-9718f37d4682
2026 lines
45 KiB
C++
Executable File
2026 lines
45 KiB
C++
Executable File
#include <xvt.h>
|
||
|
||
#include <dongle.h>
|
||
#include <prefix.h>
|
||
#include <real.h>
|
||
#include <utility.h>
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @func Ritorna il nome dell'utente attuale
|
||
//
|
||
// @rdesc Ritorno il nome dell'utente attuale
|
||
TString& user()
|
||
{
|
||
static TString80 _user;
|
||
return _user;
|
||
}
|
||
|
||
const TToken_string& empty_string()
|
||
{
|
||
static TToken_string _ts(1);
|
||
return _ts;
|
||
}
|
||
|
||
// Most descriptions will fit in fifty characters
|
||
const int DEFAULT_SIZE = 50;
|
||
const int MAX_SIZE = 65535;
|
||
|
||
inline bool is_space(char c)
|
||
{ return c >= '\t' && c <= ' '; }
|
||
|
||
inline int round16(int n)
|
||
{ const int k = (n/16 + 1) * 16; CHECKD(k>=n,"Round16 failed ", k); return k; }
|
||
|
||
// Certified 99%
|
||
// @doc EXTERNAL
|
||
//
|
||
// @mfunc Cambia la dimensione della stringa eventualmente preservandone il contenuto iniziale
|
||
void TString::resize(
|
||
int size, // @parm Nuova dimensione della stringa
|
||
bool cpy) // @parm Se true mantiene il contenuto della stringa e alloca
|
||
// nuovo spazio
|
||
|
||
// @comm Non funziona con le stringhe static e per valori negativi di <p size>
|
||
{
|
||
CHECKD(size >= 0, "Invalid string resize ", size);
|
||
char* s = (char*)calloc(round16(size+1), 1);
|
||
if (_str)
|
||
{
|
||
if (cpy && *_str)
|
||
strcpy_s(s, size+1, _str);
|
||
free(_str);
|
||
}
|
||
|
||
_str = s;
|
||
_size = size;
|
||
}
|
||
|
||
|
||
// Certified 99% (uses resize)
|
||
// @doc EXTERNAL
|
||
//
|
||
// @mfunc Inizializza con la stringa puntata da char* di lunghezza size
|
||
// (usa <mf TString::resize>)
|
||
TString& TString::set(
|
||
const char* s) // @parm Stringa da inizializzare
|
||
|
||
// @rdesc Ritorna l'indirizzo della stringa inizializzata
|
||
{
|
||
if (s && *s)
|
||
{
|
||
const int sz = strlen(s);
|
||
strncpy(s, sz);
|
||
}
|
||
else
|
||
{
|
||
if (size() == 0)
|
||
resize(DEFAULT_SIZE, false);
|
||
*_str = '\0';
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Espande la stringa per altri caratteri
|
||
int TString::make_room(
|
||
int s) // @parm Numero di caratteri di cui si vuole aspandere la stringa
|
||
|
||
// @comm La stringa viene espansa di un numero di caratteri maggiore (per efficienza) di
|
||
// quello passato per parametro
|
||
//
|
||
// @rdesc Ritorna il numero di caratteri della stringa prima della chiamata
|
||
{
|
||
const int lun = len();
|
||
const int spare = size() - lun;
|
||
if (spare < s)
|
||
{
|
||
const int min_size = lun + s;
|
||
int new_size = round16(3 * min_size / 2);
|
||
if (new_size > MAX_SIZE)
|
||
new_size = MAX_SIZE;
|
||
if (new_size < min_size)
|
||
fatal_box("Stringa di lunghezza superiore a %d)", min_size);
|
||
resize(new_size, true);
|
||
}
|
||
return lun;
|
||
}
|
||
|
||
TString::TString(const char* s) : _str(NULL), _size(0)
|
||
{ set(s); }
|
||
|
||
TString::TString(const TString& s) : _str(NULL), _size(0)
|
||
{ set(s); }
|
||
|
||
TString::TString(int size, char c) : _str(NULL), _size(0)
|
||
{
|
||
if (size > 0)
|
||
fill(c, size); // Guy: Much simpler and faster (uses memset)
|
||
else
|
||
resize(DEFAULT_SIZE, false);
|
||
}
|
||
|
||
TString::TString() : _str(NULL), _size(0)
|
||
{ resize(DEFAULT_SIZE, false); }
|
||
|
||
TString::~TString()
|
||
{
|
||
if (_str)
|
||
{
|
||
free(_str);
|
||
#ifdef DBG
|
||
_str = NULL;
|
||
_size = -883;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
char TString::shift(int n)
|
||
{
|
||
CHECK(n>0 && n<=len(),"Errore di scorrimento");
|
||
const char r=*(_str+n-1);
|
||
strcpy_s(_str, _size+1, _str+n);
|
||
return r;
|
||
}
|
||
|
||
TString& TString::operator <<(const char* s)
|
||
{
|
||
if (s && *s)
|
||
{
|
||
const int pos = make_room(strlen(s));
|
||
strcpy_s(&_str[pos], _size-pos+1, s);
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
TString& TString::operator <<(char c)
|
||
{
|
||
int pos = make_room(1);
|
||
_str[pos++] = c;
|
||
_str[pos] = '\0';
|
||
return *this;
|
||
}
|
||
|
||
|
||
TString& TString::operator <<(int n)
|
||
{
|
||
char s[16]; _itoa(n, s, 10);
|
||
return operator <<(s);
|
||
}
|
||
|
||
|
||
TString& TString::operator <<(long n)
|
||
{
|
||
char s[16]; _ltoa(n, s, 10);
|
||
return operator <<(s);
|
||
}
|
||
|
||
TString& TString::operator <<(double n)
|
||
{
|
||
char s[32]; sprintf(s, "%lg", n);
|
||
return operator <<(s);
|
||
}
|
||
|
||
// Appends an object to the string
|
||
// Certified 99%
|
||
// The object should be completely storable in spark
|
||
TString& TString::operator <<(const TObject& obj)
|
||
{
|
||
TString256 spark;
|
||
#ifdef WIN32
|
||
ostrstream out(spark.get_buffer(), spark.size());
|
||
#else
|
||
ostringstream out(spark.get_buffer());
|
||
#endif
|
||
obj.print_on(out);
|
||
out << ends;
|
||
return operator <<(spark);
|
||
}
|
||
|
||
TString& TString::operator <<(const TString& str)
|
||
{ return operator <<(str._str); }
|
||
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Elimina tutti i caratteri contenuti in <p k>
|
||
TString& TString::strip(
|
||
const char* k) // @parm Stringa dei caratteri da eliminare
|
||
{
|
||
int j = 0;
|
||
for (const char* s = _str; *s; s++)
|
||
{
|
||
const char& c = *s;
|
||
if (strchr(k, c) == NULL)
|
||
_str[j++] = c;
|
||
|
||
}
|
||
return cut(j);
|
||
}
|
||
|
||
bool TString::blank() const
|
||
{
|
||
for (const char* s = _str; *s; s++)
|
||
if (!is_space(*s))
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
bool TString::full() const
|
||
{
|
||
for (const char* s = _str; *s; s++)
|
||
if (!is_space(*s))
|
||
return true;
|
||
return false;
|
||
|
||
}
|
||
|
||
TString& TString::strip_spaces()
|
||
{
|
||
char instring = '\0';
|
||
int j = 0;
|
||
for (const char* s = _str; *s; s++)
|
||
{
|
||
const char& c = *s;
|
||
if (is_space(c) && !instring)
|
||
continue;
|
||
if (c == '"' || c == '\'')
|
||
{
|
||
if (instring == c)
|
||
instring = '\0';
|
||
else
|
||
if (instring == '\0')
|
||
instring = c;
|
||
}
|
||
_str[j++] = c;
|
||
}
|
||
_str[j] = '\0';
|
||
return *this;
|
||
}
|
||
|
||
TString& TString::strip_double_spaces()
|
||
{
|
||
int j = 0;
|
||
bool spc = false;
|
||
for (const char* s = _str; *s; s++)
|
||
{
|
||
const char& c = *s;
|
||
if (is_space(c))
|
||
{
|
||
if (spc)
|
||
continue;
|
||
else
|
||
spc = true;
|
||
}
|
||
else
|
||
spc = false;
|
||
_str[j++] = c;
|
||
}
|
||
if (spc) // Toglie eventuale spazio finale
|
||
j--;
|
||
_str[j] = '\0';
|
||
return *this;
|
||
}
|
||
|
||
// Certified 100%
|
||
const char* TString::class_name() const
|
||
{ return "String"; }
|
||
|
||
// Certified 100%
|
||
word TString::class_id() const
|
||
{ return CLASS_STRING; }
|
||
|
||
bool TString::is_kind_of(word cid) const
|
||
{ return cid == CLASS_STRING || TObject::is_kind_of(cid); }
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Duplica una stringa
|
||
TObject* TString::dup() const
|
||
|
||
// @comm Alloca nuovo spazio per duplicare la stringa
|
||
//
|
||
// @rdesc Ritorna il puntatore alla stringa duplicata
|
||
{
|
||
return new TString(_str);
|
||
}
|
||
|
||
void TString::read_from(istream& in)
|
||
{
|
||
if (size() < 256)
|
||
{
|
||
char tmp[256] = "";
|
||
in >> tmp;
|
||
set(tmp);
|
||
}
|
||
else
|
||
{
|
||
cut(0);
|
||
in >> _str;
|
||
}
|
||
}
|
||
|
||
// Certified 100%
|
||
void TString::print_on(ostream& out) const
|
||
{ out << _str; }
|
||
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna la posizione del carattere o della stringa nell'oggetto TString
|
||
//
|
||
// @rdesc Ritorna i seguneti parametri:
|
||
//
|
||
// @flag <gt>= 0 | Posizione dell'elemento nella stringa
|
||
// @flag -1 | L'elemento non e' stato trovato
|
||
int TString::find(
|
||
char c, // @parm Carattere da cercare
|
||
int from) const // @parm Posizione da cui iniziare la ricerca
|
||
// @parm const char* | s | Stringa da cercare
|
||
|
||
// @syntax find(char c, int from);
|
||
// @syntax find(const char* s, int from);
|
||
//
|
||
// @comm Cerca nella stringa, dalla posizione indicata, l'elemento passato.
|
||
// Nel caso <p from> sia maggiore della lunghezza della stringa manda
|
||
// un messaggio di errore
|
||
{
|
||
CHECKD(from >= 0, "bad string index", from);
|
||
CHECK(c, "bad character to find");
|
||
int pos = -1;
|
||
if (from == 0 || from < len())
|
||
{
|
||
const char* p = strchr(_str + from, c);
|
||
if (p != NULL)
|
||
pos = int(p - _str);
|
||
}
|
||
return pos;
|
||
}
|
||
|
||
int TString::rfind(
|
||
char c) const // @parm Carattere da cercare
|
||
|
||
// @syntax rfind(char c);
|
||
//
|
||
{
|
||
const char* p = strrchr(_str, c);
|
||
return p ? int(p - _str) : -1;
|
||
}
|
||
|
||
// Certified 100%
|
||
int TString::find(const char* s, int from) const
|
||
{
|
||
CHECKD(from >= 0, "bad string index", from);
|
||
CHECK(s && *s, "bad string to find");
|
||
int pos = -1;
|
||
if (from == 0 || from < len())
|
||
{
|
||
const char* p = strstr(_str + from, s);
|
||
if (p != NULL)
|
||
pos = int(p - _str);
|
||
}
|
||
return pos;
|
||
}
|
||
|
||
bool TString::match(const char* pat, bool ignore_case) const
|
||
{
|
||
return (pat && *pat) ? xvt_str_match(_str, pat, !ignore_case) != 0 : empty();
|
||
}
|
||
|
||
int TString::replace(char find_char, char replace_char)
|
||
{
|
||
int n = 0;
|
||
for (int i = 0; _str[i]; i++)
|
||
if (_str[i] == find_char)
|
||
{
|
||
_str[i] = replace_char;
|
||
n++;
|
||
}
|
||
return n;
|
||
}
|
||
|
||
|
||
// Certified 99%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna l'oggetto TString composto dai <p count> caratteri da sinistra
|
||
const TString& TString::left(
|
||
int count) const // @parm Indica fino quale carattere restituire la stringa
|
||
|
||
// @rdesc Ritorna l'indirizzo della stringa contenente i <p count> caratteri da sinistra
|
||
{
|
||
return mid(0, count);
|
||
}
|
||
|
||
// Certified 99%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna l'oggetto TString composto dai <p count> caratteri da destra
|
||
const TString& TString::right(
|
||
int count) const // @parm Indica da quale carattere restituire la stringa
|
||
|
||
// @rdesc Ritorna l'indirizzo della stringa contenente i <p count> caratteri da destra
|
||
{
|
||
int from = len()-count;
|
||
if (from <= 0)
|
||
from = 0;
|
||
return mid(from);
|
||
}
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna l'oggetto TString composto dai <p count> caratteri a partire
|
||
// da <p from>
|
||
const TString& TString::mid(
|
||
int from, // @parm Posizione dalla quale partire per l'estrazione
|
||
int count) const // @parm Numero di caratteri da estrarre
|
||
|
||
// @rdesc Ritorna l'indirizzo della stringa contenente i <p count> cartteri da <p from>
|
||
{
|
||
CHECKD(from >= 0, "Invalid MID parameter: from ", from);
|
||
|
||
const int l = len();
|
||
if (count < 0 || from+count>l)
|
||
count = l-from;
|
||
|
||
if (from >= l || count == 0)
|
||
return EMPTY_STRING;
|
||
|
||
TString& spark = get_tmp_string(count);
|
||
spark.strncpy(&_str[from], count);
|
||
return spark;
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna la stringa da <p from> a <p to> (escluso)
|
||
const TString& TString::sub(
|
||
int from, // @parm Posizione dalla quale estrarre la stringa
|
||
int to) const // @parm Posizione fin alla quale estrarre la stringa
|
||
|
||
// @rdesc Ritorna l'indirizzo della stringa da i <p from> a <p to>
|
||
{
|
||
const int count = to-from;
|
||
return mid(from, count);
|
||
}
|
||
|
||
const TString& TString::after(char c) const
|
||
{
|
||
const int pos = find(c);
|
||
if (pos >= 0)
|
||
return mid(pos+1);
|
||
return EMPTY_STRING;
|
||
}
|
||
|
||
const TString& TString::after(const char* str) const
|
||
{
|
||
if (str && *str)
|
||
{
|
||
const int pos = find(str);
|
||
if (pos >= 0)
|
||
return mid(pos+strlen(str));
|
||
}
|
||
return EMPTY_STRING;
|
||
}
|
||
|
||
const TString& TString::before(char c) const
|
||
{
|
||
const int pos = find(c);
|
||
if (pos >= 0)
|
||
return left(pos);
|
||
return *this;
|
||
}
|
||
|
||
const TString& TString::before(const char* str) const
|
||
{
|
||
if (str && *str)
|
||
{
|
||
const int pos = find(str);
|
||
if (pos >= 0)
|
||
return left(pos);
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// Certified 100%
|
||
TString& TString::cut(int n)
|
||
{
|
||
CHECKD(n >= 0, "Invalid TString::cut position ", n);
|
||
if (n <= _size)
|
||
_str[n] = '\0';
|
||
return *this;
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
// @mfunc Espande la stringa fino alla lunghezza indicata, eventualmente aggiungendo spazi a destra
|
||
TString& TString::rpad(const int n,const char c)
|
||
{
|
||
const int l = len();
|
||
if (n > l)
|
||
{
|
||
if (n > size()) resize(n, true);
|
||
memset(_str+l, c, n-l);
|
||
_str[n] = '\0';
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
// @mfunc Espande la stringa fino alla lunghezza indicata, eventualmente aggiungendo spazi a sinistra
|
||
TString& TString::lpad(const int n,const char c)
|
||
{
|
||
int l=len();
|
||
const int nsp=n-l;
|
||
if (n>l)
|
||
{
|
||
if (n > size()) resize(n, true);
|
||
for (l--; l>=0; l--)
|
||
*(_str+l+nsp)=*(_str+l);
|
||
memset(_str, c, nsp);
|
||
_str[n] = '\0';
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Elimina gli spazi da sinistra o i primi n caratteri (da sinistra).
|
||
TString& TString::ltrim(
|
||
int count) // @parm Indica il numero di caratteri da eliminare.
|
||
// Se uguale a 0 elimina tutti gli spazi da sinistra
|
||
|
||
// @comm Controlla se <p count> e' 0. Se non lo <20> ritorna l'indirizzo della
|
||
// stringa a partire dal <p count>-esimo carattere; altrimenti controlla
|
||
// se i primi caratteri sono spazi e li elimina fino a che non trova
|
||
// un carattere diverso da ' '
|
||
//
|
||
// @xref <mf TString::rtrim>
|
||
{
|
||
const char* s;
|
||
|
||
if (count > 0)
|
||
{
|
||
if (count >= len())
|
||
return cut(0);
|
||
s = &_str[count];
|
||
}
|
||
else
|
||
for (s = _str; *s && is_space(*s); s++);
|
||
|
||
if (s != _str)
|
||
strcpy_s(_str, _size+1, s);
|
||
|
||
return *this;
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Elimina gli spazi da destra o i primi n caratteri (da destra).
|
||
TString& TString::rtrim(
|
||
int count) // @parm Indica il numero di caratteri da eliminare.
|
||
// Se uguale a 0 elimina tutti gli spazi da destra
|
||
|
||
// @comm Controlla se <p count> e' 0. Se non lo e' pone il fine stringa alla
|
||
// posizione <p count>; altrimenti controlla se gli ultimi caratteri
|
||
// sono spazi e li elimina fino a che non trova un carattere diverso da ' '
|
||
//
|
||
// @xref <mf TString::ltrim>
|
||
{
|
||
if (count > 0)
|
||
{
|
||
int i = len() - count;
|
||
if (i < 0) i = 0;
|
||
cut(i);
|
||
}
|
||
else
|
||
{
|
||
char* good = _str-1;
|
||
for (char* s = _str; *s; s++)
|
||
if (!is_space(*s)) good = s;
|
||
*(good+1) = '\0';
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
TString& TString::trim()
|
||
{
|
||
char* last = _str;
|
||
const char * s;
|
||
|
||
// Salta spazi iniziali
|
||
for (s = _str; *s && is_space(*s); s++);
|
||
|
||
// Copia stringa
|
||
if (s > _str)
|
||
{
|
||
for(char* c = _str; *s; s++)
|
||
{
|
||
*c++ = *s;
|
||
if (!is_space(*s)) last = c;
|
||
}
|
||
// Elimina spazi finali
|
||
*last = '\0';
|
||
}
|
||
else rtrim();
|
||
|
||
return *this;
|
||
}
|
||
|
||
// Certified 50%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Compara due stringhe (o i primi <p max> caratteri)
|
||
//
|
||
// @rdesc Ritrna i seguenti valori:
|
||
//
|
||
// @flag 0 | Se le stringhe sono uguali
|
||
// @flag <gt><lt>0 | Se le stringhe sono diverse
|
||
int TString::compare(
|
||
const char* s, // @parm Stringa da comparare
|
||
int max, // @parm Numero di caratteri da conforntare (default tutta la stringa)
|
||
bool ignorecase) const // @parm Ignorare la differenza maiuscolo/minuscolo (default false)
|
||
{
|
||
int res = 0;
|
||
|
||
if (s == NULL) s = "";
|
||
if (ignorecase)
|
||
{
|
||
if (max < 0)
|
||
res = xvt_str_compare_ignoring_case(_str, s);
|
||
else
|
||
{
|
||
for (int i = 0; i < max; i++)
|
||
{
|
||
res = toupper(_str[i]) - toupper(s[i]);
|
||
if (res) break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
res = max < 0 ? strcmp(_str, s) : strncmp(_str, s, max);
|
||
|
||
return res;
|
||
}
|
||
|
||
bool TString::starts_with(const char* s, bool ignorecase) const
|
||
{
|
||
return (s && *s) ? (compare(s, strlen(s), ignorecase) == 0) : true;
|
||
}
|
||
|
||
bool TString::ends_with(const char* s, bool ignorecase) const
|
||
{
|
||
const int mylen = len();
|
||
const int slen = (s && *s) ? strlen(s) : 0;
|
||
bool yes = false;
|
||
if (slen > 0 && slen <= mylen)
|
||
{
|
||
if (slen > 1)
|
||
{
|
||
if (slen != mylen)
|
||
{
|
||
const TString& fine = right(slen);
|
||
yes = fine.compare(s, slen, ignorecase) == 0;
|
||
}
|
||
else
|
||
yes = compare(s, -1, ignorecase) == 0;
|
||
}
|
||
else
|
||
{
|
||
if (ignorecase)
|
||
yes = toupper(_str[mylen-1]) == toupper(s[0]);
|
||
else
|
||
yes = _str[mylen-1] == s[0];
|
||
}
|
||
}
|
||
return yes;
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Riempe la stringa con n caratteri c
|
||
//
|
||
// @rdesc Ritorna l'indirizzo dell stringa
|
||
TString& TString::fill(
|
||
char c, // @parm Caratteri con cui riempire la stringa
|
||
int n) // @parm Numero di caratteri da inserire nella stringa
|
||
// (default per tutta la lungehzza)
|
||
|
||
// @comm Se il paramatro <p n> e' maggiore della dimensione della stringa, la
|
||
// stessa viene ridimensionata (chaimata alla <mf TString::resize>).
|
||
// <nl>Nel caso non venga passato il parametro <p n> la stringa viene
|
||
// riempita col carattere <p c> per tutta la lunghezza.
|
||
|
||
{
|
||
if (n < 0)
|
||
n = size();
|
||
else
|
||
if (n > size())
|
||
resize(n, false);
|
||
memset(_str, c, n);
|
||
_str[n] = '\0';
|
||
return *this;
|
||
}
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Giustifica l'oggetto stringa a destra
|
||
TString& TString::right_just(
|
||
int n, // @parm Numero di colonne alla quali allineare (defualt larghezza della stringa)
|
||
char c) // @parm Carattere di riempimento (default ' ')
|
||
|
||
// @comm Nel caso venga passato un carattere in <p c>, questo viene inserito
|
||
// nel resto della stringa (a sinistra della stringa stessa)
|
||
//
|
||
// @xref <mf TString::left_just> <mf TString::center_just>
|
||
{
|
||
if (n < 0)
|
||
n = size();
|
||
trim();
|
||
if (len() < n)
|
||
{
|
||
TString& spark = get_tmp_string();
|
||
spark = _str;
|
||
fill(c, n);
|
||
overwrite(spark, n-spark.len());
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Centra l'oggetto stringa
|
||
TString& TString::center_just(
|
||
int n, // @parm Numero di colonne alla quali allineare (defualt larghezza della stringa)
|
||
char c) // @parm Carattere di riempimento (default ' ')
|
||
|
||
// @comm Nel caso venga passato un carattere in <p c>, questo viene inserito
|
||
// nel resto della stringa (a destra e a sinistra della stringa stessa)
|
||
//
|
||
// @xref <mf TString::left_just> <mf TString::right_just>
|
||
{
|
||
if (n < 0)
|
||
n = size();
|
||
trim();
|
||
if (len() < n)
|
||
{
|
||
TString& spark = get_tmp_string();
|
||
spark = _str;
|
||
fill(c, n);
|
||
const int p = (n-spark.len()) >> 1;
|
||
overwrite(spark, p);
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
// Certified 100%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Giustifica l'oggetto stringa a sinistra
|
||
TString& TString::left_just(
|
||
int n, // @parm Numero di colonne alla quali allineare (defualt larghezza della stringa)
|
||
char c) // @parm Carattere di riempimento (default ' ')
|
||
|
||
// @comm Nel caso venga passato un carattere in <p c>, questo viene inserito
|
||
// nel resto della stringa (a destra della stringa stessa)
|
||
//
|
||
// @xref <mf TString::right_just> <mf TString::center_just>
|
||
{
|
||
if (n < 0)
|
||
n = size();
|
||
trim();
|
||
if (len() < n)
|
||
{
|
||
TString& spark = get_tmp_string();
|
||
spark = _str;
|
||
fill(c, n);
|
||
overwrite(spark, 0);
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Formatta una stringa usando il formato dato da <p pic>
|
||
TString& TString::picture(
|
||
const char* pic, // @parm Formato della stringa
|
||
const char* s) // @parm Stringa da formattare
|
||
{
|
||
if (pic == NULL || *pic == '\0')
|
||
return set(s);
|
||
|
||
set(pic);
|
||
|
||
int l = strlen(s)-1; // Prossimo carattere da sostituire a # o @
|
||
|
||
for (int i = len()-1; i >= 0; i--)
|
||
{
|
||
const char k = pic[i];
|
||
if (k == '#') _str[i] = (l >= 0) ? s[l--] : ' ';
|
||
else if (k == '@') _str[i] = (l >= 0) ? s[l--] : '0';
|
||
else if (k == '^') { _str[i] = ' '; l--; }
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
// Certified 99% (s != NULL)
|
||
int TString::strncpy(const char* s, int n)
|
||
{
|
||
int i = 0;
|
||
if (s && *s && n>0)
|
||
{
|
||
if (n > size())
|
||
resize(n, false);
|
||
strncpy_s(_str, _size+1, s, n);
|
||
i = strlen(s);
|
||
if (n < i) i = n;
|
||
}
|
||
_str[i] = '\0';
|
||
return i;
|
||
}
|
||
|
||
// Certified 90% (spark size limited)
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Manda un output formattato alla stringa oggetto
|
||
TString& TString::format(
|
||
const char* fmt, // @parm Stringa da formattare
|
||
...) // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
|
||
|
||
// @comm Funziona come la funzione "sprintf" standard del C e ritorna la
|
||
// stringa formattata con i parametri passati.
|
||
{
|
||
char spark[512] = { 0 };
|
||
va_list pars;
|
||
va_start(pars, fmt);
|
||
const unsigned int tot = _vsnprintf(spark, sizeof(spark), fmt, pars);
|
||
va_end(pars);
|
||
|
||
CHECK(tot < sizeof(spark), "Ue'! Quanto scrivi?");
|
||
return set(spark);
|
||
}
|
||
|
||
// Certified 99%
|
||
char* TString::get_buffer(int min_size)
|
||
{
|
||
if (min_size > size())
|
||
resize(min_size, true);
|
||
return _str;
|
||
}
|
||
|
||
// Certified 99%
|
||
TString& TString::upper(int from, int to)
|
||
{
|
||
for (int c=0; *(_str+c) && (to<0 || c<=to); c++)
|
||
if (c>=from)
|
||
*(_str+c) = toupper(*(_str+c));
|
||
return *this;
|
||
}
|
||
|
||
// Certified 99%
|
||
TString& TString::lower(int from, int to)
|
||
{
|
||
for (int c=0; *(_str+c) && (to<0 || c<=to); c++)
|
||
if (c>=from)
|
||
*(_str+c) = tolower(*(_str+c));
|
||
return *this;
|
||
}
|
||
|
||
// Certified 50%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Permette di ttrovare il plurale di una stringa
|
||
TString& TString::add_plural(
|
||
long num, // @parm Numero di elementi per sapere la desineneza
|
||
const char* name) // @parm Stringa da modificare
|
||
|
||
// @comm A seconda del numero passato in <p num> permette di stabilire la
|
||
// corretta sintassi della stringa <p name> da scrivere nei messaggi
|
||
// dati all'utente. Nel caso <p num> sia 0 allora ritorna "nessuno".
|
||
{
|
||
const TFixed_string n(name);
|
||
const char last = n[n.len()-1];
|
||
|
||
if (num < 1)
|
||
{
|
||
*this << "nessun";
|
||
if (toupper(last) == 'A' || toupper(n[0]) == 'Z' ||
|
||
toupper(n[0]) == 'S' && strchr("aeiouAEIOU", n[1]) == NULL)
|
||
*this << tolower(last);
|
||
*this << ' ' << name;
|
||
}
|
||
else
|
||
{
|
||
*this << num << ' ' << name;
|
||
if (num > 1)
|
||
_str[len()-1] = (last == 'a') ? 'e' : 'i';
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
// Certified 90%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Sovrascrive la stringa <p s> dalla posizione <p pos>
|
||
TString& TString::overwrite(
|
||
const char* s, // @parm Stringa da inserire
|
||
int pos, // @parm Posizione dalla quale iniziare a sovrascrivere
|
||
int lung) // @parm Lunghezza massima da scrivere
|
||
|
||
// @comm Sovrascrive dalla posizione <p pos> fino alla lunghezza di <p s> l'oggetto
|
||
// stringa. Nel caso la dimensione sia maggiore l'oggetto viene riallocato
|
||
// dinamicamente
|
||
//
|
||
// @xref <mf TString::insert>
|
||
{
|
||
if (s == NULL) s = "";
|
||
if (lung <= 0 && *s)
|
||
lung=strlen(s);
|
||
if (lung > 0)
|
||
{
|
||
const int l = len();
|
||
if (pos < 0) pos = l;
|
||
const int max = pos+lung;
|
||
if (max > size()) resize(max, true); // resize needed?
|
||
|
||
const bool over = max > l; // beyond end of string?
|
||
for (int i = l; i < pos; i++) _str[i] = ' '; // space padding per inserimenti dopo la fine della stringa
|
||
for (; *s && pos < max; s++) _str[pos++] = *s;// write
|
||
for (; pos < max ; pos++) _str[pos] = ' '; // space padding per inserimenti con stringhe minori della lunghezza prevista
|
||
if (over) _str[pos] = '\0'; // end of string
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
|
||
// Certified 90%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Inserisce la stringa s dalla posizione pos
|
||
TString& TString::insert(
|
||
const char* s, // @parm Stringa da inserire
|
||
int pos) // @parm Posizione dalla quale iniziare a inserire
|
||
|
||
// @comm Inserisce dalla posizione <p pos> la stringa <p s> nell'oggetto
|
||
// stringa. Nel caso la dimensione sia maggiore l'oggetto viene riallocato
|
||
// dinamicamente
|
||
//
|
||
// @xref <mf TString::overwrite>
|
||
{
|
||
CHECK(s != _str, "Can't autoinsert string");
|
||
if (s && *s)
|
||
{
|
||
const int l = strlen(s);
|
||
make_room(l);
|
||
const TString& spark = mid(pos); // Scrivi in spark la stringa da pos in poi
|
||
overwrite(s, pos); // Aggiungi s
|
||
strcpy_s(&_str[pos+l], _size-(pos+l)+1, spark); // Aggiungi spark
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// Certified 90%
|
||
word TString::hash() const
|
||
{
|
||
/*
|
||
// Villa's megasmart hash function
|
||
word h = 0x0000;
|
||
for (int i = 0; _str[i]; i++)
|
||
h ^= (i & 0x1) ? (_str[i] << 8) : _str[i];
|
||
*/
|
||
// Peter Weinberger's (PJW) generic hashing
|
||
word h = 0;
|
||
for (const char* s = _str; *s; s++)
|
||
{
|
||
h = (h << 2) + *s;
|
||
const word i = h & 0xC000;
|
||
if (i) h = (h ^ (i >> 12)) & 0x3FFF;
|
||
}
|
||
return h;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TFixed_string
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// Certified 99%
|
||
// Se la size del buffer str <20> di 16, allora la size stringa <20> di 15 (15 + '\0' = 16)
|
||
// es: char buf[16]; TFixed_string str(buf, sizeof(buf));
|
||
TFixed_string::TFixed_string(const char* str, int size)
|
||
: TString((char*)str, (size <= 0) ? strlen(str) : size-1)
|
||
{
|
||
CHECK(str, "NULL buffer for fixed string");
|
||
if (size > 0 && memchr(str, '\0', size) == NULL)
|
||
cut(0);
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
TFixed_string::~TFixed_string()
|
||
{ _str = NULL; } // Impedisce la deallocazione
|
||
|
||
// Certified 100%
|
||
void TFixed_string::resize(int size, bool)
|
||
{
|
||
fatal_box("Impossibile ridimensionare una stringa fissa da %d a %d caratteri:\n'%s'",
|
||
_size, size, _str);
|
||
}
|
||
|
||
// Certified 99%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Manda un output formattato alla stringa oggetto
|
||
TString& TFixed_string::format(
|
||
const char* fmt, // @parm Formato della stringa
|
||
...) // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
|
||
|
||
// @comm Funziona come la funzione "sprintf" standard del C e ritorna la
|
||
// stringa formattata con i parametri passati.
|
||
// <nl>E' piu' efficiente di <mf TString::format> poiche' non usa spark
|
||
{
|
||
va_list pars;
|
||
va_start(pars, fmt);
|
||
const int tot = _vsnprintf(_str, size()+1, fmt, pars);
|
||
va_end(pars);
|
||
CHECK(tot >= 0 && tot <= size(), "Ue'! Quanto scrivi con 'sta format?");
|
||
return *this;
|
||
}
|
||
|
||
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// Filename
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// Certified 90%
|
||
const char* TFilename::ext() const
|
||
{
|
||
/* Riduciamo il parsing "manuale" dei nomi dei file
|
||
const char* d = strrchr(name(), '.');
|
||
if (d && is_not_slash(*(++d)))
|
||
return d;
|
||
return "";
|
||
*/
|
||
if (rfind('.') > 0)
|
||
{
|
||
char e[_MAX_EXT];
|
||
xvt_fsys_parse_pathname(_str, NULL, NULL, NULL, e, NULL);
|
||
return get_tmp_string() = e;
|
||
}
|
||
return "";
|
||
}
|
||
|
||
// Certified 90%
|
||
void TFilename::ext(const char* e)
|
||
{
|
||
/* Riduciamo il parsing "manuale" dei nomi dei file
|
||
int start = find(' ')-1;
|
||
if (start < 0)
|
||
start = len()-1;
|
||
|
||
bool can_cut = true;
|
||
int i;
|
||
for (i = start; i > 0 && _str[i] != '.'; i--)
|
||
if (is_slash(_str[i]) || _str[i] == ':')
|
||
{
|
||
can_cut = false;
|
||
i = start;
|
||
break;
|
||
}
|
||
|
||
if (i > 0 && can_cut && is_not_slash(_str[i+1]))
|
||
cut(i);
|
||
if (*e)
|
||
{
|
||
if (*e != '.')
|
||
*this << ".";
|
||
*this << e;
|
||
}
|
||
*/
|
||
char v[_MAX_DRIVE], d[_MAX_DIR], n[_MAX_FNAME], p[_MAX_PATH];
|
||
xvt_fsys_parse_pathname(_str, v, d, n, NULL, NULL);
|
||
xvt_fsys_build_pathname(p, v, d, n, e, NULL);
|
||
set(p);
|
||
}
|
||
|
||
// Certified 95%
|
||
const char* TFilename::name() const
|
||
{
|
||
/* Riduciamo il parsing "manuale" dei nomi dei file
|
||
int start = find(' ')-1;
|
||
if (start < 0)
|
||
start = len()-1;
|
||
int i;
|
||
for (i = start; i >= 0; i--)
|
||
if (is_slash(_str[i]) || _str[i] == ':')
|
||
break;
|
||
|
||
TString& spark = get_tmp_string();
|
||
spark = &_str[i+1];
|
||
spark.cut(start-i);
|
||
return spark;
|
||
*/
|
||
if (full())
|
||
{
|
||
char n[_MAX_FNAME], e[_MAX_EXT];
|
||
xvt_fsys_parse_pathname(_str, NULL, NULL, n, e, NULL);
|
||
TString& spark = get_tmp_string();
|
||
spark = n;
|
||
if (*e)
|
||
spark << '.' << e;
|
||
return spark;
|
||
}
|
||
return "";
|
||
}
|
||
|
||
// Certified 95%
|
||
const TString& TFilename::name_only() const
|
||
{
|
||
if (full())
|
||
{
|
||
char n[_MAX_FNAME];
|
||
xvt_fsys_parse_pathname(_str, NULL, NULL, n, NULL, NULL);
|
||
return get_tmp_string() = n;
|
||
}
|
||
return EMPTY_STRING;
|
||
}
|
||
|
||
// Certified 95%
|
||
const char* TFilename::path() const
|
||
{
|
||
/* Riduciamo il parsing "manuale" dei nomi dei file
|
||
int start = find(' ')-1;
|
||
if (start < 0)
|
||
start = len()-1;
|
||
int i;
|
||
for (i = start; i >= 0; i--)
|
||
if (is_slash(_str[i]) || _str[i] == ':')
|
||
break;
|
||
TString& spark = get_tmp_string();
|
||
spark = _str;
|
||
spark.cut(i+1);
|
||
return spark;
|
||
*/
|
||
if (full())
|
||
{
|
||
char v[_MAX_DRIVE], d[_MAX_DIR];
|
||
xvt_fsys_parse_pathname(_str, v, d, NULL, NULL, NULL);
|
||
TString& spark = get_tmp_string();
|
||
spark << v << d;
|
||
if (spark.not_empty() && !is_slash(spark.right(1)[0]))
|
||
spark << SLASH;
|
||
return spark;
|
||
}
|
||
return EMPTY_STRING;
|
||
}
|
||
|
||
TFilename& TFilename::add(const char* n)
|
||
{
|
||
const int flag = (not_empty() && is_slash(_str[len()-1]) ? 1 : 0) + (n && is_slash(*n) ? 2 : 0);
|
||
switch (flag)
|
||
{
|
||
case 0: *this << SLASH << n; break;
|
||
case 3: *this << (n+1); break;
|
||
default: *this << n; break;
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Controlla il formato del nome del file
|
||
//
|
||
// @rdesc Ritorna i seguenti valori
|
||
//
|
||
// @flag true | Se il nome del file e' sintatticamente corretto
|
||
// @flag false | Se il nome del file non e' sintatticamente corretto
|
||
bool TFilename::ok() const
|
||
|
||
// @comm Controlla tutti i casi per cui un nome di file puo' non essere valido.
|
||
// <nl>Nel caso si lavori in Windows controlla anche che il nome del
|
||
// disco sia corretto.
|
||
{
|
||
const int l = len();
|
||
|
||
int len = 0; // lunghezza ultima sottostringa
|
||
bool ext = false; // trovata estensione
|
||
|
||
for (int c = 0; c < l; c++)
|
||
{
|
||
switch(_str[c])
|
||
{
|
||
#if XVT_OS == XVT_OS_WIN32
|
||
case ':':
|
||
if (c != 1 || !isalpha(_str[0])) return false; // Nome disco errato
|
||
len = 0;
|
||
break;
|
||
case '\\':
|
||
#endif
|
||
case '/':
|
||
if (ext) return false; // Slash dopo estensione
|
||
if (len > _MAX_FNAME) return false; // Nome troppo lungo
|
||
if (!isalnum(_str[++c])) return false;
|
||
len = 1;
|
||
break;
|
||
case '.':
|
||
if (len == 0 || ext) return false; // Nome nullo o Doppia estensione
|
||
ext = true;
|
||
len = 0;
|
||
c++;
|
||
default:
|
||
if (isalnum(_str[c])) len++;
|
||
else return false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (ext && len > _MAX_EXT)
|
||
return false;
|
||
|
||
return len > 0 && len <= _MAX_FNAME;
|
||
}
|
||
|
||
// Certified 70%
|
||
TFilename& TFilename::tempdir()
|
||
{
|
||
static TFilename _tempdir;
|
||
const bool create = _tempdir.empty() || !_tempdir.ends_with(user(), true);
|
||
|
||
if (create)
|
||
{
|
||
const int maxlen = 28; // Lunghezza max nome file temporaneo = 42 -> lunghezza max cartella 42-14 = 28
|
||
DIRECTORY tmp = { 0 }; xvt_fsys_get_temp_dir(&tmp);
|
||
xvt_fsys_convert_dir_to_str(&tmp, _tempdir.get_buffer(), _tempdir.size());
|
||
if (_tempdir.len() > maxlen) // troppo lunga!
|
||
{
|
||
_tempdir.currdir().add("temp");
|
||
if (_tempdir.len() > maxlen) // ancora troppo lunga!
|
||
_tempdir = "c:\\temp";
|
||
xvt_sys_set_profile_string(NULL, "Main", "Temp", _tempdir);
|
||
}
|
||
bool ok = dexist(_tempdir);
|
||
if (!ok) // Codebase NON funziona senza una temp esistente!
|
||
{
|
||
ok = make_dir(_tempdir);
|
||
if (!ok)
|
||
cantwrite_box(_tempdir);
|
||
}
|
||
|
||
const int last = len()-1;
|
||
if (is_slash(_str[last]))
|
||
_tempdir.cut(last);
|
||
_tempdir.lower();
|
||
|
||
TString theuser = user();
|
||
if (theuser.blank())
|
||
theuser = ::dongle().administrator();
|
||
theuser.lower();
|
||
if (!_tempdir.ends_with(user(), true))
|
||
_tempdir.add(theuser);
|
||
|
||
ok = dexist(_tempdir);
|
||
if (!ok)
|
||
{
|
||
ok = make_dir(_tempdir);
|
||
if (!ok)
|
||
cantwrite_box(_tempdir);
|
||
}
|
||
|
||
xvt_sys_set_env("TMP", _tempdir); // Usata da _tmpnam
|
||
}
|
||
|
||
set(_tempdir);
|
||
return *this;
|
||
}
|
||
|
||
TFilename& TFilename::currdir()
|
||
{
|
||
DIRECTORY d; xvt_fsys_get_dir(&d);
|
||
xvt_fsys_convert_dir_to_str(&d, get_buffer(), size());
|
||
return *this;
|
||
}
|
||
|
||
TFilename& TFilename::slash_terminate()
|
||
{
|
||
if (empty())
|
||
operator<<(SLASH);
|
||
else
|
||
{
|
||
if (!is_slash(_str[len()-1]))
|
||
operator<<(find("/") >= 0 ? '/' : '\\');
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
// @mfunc Genera il nome di un file temporaneo
|
||
TFilename& TFilename::temp(
|
||
const char* prefix, // @parm Eventuale prefisso da assegnare al file temporaneo
|
||
const char* extension) // @parm Eventuale estensione da assegnare al file temporaneo
|
||
|
||
// @comm Nel generare il nome del file controlla se esistono dei caratteri jolly e li elimina.
|
||
{
|
||
TFilename root; root.tempdir();
|
||
root.slash_terminate();
|
||
if (prefix && *prefix)
|
||
{
|
||
bool has_path = false;
|
||
for (const char *s = prefix; !has_path && *s; s++)
|
||
has_path = *s ==':' || is_slash(*s);
|
||
if (has_path)
|
||
{
|
||
root = prefix;
|
||
if (xvt_fsys_dir_exists(root))
|
||
root.slash_terminate();
|
||
}
|
||
else
|
||
root.add(prefix);
|
||
}
|
||
for (unsigned int n = (unsigned int)clock(); ; n++)
|
||
{
|
||
TString8 name; name.format("%05lu", n % 100000);
|
||
set(root); operator<<(name);
|
||
if (extension && *extension)
|
||
ext(extension);
|
||
if (!exist())
|
||
break;
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
|
||
bool TFilename::is_absolute_path() const
|
||
{
|
||
const char* s = _str;
|
||
if (isalpha(*s) && s[1] == ':')
|
||
s += 2;
|
||
return is_slash(*s);
|
||
}
|
||
|
||
TFilename& TFilename::make_absolute_path()
|
||
{
|
||
if (is_relative_path())
|
||
{
|
||
const TString saved(_str);
|
||
DIRECTORY dir;
|
||
xvt_fsys_get_dir(&dir);
|
||
xvt_fsys_convert_dir_to_str(&dir, get_buffer(), size());
|
||
add(saved);
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
bool TFilename::exist() const
|
||
{
|
||
return full() && ::fexist(_str);
|
||
}
|
||
|
||
bool TFilename::fremove() const
|
||
{
|
||
return xvt_fsys_remove_file(_str) != FALSE;
|
||
}
|
||
|
||
bool TFilename::frename(const char* src_path, const char* dst_path)
|
||
{
|
||
return xvt_fsys_rename_file(src_path, dst_path) != FALSE;
|
||
}
|
||
|
||
bool TFilename::search_in_path(TFilename& path) const
|
||
{
|
||
xvt_sys_search_env(_str, "PATH", path.get_buffer());
|
||
if (path.empty())
|
||
xvt_sys_search_env(_str, "path", path.get_buffer());
|
||
return path.full();
|
||
}
|
||
|
||
bool TFilename::input()
|
||
{
|
||
return input_filename(*this);
|
||
}
|
||
|
||
bool TFilename::custom_path(const char* path_list)
|
||
{
|
||
if (blank()) // Inutile continuare!
|
||
return false;
|
||
// Espando solo i nomi di file senza path (relativo o assoluto)
|
||
if (!starts_with(".") && !is_absolute_path())
|
||
{
|
||
TToken_string pl = path_list;
|
||
if (pl.empty())
|
||
{
|
||
pl.add("custom"); // c:/campo32/custom
|
||
if (prefix_valid())
|
||
{
|
||
TFilename n;
|
||
n = firm2dir(prefix().get_codditta()); n.add("custom");
|
||
pl.add(n); // f:/campo32/dati/00001A/custom
|
||
|
||
n = firm2dir(-1); n.add("custom");
|
||
pl.add(n); // f:/campo32/dati/custom
|
||
}
|
||
}
|
||
const TString fname = name();
|
||
FOR_EACH_TOKEN(pl, path)
|
||
{
|
||
TFilename cust = path;
|
||
cust.add(fname);
|
||
if (cust.exist())
|
||
{
|
||
set(cust);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return exist();
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// Token string
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// Certified 100%
|
||
TToken_string::~TToken_string()
|
||
{
|
||
}
|
||
|
||
// Certified 100%
|
||
TToken_string::TToken_string(const char* s, char separator)
|
||
: TString(s), _separator(separator)
|
||
{
|
||
CHECK(_separator, "NULL TToken_string separator");
|
||
restart();
|
||
}
|
||
|
||
// Certified 100%
|
||
TToken_string::TToken_string(int n, char separator)
|
||
: TString(n), _separator(separator), _last(-1)
|
||
{
|
||
CHECK(_separator, "NULL TToken_string separator");
|
||
}
|
||
|
||
// Certified 100%
|
||
TToken_string::TToken_string(const TToken_string& s)
|
||
: TString(s), _separator(s._separator), _last(s._last)
|
||
{
|
||
CHECK(_separator, "NULL TToken_string separator");
|
||
}
|
||
|
||
const TToken_string& TToken_string::operator =(const TToken_string& s)
|
||
{
|
||
set(s);
|
||
restart();
|
||
separator(s.separator());
|
||
return *this;
|
||
}
|
||
|
||
void TToken_string::separator(char s)
|
||
{
|
||
CHECK(s, "NULL TToken_string separator");
|
||
_separator = s;
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
TObject* TToken_string::dup() const
|
||
{
|
||
return new TToken_string(_str, _separator);
|
||
}
|
||
|
||
// Certified 90%
|
||
const char* TToken_string::get()
|
||
{
|
||
CHECK(_separator, "Corrupted TToken_string: NULL separator");
|
||
|
||
if (_last < 0) return NULL;
|
||
|
||
const int start = _last;
|
||
|
||
if (_str[start] == '\0')
|
||
{
|
||
_last = -1;
|
||
return NULL;
|
||
}
|
||
else
|
||
if (_str[start] == _separator)
|
||
{
|
||
_last = start+1;
|
||
}
|
||
else
|
||
{
|
||
const int k = find(_separator, start);
|
||
_last = (k >= 0) ? k+1 : -1;
|
||
return sub(start, k);
|
||
}
|
||
return "";
|
||
}
|
||
|
||
// Certified 50%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna un Token
|
||
//
|
||
// @rdesc Ritorna la stringa alla posizione <p n>
|
||
const char* TToken_string::get(
|
||
int n) // @parm Token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
|
||
// @syntax const char* get(int n);
|
||
// @syntax const char* get();
|
||
//
|
||
// @comm Se non viene passato il parametro <p n> ritorna il prossimo Token
|
||
// (come se <p n> == -1)
|
||
//
|
||
// @xref <mf TToken_string::get_char>
|
||
{
|
||
CHECK(_separator, "Corrupted TToken_string: NULL separator");
|
||
|
||
if (n < 0)
|
||
{
|
||
if (n == -2)
|
||
{
|
||
const char* sep = strrchr(_str, _separator);
|
||
_last = -1;
|
||
return sep ? sep+1 : _str;
|
||
}
|
||
else
|
||
return get();
|
||
}
|
||
int sep = 0;
|
||
const char * s;
|
||
|
||
for (s = _str; sep < n && *s; s++)
|
||
if (*s == _separator) sep++;
|
||
|
||
if (sep >= n)
|
||
{
|
||
char* p = (char*)strchr(s, _separator); //antica porcata
|
||
TString& spark = get_tmp_string();
|
||
|
||
if (p == NULL)
|
||
{
|
||
_last = -1;
|
||
spark = s;
|
||
}
|
||
else
|
||
{
|
||
*p = '\0';
|
||
spark = s;
|
||
*p = _separator;
|
||
_last = (int)((const char*)p - _str) + 1;
|
||
}
|
||
return spark;
|
||
}
|
||
|
||
_last = -1;
|
||
return NULL;
|
||
}
|
||
|
||
// Certified 99%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna un carattere
|
||
//
|
||
// @rdesc Ritorna il primo carattere del Token richiesto
|
||
char TToken_string::get_char(
|
||
int n) // @parm Token da ritornare
|
||
|
||
// @comm Chiama la <mf TToken_string::get> con tutti i relativi significati per
|
||
// il parametro <p n>
|
||
{
|
||
const char* const car = get(n);
|
||
return car ? *car : '\0';
|
||
}
|
||
|
||
// Certified 99%
|
||
int TToken_string::get_int(int n)
|
||
{
|
||
const char* const num = get(n);
|
||
return num ? atoi(num) : 0;
|
||
}
|
||
|
||
|
||
// Certified 99%
|
||
long TToken_string::get_long(int n)
|
||
{
|
||
const char* const num = get(n);
|
||
return num ? atol(num) : 0L;
|
||
}
|
||
|
||
|
||
// const TToken_string new age!
|
||
|
||
// @rdesc Ritorna true se e' stata trovata una stringa alla posizione <p n>
|
||
bool TToken_string::get(
|
||
int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
TString& tok) const // @parm Stringa da ritornare
|
||
// @syntax const char* get(TString& str, int n);
|
||
//
|
||
// @xref <mf TToken_string::get_char>
|
||
{
|
||
CHECK(_separator, "Corrupted TToken_string: NULL separator");
|
||
|
||
if (n < 0)
|
||
{
|
||
const char* sep = strrchr(_str, _separator);
|
||
tok = sep ? sep+1 : _str;
|
||
return tok.not_empty();
|
||
}
|
||
|
||
int sep = 0;
|
||
const char* s;
|
||
for (s = _str; *s && sep < n; s++)
|
||
if (*s == _separator) sep++;
|
||
|
||
bool found = sep == n;
|
||
if (found)
|
||
{
|
||
char* p = (char*)strchr(s, _separator); //antica porcata
|
||
if (p == NULL)
|
||
{
|
||
tok = s;
|
||
found = tok.not_empty();
|
||
}
|
||
else
|
||
{
|
||
*p = '\0';
|
||
tok = s;
|
||
*p = _separator;
|
||
}
|
||
}
|
||
else
|
||
tok.cut(0);
|
||
|
||
return found;
|
||
}
|
||
|
||
bool TToken_string::get(
|
||
int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
char& tok) const // @parm char da ritornare
|
||
{
|
||
TString16 str;
|
||
bool found = get(n, str);
|
||
tok = found ? str[0] : '\0';
|
||
return found;
|
||
}
|
||
|
||
bool TToken_string::get(
|
||
int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
int& tok) const // @parm int da ritornare
|
||
{
|
||
TString16 str;
|
||
bool found = get(n, str);
|
||
tok = found ? atoi(str) : 0;
|
||
return found;
|
||
}
|
||
|
||
bool TToken_string::get(
|
||
int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
long& tok) const // @parm long da ritornare
|
||
{
|
||
TString16 str;
|
||
const bool found = get(n, str);
|
||
tok = found ? atol(str) : 0L;
|
||
return found;
|
||
}
|
||
|
||
bool TToken_string::get(
|
||
int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
real& tok) const // @parm real da ritornare
|
||
{
|
||
TString80 str;
|
||
const bool found = get(n, str);
|
||
tok = found ? real(str) : ZERO;
|
||
return found;
|
||
}
|
||
|
||
bool TToken_string::get(
|
||
int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo)
|
||
TDate& tok) const // @parm TDate da ritornare
|
||
{
|
||
TString16 str;
|
||
bool found = get(n, str);
|
||
if (found && TDate::isdate(str))
|
||
tok = TDate(str);
|
||
else
|
||
tok = botime;
|
||
return found;
|
||
}
|
||
|
||
// Certified 90%
|
||
bool TToken_string::set_item(const char* v, int n)
|
||
{
|
||
CHECK(_separator, "Corrupted TToken_string: NULL separator");
|
||
TString& spark = get_tmp_string();
|
||
|
||
int sep = 0, i;
|
||
for (i = 0; sep < n && _str[i]; i++)
|
||
if (_str[i] == _separator) sep++;
|
||
|
||
if (sep < n) // Aggiunge items mancanti prima della posizione n
|
||
{
|
||
for (;sep < n; sep++)
|
||
*this << _separator;
|
||
*this << v;
|
||
return false;
|
||
}
|
||
|
||
int e = find(_separator, i);
|
||
if (e < 0) e = len();
|
||
|
||
spark = _str+e; // Salva items seguenti
|
||
cut(i); // Considera solo items precedenti
|
||
*this << v << spark; // Aggiunge item desiderato e seguenti
|
||
return true;
|
||
}
|
||
|
||
|
||
// Certified 80%
|
||
int TToken_string::get_pos(const char* s)
|
||
{
|
||
const char* item;
|
||
|
||
restart();
|
||
for (int i = 0; (item = get()) != NULL; i++)
|
||
if (strcmp(item, s) == 0) return i;
|
||
|
||
return -1;
|
||
}
|
||
|
||
// Certified 80%
|
||
int TToken_string::get_pos(long n)
|
||
{
|
||
char s[16]; _ltoa(n, s, 10);
|
||
return get_pos(s);
|
||
}
|
||
|
||
// Certified 90%
|
||
bool TToken_string::empty_items() const
|
||
{
|
||
for (const char* c = _str; *c; c++)
|
||
if (!is_space(*c) && *c != _separator)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
// Certified 80%
|
||
int TToken_string::items() const
|
||
{
|
||
int t = 0;
|
||
if (not_empty())
|
||
{
|
||
t++;
|
||
for (const char* s = _str; *s; s++)
|
||
if (*s == _separator) t++;
|
||
}
|
||
return t;
|
||
}
|
||
|
||
// Certified 99%
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Aggiunge un elemento alla token string
|
||
void TToken_string::add(
|
||
const char* s, // @parm Stringa da aggiungere
|
||
int pos) // @parm Posizione nella quale aggiungere l'elemento
|
||
// (default aggiunge come ultimo elemento)
|
||
// @parm char | c | Caratter da aggiungere
|
||
// @parm long | n | Long da aggiungere
|
||
// @parm int | n | Intero da aggiungere
|
||
|
||
// @syntax void add(const char* s, int n = -1);
|
||
// @syntax void add(char c, int pos = -1);
|
||
// @syntax void add(long n, int pos = -1);
|
||
// @syntax void add(int n, int pos = -1);
|
||
//
|
||
// @comm Permette, a seconda del parametro passato, di aggiungere alla Token
|
||
// string un nuovo elemnto gia' completo del carattere di separazione
|
||
{
|
||
if (s == NULL || *s == '\0') s = " ";
|
||
if (pos < 0)
|
||
{
|
||
if (not_empty()) *this << _separator;
|
||
*this << s;
|
||
}
|
||
else
|
||
set_item(s, pos);
|
||
if (_last < 0) _last = 0;
|
||
}
|
||
|
||
// Certified 100%
|
||
void TToken_string::add(char c, int pos)
|
||
{
|
||
const char s[2] = { c, '\0' };
|
||
add(s, pos);
|
||
}
|
||
|
||
// Adds an integer value to the token string
|
||
// Certified 100%
|
||
void TToken_string::add(long n, int pos)
|
||
{
|
||
char s[16]; _ltoa(n, s, 10);
|
||
add(s, pos);
|
||
}
|
||
|
||
// Adds an integer value to the token string
|
||
// Certified 100%
|
||
void TToken_string::add(int n, int pos)
|
||
{
|
||
char s[16]; _itoa(n, s, 10);
|
||
add(s, pos);
|
||
}
|
||
|
||
void TToken_string::insert_at(const char* s, int pos)
|
||
{
|
||
if (pos >= 0 && not_empty())
|
||
{
|
||
int sep = 0;
|
||
int i;
|
||
for (i = 0; _str[i] && sep < pos; i++)
|
||
{
|
||
if (_str[i] == _separator)
|
||
sep++;
|
||
}
|
||
const TString& after = mid(i);
|
||
cut(i);
|
||
operator <<(s);
|
||
operator <<(_separator);
|
||
operator <<(after);
|
||
}
|
||
else
|
||
add(s, pos);
|
||
}
|
||
|
||
|
||
// Certified 50%
|
||
void TToken_string::destroy(int n)
|
||
{
|
||
if (_last == -2) return ;
|
||
|
||
if (n < 0)
|
||
{
|
||
char* s = strrchr(_str, _separator);
|
||
if (s != NULL) *s = '\0';
|
||
}
|
||
else
|
||
{
|
||
int sep = 0;
|
||
char * s;
|
||
for (s = _str; sep < n && *s; s++)
|
||
if (*s == _separator) sep++;
|
||
|
||
if (sep >= n)
|
||
{
|
||
const char* p = strchr(s, _separator);
|
||
*s = '\0';
|
||
if (p != NULL) strcat(s, p+1);
|
||
}
|
||
}
|
||
restart();
|
||
}
|
||
|
||
TToken_string& TToken_string::pack()
|
||
{
|
||
const char sep = separator();
|
||
int dst = 0, last_good = -1;
|
||
trim();
|
||
for (int src = 0; _str[src]; src++)
|
||
{
|
||
if ((_str[src] == ' ') &&
|
||
(_str[src+1] == sep || _str[src+1] == '\0') &&
|
||
(src == 0 || _str[src-1] == sep))
|
||
{
|
||
// Ignore empty item
|
||
}
|
||
else
|
||
{
|
||
if (src > dst)
|
||
_str[dst] = _str[src];
|
||
if (_str[src] != sep)
|
||
last_good = dst;
|
||
dst++;
|
||
}
|
||
}
|
||
cut(last_good+1);
|
||
return *this;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TAuto_token_string
|
||
///////////////////////////////////////////////////////////
|
||
|
||
TAuto_token_string& TAuto_token_string::create(const char* ts)
|
||
{
|
||
// Copia la stringa
|
||
set(ts);
|
||
|
||
// Calcola il separatore
|
||
for (const char* s = ts; s && *s; s++)
|
||
{
|
||
if (strchr("|<7C>?\t\n^;,!&+", *s) != NULL)
|
||
{
|
||
separator(*s);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// Paragraph string
|
||
///////////////////////////////////////////////////////////
|
||
|
||
TParagraph_string::TParagraph_string(const char* s, int width)
|
||
: TToken_string(s, '|'), _width(width)
|
||
{ tokenize(); }
|
||
|
||
const TString& TParagraph_string::operator =(const char* s)
|
||
{
|
||
TToken_string::operator=(s);
|
||
tokenize();
|
||
return *this;
|
||
}
|
||
|
||
void TParagraph_string::tokenize()
|
||
{
|
||
if (not_empty())
|
||
{
|
||
TToken_string tmp;
|
||
int start = 0;
|
||
int last_space = -1;
|
||
|
||
const int length = len();
|
||
for (int i = start; i <= length; i++)
|
||
{
|
||
int add_now = -1;
|
||
switch(_str[i])
|
||
{
|
||
case ' ':
|
||
case '\t':
|
||
last_space = i;
|
||
break;
|
||
case '\r':
|
||
case '\n':
|
||
case '\0':
|
||
add_now = i;
|
||
break;
|
||
default:
|
||
if (i - start >= _width)
|
||
{
|
||
if (last_space > start)
|
||
add_now = last_space;
|
||
else
|
||
add_now = i;
|
||
}
|
||
break;
|
||
}
|
||
if (add_now >= start)
|
||
{
|
||
const TString& tok = sub(start, add_now);
|
||
tmp.add(tok);
|
||
tmp.rtrim(); // Preserva gli spazi iniziali dopo un a capo forzato da \n
|
||
start = add_now + (_str[add_now] <= ' ');
|
||
last_space = start;
|
||
}
|
||
}
|
||
tmp.rtrim();
|
||
TToken_string::operator=(tmp);
|
||
}
|
||
}
|
||
|
||
// Temporary strings generator: a little step for a man, a big step for campo!
|
||
|
||
TToken_string& get_tmp_string(int len)
|
||
{
|
||
static TString_array ararar(128);
|
||
static int next = 0;
|
||
|
||
TToken_string* str = (TToken_string*)ararar.objptr(next);
|
||
if (str == NULL)
|
||
{
|
||
str = new TToken_string(max(len,50));
|
||
ararar.add(str, next);
|
||
}
|
||
else
|
||
{
|
||
if (str->size() < len)
|
||
str->resize(len, false);
|
||
str->cut(0);
|
||
}
|
||
|
||
if (++next >= ararar.size())
|
||
next = 0;
|
||
return *str;
|
||
}
|