campo-sirio/include/strings.cpp
guy 2b68cb81ae Patch level : 2.0 nopatch
Files correlati     : ve0.exe
Ricompilazione Demo : [ ]
Commento            :

form.cpp      Aggiunto supporto per custom/bitamp
realtion.cpp  Semplici sostituzioni di cose ripetute n volte con una singola variabile
scanner.cpp   Aggiunti apici in segnalazione di errore
strings.cpp   Corretta lettura di una stringa da file ad EOF
tree.cpp      Corretto disegno linee in presenza di header (Elaborazioni differite)


git-svn-id: svn://10.65.10.50/trunk@11226 c028cbd2-c16b-5b4b-a496-9718f37d4682
2003-06-11 07:44:57 +00:00

1934 lines
43 KiB
C++
Executable File
Raw Blame History

#include <ctype.h>
#include <direct.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <strstrea.h>
#include <dongle.h>
#include <real.h>
#include <regexp.h>
#include <utility.h>
// @doc EXTERNAL
// @func Ritorna il nome dell'utente attuale
//
// @rdesc Ritorno il nome dell'utente attuale
TString& user()
{
static TString16 _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 = 32000;
inline bool is_space(char c)
{ return c >= '\t' && c <= ' '; }
// 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 = new char[size+1];
if (cpy && _str) strcpy(s, _str);
else *s = '\0';
if (_str)
delete _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);
if (sz > size()) resize(sz, FALSE);
strcpy(_str, s);
}
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)
{
long new_size = long(lun) + long(s);
if (new_size > MAX_SIZE)
fatal_box("Stringa di lunghezza eccessiva (> %ld)", MAX_SIZE);
new_size = 3L * new_size / 2L;
if (new_size > MAX_SIZE)
new_size = MAX_SIZE;
resize(int(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)
delete _str;
}
char TString::shift(int n)
{
CHECK(n>0,"Scorrimento a destra delle stringhe non ancora supportato");
CHECK(n<_size,"Errore di scorrimento");
char r=*(_str+n-1);
if (n)
{
char *c=_str;
while (*c)
{
*(c)=*(c+n);
c++;
}
}
return r;
}
TString& TString::operator <<(const char* s)
{
if (s && *s)
{
const int pos = make_room(strlen(s));
strcpy(&_str[pos], 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];
sprintf(s, "%d", n);
return operator <<(s);
}
TString& TString::operator <<(long n)
{
char s[16];
sprintf(s, "%ld", n);
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 50%
// The object should be completely storable in spark
TString& TString::operator <<(const TObject& obj)
{
TString256 spark;
ostrstream out(spark.get_buffer(), spark.size());
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 (int i = 0; _str[i]; i++)
{
char c = _str[i];
if (strchr(k, c) == NULL)
_str[j++] = c;
}
return cut(j);
}
bool TString::blank() const
{
for (int i = 0; _str[i]; i++)
if (!is_space(_str[i]))
return FALSE;
return TRUE;
}
TString& TString::strip_spaces()
{
char instring = '\0';
int j = 0;
for (int i = 0; _str[i]; i++)
{
char c = _str[i];
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_d_spaces()
{
int j = 0;
bool spc = FALSE;
for (int i = 0; _str[i]; i++)
{
char c = _str[i];
if (is_space(c))
if (spc)
continue;
else
spc = TRUE;
else
if (spc) spc = FALSE;
_str[j++] = c;
}
_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; }
// @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
{
TString* s = new TString(_str);
return s;
}
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
{
int pos = -1;
if (from < len())
{
const char* p = strchr(_str + from, c);
if (p)
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;
}
#if XVT_OS == XVT_OS_SCOUNIX
HIDDEN char* strstr(const char* string1, const char* string2)
{
const int len = strlen(string2);
while (*string1)
{
if (strncmp(string1, string2, len) == 0) return (char*) string1;
string1++;
}
return NULL;
}
#endif
// Certified 100%
int TString::find(const char* s, int from) const
{
int pos = -1;
if (from < len())
{
const char* p = strstr(_str + from, s);
if (p)
pos = int(p - _str);
}
return pos;
}
bool TString::match(const char* pat) const
{
if (pat == NULL || *pat =='\0')
return empty();
return ::match(pat, _str);
}
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
{
TString& spark = get_tmp_string();
spark = _str;
spark.cut(count);
return spark;
}
// 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
{
TString& spark = get_tmp_string();
int from = len()-count;
if (from < 0) from = 0;
spark = _str + from;
return spark;
}
// 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>
{
TString& spark = get_tmp_string();
const int l = len();
#ifdef DBG
if (from < 0)
{
NFCHECK("Invalid MID parameter: from = %d", from);
from = 0;
}
#endif
if (from > l) from = l;
if (count < 0 || from+count>l)
count = l-from;
spark = &_str[from];
spark.cut(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);
}
// 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(_str, 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;
// Salta spazi iniziali
for (const char* 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;
if (s == NULL) s = "";
if (ignorecase)
{
if (max < 0)
res = stricmp(_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 compare(s, strlen(s), ignorecase) == 0;
}
// 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)
{
if (n > size())
resize(n, FALSE);
int i = 0;
if (s && *s)
{
for (; *s && i < n; i++)
_str[i] = *s++;
}
_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.
{
TString& spark = get_tmp_string(512);
va_list pars;
va_start(pars, fmt);
const int tot = vsprintf(spark.get_buffer(), fmt, pars);
va_end(pars);
CHECK(tot >= 0 && tot < spark.size(), "Ue'! Quanto scrivi?");
if (tot > size()) resize(tot, FALSE);
strcpy(_str, spark);
return *this;
}
// 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
// @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 (lung == 0) lung=strlen(s);
if (s || lung)
{
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; 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>
{
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(&_str[pos+l], 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 100%
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 = vsprintf(_str, 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
{
const char* d = strrchr(name(), '.');
if (d && is_not_slash(*(++d))) return d;
return "";
}
// Certified 90%
void TFilename::ext(const char* e)
{
int start = find(' ')-1;
if (start < 0)
start = len()-1;
bool can_cut = TRUE;
for (int i = start; i > 0 && _str[i] != '.'; i--)
if (_str[i] == '/' || _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;
}
}
// Certified 95%
const char* TFilename::name() const
{
int start = find(' ')-1;
if (start < 0)
start = len()-1;
for (int i = start; i >= 0; i--)
if (_str[i] == '/' || _str[i] == '\\' || _str[i] == ':')
break;
TString& spark = get_tmp_string();
spark = &_str[i+1];
spark.cut(start-i);
return spark;
}
// Certified 95%
const char* TFilename::path() const
{
int start = find(' ')-1;
if (start < 0)
start = len()-1;
for (int i = start; i >= 0; i--)
if (_str[i] == '/' || _str[i] == '\\' || _str[i] == ':')
break;
TString& spark = get_tmp_string();
spark = _str;
spark.cut(i+1);
return spark;
}
TFilename& TFilename::add(const char* n)
{
if (not_empty() && is_not_slash(_str[len()-1]) && is_not_slash(*n))
*this << SLASH;
*this << n;
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%
const TFilename& TFilename::tempdir()
{
static TFilename _tempdir;
const bool create = _tempdir.empty() || user().compare(_tempdir.right(user().len()), -1, TRUE);
if (create)
{
_tempdir = getenv("TEMP");
if (_tempdir.empty())
_tempdir = getenv("TMP");
if (_tempdir.empty())
_tempdir << SLASH << "temp";
const int last = len()-1;
if (!is_not_slash(_str[last]))
_tempdir.cut(last);
bool ok = TRUE;
_tempdir.lower();
if (!_tempdir.exist())
ok = make_dir(_tempdir);
if (ok)
{
TString16 theuser(user());
if (theuser.empty())
theuser = ::dongle().administrator();
theuser.lower();
const int f = _tempdir.find(theuser);
if (f < 0 || f != _tempdir.len() - theuser.len())
_tempdir << SLASH << theuser;
_tempdir.lower();
if (!_tempdir.exist())
ok = make_dir(_tempdir);
}
if (!ok)
fatal_box("Impossibile creare la directory '%s' per i file temporanei", (const char*)_tempdir);
TString tmp = _tempdir;
tmp.insert("TMP=", 0);
putenv(tmp);
}
set(_tempdir);
return *this;
}
const TFilename& TFilename::currdir()
{
_getcwd(get_buffer(),256);
return *this;
}
// Certified 50%
// @doc EXTERNAL
// @mfunc Genera il nome di un file temporaneo
const 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 esistone dei caratteri jolly
// e li elimina.
{
if (extension && *extension)
{
TFilename mask(prefix);
if (mask.empty())
mask.tempdir();
mask.add("*");
mask.ext(extension);
const int preflen = strlen(mask.path());
TString_array list;
const int count = list_files(mask, list);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
const char* name = (const char*)list.row(i) + preflen;
const long numero = atol(name) + 1;
mask.cut(preflen);
mask << numero;
mask.ext(extension);
if (list.find(mask) < 0)
break;
}
}
else
{
const int star = mask.find('*');
mask[star] = '1';
}
set(mask);
}
else
{
tempdir();
if (prefix && *prefix)
{
set(prefix); // Copia prefisso e ...
strip("$#*?."); // ... toglie caratteri jolly
}
else
cut(0);
char* t = tempnam(NULL, (char*)_str);
CHECK(t != NULL, "Can't execute tempnam");
set(t);
free(t);
}
CHECKS(!fexist(_str), "Il file temporaneo esiste gia': ", _str);
return *this;
}
bool TFilename::is_absolute_path() const
{
const char* s = _str;
if (isalpha(*s) && s[1] == ':')
s += 2;
return *s == '/' || *s == '\\';
}
const TFilename& TFilename::make_absolute_path()
{
if (is_relative_path())
{
const TString saved(_str);
getcwd(get_buffer(), size());
add(saved);
}
return *this;
}
bool TFilename::exist() const
{
return ::fexist(_str);
}
bool TFilename::search_in_path(TFilename& path) const
{
_searchenv(_str, "PATH", path.get_buffer());
if (path.empty())
_searchenv(_str, "path", path.get_buffer());
return path.not_empty();
}
bool TFilename::input()
{
return input_filename(*this);
}
bool TFilename::custom_path(const char* path_list)
{
TToken_string pl = path_list;
if (pl.empty())
pl = "custom";
TFilename cust;
FOR_EACH_TOKEN(pl, path)
{
cust = path;
cust.add(name());
if (cust.exist())
{
set(cust);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////
// 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");
TString& spark = get_tmp_string();
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;
for (const char* s = _str; sep < n && *s; s++)
if (*s == _separator) sep++;
if (sep >= n)
{
char* p = strchr(s, _separator);
if (p == NULL)
{
spark = s;
_last = -1;
}
else
{
*p = '\0';
spark = s;
*p = _separator;
_last = (int)((const char*)p - _str) + 1;
}
}
else
{
_last = -1;
return NULL;
}
return spark;
}
// 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;
for (const char* s = _str; *s && sep < n; s++)
if (*s == _separator) sep++;
bool found = sep == n;
if (found)
{
char* p = strchr(s, _separator);
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;
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;
bool found = get(n, str);
if (found)
tok = real(str);
else
tok = ZERO;
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;
for (int 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]; sprintf(s, "%ld", n);
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];
sprintf(s, "%ld", n);
add(s, pos);
}
// Adds an integer value to the token string
// Certified 100%
void TToken_string::add(int n, int pos)
{
char s[16];
sprintf(s, "%d", n);
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;
for (char* 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();
}
///////////////////////////////////////////////////////////
// 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()
{
int last_space = -1, last_start = 0;
int num_chars = 0;
const int l = len();
TString stmp,swork; // stringhe di lavoro
for (int start = 0; start < l;)
{
switch (_str[start])
{
case '\r':
case '\n': last_space = start; num_chars = _width; break;
case ' ' : last_space = start; num_chars++; break;
default : num_chars++; break;
}
if (num_chars == _width && (start < l-1))
{
int num_of_chars_in_row = (last_space+1) - last_start;
if (num_of_chars_in_row <= 0) num_of_chars_in_row = _width; // Se non ci sono spazi tronca la stringa a 25
swork = mid(last_start,num_of_chars_in_row);
stmp << swork.trim(); stmp << '|';
last_space = num_chars = 0;
// start = start - (_width - num_of_chars_in_row); // riporta indietro (toglie il numero di caratteri effettivi della riga)
start = last_start + num_of_chars_in_row;
last_start = start;
}
else
start++;
}
swork=mid(last_start,l-last_start);
swork.trim();
stmp << swork;
if (stmp.empty()) stmp = _str;
TToken_string::operator=(stmp);
}
*/
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)
{
TString256 tok = sub(start, add_now);
tok.rtrim(); // Preserva gli spazi iniziali dopo un a capo forzato da \n
tmp.add(tok);
start = add_now + (_str[add_now] <= ' ');
last_space = start;
}
}
tmp.rtrim();
TToken_string::operator=(tmp);
}
}
///////////////////////////////////////////////////////////
// TString_array
///////////////////////////////////////////////////////////
int TString_array::add(const char* s, int n)
{
if (objptr(n) == NULL)
n = TArray::add(new TToken_string(s), n);
else row(n) = s;
return n;
}
int TString_array::add(const TToken_string& s, int n)
{
if (objptr(n) == NULL)
n = TArray::add(s, n);
else
row(n) = s;
return n;
}
const TString_array& TString_array::operator=(const TString_array& a)
{
destroy();
for (int i = a.last(); i >= 0; i = a.pred(i))
{
const TToken_string& s = a.row(i);
add(s, i);
}
return a;
}
// @doc EXTERNAL
// @mfunc Cerca una stringa nell'array
//
// @rdesc Ritorna la posizione nell'array in cui si trova la stringa (-1 se non
// e' stata trovata)
int TString_array::find(
const char* s, // @parm Stringa da cercare
int from) const // @parm Posizione dalla quale cercare la stringa
{
int found = -1;
for (int i = from; i < items(); i++)
if (row(i).compare(s, -1, TRUE) == 0)
{
found = i;
break;
}
return found;
}
HIDDEN int ascending_string(const TObject** o1, const TObject** o2)
{
const TString* s1 = (const TString*)*o1;
const TString* s2 = (const TString*)*o2;
return strcmp(*s1, *s2);
}
HIDDEN int descending_string(const TObject** o1, const TObject** o2)
{
return -ascending_string(o1, o2);
}
void TString_array::sort(bool ascending)
{
TArray::sort(ascending ? ascending_string : descending_string);
}
// 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->size() < len)
{
str = new TToken_string(len);
ararar.add(str, next);
}
else
str->cut(0);
if (++next >= ararar.size())
next = 0;
return *str;
}