campo-sirio/omnia/strings.cpp

1842 lines
41 KiB
C++
Raw Normal View History

#include <ctype.h>
#include <direct.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <strstrea.h>
#include "strings.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;
}
// 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;
}
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.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);
}
// 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.
{
char spark[512];
va_list pars;
va_start(pars, fmt);
const int tot = vsprintf(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
// @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_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 (is_slash(_str[i]) || _str[i] == ':')
{
can_cut = FALSE;
i = start;
break;
}
if (i > 0 && can_cut && !is_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 (is_slash(_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 (is_slash(_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_slash(_str[len()-1]) && !is_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])
{
case ':':
if (c != 1 || !isalpha(_str[0])) return FALSE; // Nome disco errato
len = 0;
break;
case '\\':
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_slash(_str[last]))
_tempdir.cut(last);
bool ok = TRUE;
_tempdir.lower();
if (!_tempdir.exist())
ok = mkdir(_tempdir) == 0;
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(_str, size());
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.
{
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 is_slash(*s);
}
const TFilename& TFilename::make_absolute_path()
{
if (is_relative_path())
{
const TString saved(_str);
currdir();
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::custom_path(const char* path_list)
{
bool ok = false;
if (!is_absolute_path())
{
TToken_string pl = path_list;
if (pl.empty())
pl.add("custom"); // c:/campo32/custom
const TString fname = name();
FOR_EACH_TOKEN(pl, path)
{
TFilename cust = path;
cust.add(fname);
if (cust.exist())
{
set(cust);
ok = true;
break;
}
}
}
else
ok = exist();
return ok;
}
///////////////////////////////////////////////////////////
// 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;
}
// 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 = new TToken_string(len);
ararar.add(str, next);
}
if (str->size() < len)
str->spaces(len);
str->cut(0);
if (++next >= ararar.size())
next = 0;
return *str;
}