Files correlati : ve0.exe Ricompilazione Demo : [ ] Commento : Corretto azzeramento dei sottocampi es: RAGSOC[30,50] git-svn-id: svn://10.65.10.50/trunk@20216 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			2163 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2163 lines
		
	
	
		
			47 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 = 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);
 | ||
|     strncpy(s, size());
 | ||
|   }
 | ||
|   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 = 3 * min_size / 2;
 | ||
|     if (new_size > MAX_SIZE)
 | ||
|       new_size = MAX_SIZE;
 | ||
|     if (new_size < min_size)
 | ||
|       fatal_box("Stringa di lunghezza eccessiva (%ld)", min_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;
 | ||
| #ifdef DBG
 | ||
|     _str = NULL;
 | ||
|     _size = -883;
 | ||
| #endif
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| 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 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;
 | ||
| }
 | ||
| 
 | ||
| #if XVT_OS == XVT_OS_SCOUNIX
 | ||
| HIDDEN const char* strstr(const char* string1, const char* string2)
 | ||
| {
 | ||
|   const int len = strlen(string2);
 | ||
|   while (*string1)
 | ||
|   {
 | ||
|     if (strncmp(string1, string2, len) == 0) 
 | ||
|       return string1;
 | ||
|     string1++;
 | ||
|   }
 | ||
|   return NULL;
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| 
 | ||
| // 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(_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;
 | ||
|   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);
 | ||
|     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];
 | ||
|   memset(spark, 0, sizeof(spark));
 | ||
|   va_list pars;
 | ||
|   va_start(pars, fmt);
 | ||
| 
 | ||
| #ifdef WIN32
 | ||
|   const unsigned int tot = _vsnprintf(spark, sizeof(spark)-1, fmt, pars);
 | ||
| #else
 | ||
|   const unsigned int tot = vsprintf(spark, fmt, pars);
 | ||
| #endif
 | ||
|   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(&_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);
 | ||
| #ifdef WIN32
 | ||
|   const int tot = _vsnprintf(_str, size()+1, fmt, pars);
 | ||
| #else
 | ||
|   const int tot = vsprintf(_str, fmt, pars);
 | ||
| #endif
 | ||
|   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];
 | ||
|   xvt_fsys_parse_pathname(_str, v, d, n, NULL, NULL);
 | ||
|   xvt_fsys_build_pathname(_str, v, d, n, e, NULL);
 | ||
| }
 | ||
| 
 | ||
| // 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%
 | ||
| const TFilename& TFilename::tempdir()
 | ||
| {                                         
 | ||
|   static TFilename _tempdir;
 | ||
|   const bool create = _tempdir.empty() || !_tempdir.ends_with(user(), true);
 | ||
|   
 | ||
|   if (create) 
 | ||
|   {
 | ||
|     _tempdir.cut(0);
 | ||
|     xvt_sys_get_env("TEMP", _tempdir.get_buffer(), _tempdir.size());
 | ||
|     if (_tempdir.empty()) 
 | ||
|       xvt_sys_get_env("TMP", _tempdir.get_buffer(), _tempdir.size());
 | ||
| #ifdef WIN32
 | ||
|     if (_tempdir.empty()) 
 | ||
|     {
 | ||
|       _tempdir = __argv[0];
 | ||
|       _tempdir.cut(3);
 | ||
|       _tempdir << "temp";
 | ||
|     }
 | ||
|     if (!_tempdir.exist())
 | ||
|     {
 | ||
|       _tempdir = __argv[0];
 | ||
|       _tempdir.cut(3);
 | ||
|       _tempdir << "tmp";
 | ||
|     }
 | ||
| #else
 | ||
|     _tempdir = "/tmp";
 | ||
| #endif
 | ||
|     
 | ||
|     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)
 | ||
|     {                
 | ||
|       TString 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);
 | ||
|  
 | ||
|     xvt_sys_set_env("TMP", _tempdir);
 | ||
|   }  
 | ||
|   
 | ||
|   set(_tempdir);
 | ||
|   return *this;
 | ||
| }
 | ||
| 
 | ||
| const TFilename& TFilename::currdir()
 | ||
| {           
 | ||
|   DIRECTORY d;
 | ||
|   
 | ||
|   xvt_fsys_get_dir(&d);  // verificare                            
 | ||
|   xvt_fsys_convert_dir_to_str(&d, get_buffer(), 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.
 | ||
| { 
 | ||
|   if (extension && *extension)
 | ||
|   {   
 | ||
|     /* Vengono creati file in posti fantasiosi
 | ||
|     TFilename mask(prefix);
 | ||
|     if (mask.empty())
 | ||
|       mask.tempdir();
 | ||
|     mask.add("*");
 | ||
|     mask.ext(extension);
 | ||
|     */
 | ||
|     TFilename mask;
 | ||
|     mask.tempdir();
 | ||
|     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)
 | ||
| 				mask = prefix;
 | ||
| 			else
 | ||
|       mask.add(prefix);
 | ||
|       mask << '*';
 | ||
|     }
 | ||
|     else
 | ||
|       mask.add("*");
 | ||
|     mask.ext(extension);
 | ||
| 
 | ||
|     const int star = mask.find('*');
 | ||
|     
 | ||
|     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) + star;
 | ||
|         const long numero = atol(name) + 1;
 | ||
|         mask.cut(star); 
 | ||
|         mask << numero; 
 | ||
|         mask.ext(extension);
 | ||
|         if (list.find(mask) < 0)
 | ||
|           break;
 | ||
|       }
 | ||
|     }
 | ||
|     else
 | ||
|       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, _str);
 | ||
|     CHECK(t != NULL, "Can't execute tempnam");
 | ||
|     set(t);
 | ||
|     free(t);
 | ||
|   }
 | ||
|   
 | ||
|   CHECKS(!exist(), "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);
 | ||
|     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.not_empty();
 | ||
| }
 | ||
| 
 | ||
| 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;
 | ||
|   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, 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]; 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);
 | ||
| }
 | ||
| 
 | ||
| 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] == '0') &&
 | ||
|         (_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)
 | ||
|       {
 | ||
|         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(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;
 | ||
| }
 |