#include #include #include #include #include // @doc EXTERNAL // @func Ritorna il nome dell'utente attuale // // @rdesc Ritorno il nome dell'utente attuale TString& user() { static TString80 _user; return _user; } const TToken_string& empty_string() { static TToken_string _ts(1); return _ts; } // Most descriptions will fit in fifty characters const int DEFAULT_SIZE = 50; const int MAX_SIZE = 65535; inline bool is_space(char c) { return c >= '\t' && c <= ' '; } // 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

{ 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 ) 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 (%d)", 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 && n<=len(),"Errore di scorrimento"); const char r=*(_str+n-1); strcpy(_str, _str+n); 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]; _itoa(n, s, 10); return operator <<(s); } TString& TString::operator <<(long n) { char s[16]; _ltoa(n, s, 10); return operator <<(s); } TString& TString::operator <<(double n) { char s[32]; sprintf(s, "%lg", n); return operator <<(s); } // Appends an object to the string // Certified 99% // The object should be completely storable in spark TString& TString::operator <<(const TObject& obj) { TString256 spark; #ifdef WIN32 ostrstream out(spark.get_buffer(), spark.size()); #else ostringstream out(spark.get_buffer()); #endif obj.print_on(out); out << ends; return operator <<(spark); } TString& TString::operator <<(const TString& str) { return operator <<(str._str); } // @doc EXTERNAL // @mfunc Elimina tutti i caratteri contenuti in

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 = 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

sia maggiore della lunghezza della stringa manda // un messaggio di errore { CHECKD(from >= 0, "bad string index", from); CHECK(c, "bad character to find"); int pos = -1; if (from == 0 || from < len()) { const char* p = strchr(_str + from, c); if (p != NULL) pos = int(p - _str); } return pos; } int TString::rfind( char c) const // @parm Carattere da cercare // @syntax rfind(char c); // { const char* p = strrchr(_str, c); return p ? int(p - _str) : -1; } // Certified 100% int TString::find(const char* s, int from) const { CHECKD(from >= 0, "bad string index", from); CHECK(s && *s, "bad string to find"); int pos = -1; if (from == 0 || from < len()) { const char* p = strstr(_str + from, s); if (p != NULL) pos = int(p - _str); } return pos; } bool TString::match(const char* pat, bool ignore_case) const { return (pat && *pat) ? xvt_str_match(_str, pat, !ignore_case) != 0 : empty(); } int TString::replace(char find_char, char replace_char) { int n = 0; for (int i = 0; _str[i]; i++) if (_str[i] == find_char) { _str[i] = replace_char; n++; } return n; } // Certified 99% // @doc EXTERNAL // @mfunc Ritorna l'oggetto TString composto dai

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

caratteri da sinistra { return mid(0, count); } // Certified 99% // @doc EXTERNAL // @mfunc Ritorna l'oggetto TString composto dai

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

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

caratteri a partire // da

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

cartteri da

{ 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

a

(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

a

{ 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

e' 0. Se non lo Š ritorna l'indirizzo della // stringa a partire dal

-esimo carattere; altrimenti controlla // se i primi caratteri sono spazi e li elimina fino a che non trova // un carattere diverso da ' ' // // @xref { 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

e' 0. Se non lo e' pone il fine stringa alla // posizione

; altrimenti controlla se gli ultimi caratteri // sono spazi e li elimina fino a che non trova un carattere diverso da ' ' // // @xref { 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

caratteri) // // @rdesc Ritrna i seguenti valori: // // @flag 0 | Se le stringhe sono uguali // @flag 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

e' maggiore della dimensione della stringa, la // stessa viene ridimensionata (chaimata alla ). // Nel caso non venga passato il parametro

la stringa viene // riempita col carattere

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

, questo viene inserito // nel resto della stringa (a sinistra della stringa stessa) // // @xref { 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

, questo viene inserito // nel resto della stringa (a destra e a sinistra della stringa stessa) // // @xref { 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

, questo viene inserito // nel resto della stringa (a destra della stringa stessa) // // @xref { 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

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

// @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

permette di stabilire la // corretta sintassi della stringa

da scrivere nei messaggi // dati all'utente. Nel caso

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

dalla posizione

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

fino alla lunghezza di

l'oggetto // stringa. Nel caso la dimensione sia maggiore l'oggetto viene riallocato // dinamicamente // // @xref { 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

la stringa

nell'oggetto // stringa. Nel caso la dimensione sia maggiore l'oggetto viene riallocato // dinamicamente // // @xref { 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

// @comm Funziona come la funzione "sprintf" standard del C e ritorna la // stringa formattata con i parametri passati. // E' piu' efficiente di 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. // 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()); if (_tempdir.empty()) { _tempdir = __argv[0]; _tempdir.cut(3); _tempdir << "temp"; } if (!_tempdir.exist()) { _tempdir = __argv[0]; _tempdir.cut(3); _tempdir << "tmp"; } const int last = len()-1; if (!is_not_slash(_str[last])) _tempdir.cut(last); bool ok = true; _tempdir.lower(); if (!dexist(_tempdir)) 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 (!dexist(_tempdir)) 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('*'); CHECK(star>=0, "Invalid temp file mask"); TString_array list; const int count = list_files(mask, list); if (count > 0) { FOR_EACH_ARRAY_ROW(list, i, row) { const char* name = row->mid(star); const long numero = atol(name) + 1; mask = row->left(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 già: ", _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.full(); } bool TFilename::input() { return input_filename(*this); } bool TFilename::custom_path(const char* path_list) { if (blank()) // Inutile continuare! return false; // Espando solo i nomi di file senza path (relativo o assoluto) if (!starts_with(".") && !is_absolute_path()) { TToken_string pl = path_list; if (pl.empty()) { pl.add("custom"); // c:/campo32/custom if (prefix_valid()) { TFilename n; n = firm2dir(prefix().get_codditta()); n.add("custom"); pl.add(n); // f:/campo32/dati/00001A/custom n = firm2dir(-1); n.add("custom"); pl.add(n); // f:/campo32/dati/custom } } const TString fname = name(); FOR_EACH_TOKEN(pl, path) { TFilename cust = path; cust.add(fname); if (cust.exist()) { set(cust); return true; } } } return exist(); } /////////////////////////////////////////////////////////// // Token string /////////////////////////////////////////////////////////// // Certified 100% TToken_string::~TToken_string() { } // Certified 100% TToken_string::TToken_string(const char* s, char separator) : TString(s), _separator(separator) { CHECK(_separator, "NULL TToken_string separator"); restart(); } // Certified 100% TToken_string::TToken_string(int n, char separator) : TString(n), _separator(separator), _last(-1) { CHECK(_separator, "NULL TToken_string separator"); } // Certified 100% TToken_string::TToken_string(const TToken_string& s) : TString(s), _separator(s._separator), _last(s._last) { CHECK(_separator, "NULL TToken_string separator"); } const TToken_string& TToken_string::operator =(const TToken_string& s) { set(s); restart(); separator(s.separator()); return *this; } void TToken_string::separator(char s) { CHECK(s, "NULL TToken_string separator"); _separator = s; } // Certified 100% TObject* TToken_string::dup() const { return new TToken_string(_str, _separator); } // Certified 90% const char* TToken_string::get() { CHECK(_separator, "Corrupted TToken_string: NULL separator"); if (_last < 0) return NULL; const int start = _last; if (_str[start] == '\0') { _last = -1; return NULL; } else if (_str[start] == _separator) { _last = start+1; } else { const int k = find(_separator, start); _last = (k >= 0) ? k+1 : -1; return sub(start, k); } return ""; } // Certified 50% // @doc EXTERNAL // @mfunc Ritorna un Token // // @rdesc Ritorna la stringa alla posizione

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

ritorna il prossimo Token // (come se

== -1) // // @xref { 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 con tutti i relativi significati per // il parametro

{ 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

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 { CHECK(_separator, "Corrupted TToken_string: NULL separator"); if (n < 0) { const char* sep = strrchr(_str, _separator); tok = sep ? sep+1 : _str; return tok.not_empty(); } int sep = 0; const char* s; for (s = _str; *s && sep < n; s++) if (*s == _separator) sep++; bool found = sep == n; if (found) { char* p = (char*)strchr(s, _separator); //antica porcata if (p == NULL) { tok = s; found = tok.not_empty(); } else { *p = '\0'; tok = s; *p = _separator; } } else tok.cut(0); return found; } bool TToken_string::get( int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo) char& tok) const // @parm char da ritornare { TString16 str; bool found = get(n, str); tok = found ? str[0] : '\0'; return found; } bool TToken_string::get( int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo) int& tok) const // @parm int da ritornare { TString16 str; bool found = get(n, str); tok = found ? atoi(str) : 0; return found; } bool TToken_string::get( int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo) long& tok) const // @parm long da ritornare { TString16 str; const bool found = get(n, str); tok = found ? atol(str) : 0L; return found; } bool TToken_string::get( int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo) real& tok) const // @parm real da ritornare { TString80 str; const bool found = get(n, str); tok = found ? real(str) : ZERO; return found; } bool TToken_string::get( int n, // @parm Posizione del token da ritornare (0 = primo, -1 = prossimo, -2 = ultimo, n = n-simo) TDate& tok) const // @parm TDate da ritornare { TString16 str; bool found = get(n, str); if (found && TDate::isdate(str)) tok = TDate(str); else tok = botime; return found; } // Certified 90% bool TToken_string::set_item(const char* v, int n) { CHECK(_separator, "Corrupted TToken_string: NULL separator"); TString& spark = get_tmp_string(); int sep = 0, i; for (i = 0; sep < n && _str[i]; i++) if (_str[i] == _separator) sep++; if (sep < n) // Aggiunge items mancanti prima della posizione n { for (;sep < n; sep++) *this << _separator; *this << v; return false; } int e = find(_separator, i); if (e < 0) e = len(); spark = _str+e; // Salva items seguenti cut(i); // Considera solo items precedenti *this << v << spark; // Aggiunge item desiderato e seguenti return true; } // Certified 80% int TToken_string::get_pos(const char* s) { const char* item; restart(); for (int i = 0; (item = get()) != NULL; i++) if (strcmp(item, s) == 0) return i; return -1; } // Certified 80% int TToken_string::get_pos(long n) { char s[16]; _ltoa(n, s, 10); return get_pos(s); } // Certified 90% bool TToken_string::empty_items() const { for (const char* c = _str; *c; c++) if (!is_space(*c) && *c != _separator) return false; return true; } // Certified 80% int TToken_string::items() const { int t = 0; if (not_empty()) { t++; for (const char* s = _str; *s; s++) if (*s == _separator) t++; } return t; } // Certified 99% // @doc EXTERNAL // @mfunc Aggiunge un elemento alla token string void TToken_string::add( const char* s, // @parm Stringa da aggiungere int pos) // @parm Posizione nella quale aggiungere l'elemento // (default aggiunge come ultimo elemento) // @parm char | c | Caratter da aggiungere // @parm long | n | Long da aggiungere // @parm int | n | Intero da aggiungere // @syntax void add(const char* s, int n = -1); // @syntax void add(char c, int pos = -1); // @syntax void add(long n, int pos = -1); // @syntax void add(int n, int pos = -1); // // @comm Permette, a seconda del parametro passato, di aggiungere alla Token // string un nuovo elemnto gia' completo del carattere di separazione { if (s == NULL || *s == '\0') s = " "; if (pos < 0) { if (not_empty()) *this << _separator; *this << s; } else set_item(s, pos); if (_last < 0) _last = 0; } // Certified 100% void TToken_string::add(char c, int pos) { const char s[2] = { c, '\0' }; add(s, pos); } // Adds an integer value to the token string // Certified 100% void TToken_string::add(long n, int pos) { char s[16]; _ltoa(n, s, 10); add(s, pos); } // Adds an integer value to the token string // Certified 100% void TToken_string::add(int n, int pos) { char s[16]; _itoa(n, s, 10); add(s, pos); } void TToken_string::insert_at(const char* s, int pos) { if (pos >= 0 && not_empty()) { int sep = 0; int i; for (i = 0; _str[i] && sep < pos; i++) { if (_str[i] == _separator) sep++; } const TString& after = mid(i); cut(i); operator <<(s); operator <<(_separator); operator <<(after); } else add(s, pos); } // Certified 50% void TToken_string::destroy(int n) { if (_last == -2) return ; if (n < 0) { char* s = strrchr(_str, _separator); if (s != NULL) *s = '\0'; } else { int sep = 0; char * s; for (s = _str; sep < n && *s; s++) if (*s == _separator) sep++; if (sep >= n) { const char* p = strchr(s, _separator); *s = '\0'; if (p != NULL) strcat(s, p+1); } } restart(); } TToken_string& TToken_string::pack() { const char sep = separator(); int dst = 0, last_good = -1; trim(); for (int src = 0; _str[src]; src++) { if ((_str[src] == ' ') && (_str[src+1] == sep || _str[src+1] == '\0') && (src == 0 || _str[src-1] == sep)) { // Ignore empty item } else { if (src > dst) _str[dst] = _str[src]; if (_str[src] != sep) last_good = dst; dst++; } } cut(last_good+1); return *this; } /////////////////////////////////////////////////////////// // TAuto_token_string /////////////////////////////////////////////////////////// TAuto_token_string& TAuto_token_string::create(const char* ts) { // Copia la stringa set(ts); // Calcola il separatore for (const char* s = ts; s && *s; s++) { if (strchr("|¦?\t\n^;,!&+", *s) != NULL) { separator(*s); break; } } return *this; } /////////////////////////////////////////////////////////// // Paragraph string /////////////////////////////////////////////////////////// TParagraph_string::TParagraph_string(const char* s, int width) : TToken_string(s, '|'), _width(width) { tokenize(); } const TString& TParagraph_string::operator =(const char* s) { TToken_string::operator=(s); tokenize(); return *this; } void TParagraph_string::tokenize() { if (not_empty()) { TToken_string tmp; int start = 0; int last_space = -1; const int length = len(); for (int i = start; i <= length; i++) { int add_now = -1; switch(_str[i]) { case ' ': case '\t': last_space = i; break; case '\r': case '\n': case '\0': add_now = i; break; default: if (i - start >= _width) { if (last_space > start) add_now = last_space; else add_now = i; } break; } if (add_now >= start) { const TString& tok = sub(start, add_now); tmp.add(tok); tmp.rtrim(); // Preserva gli spazi iniziali dopo un a capo forzato da \n start = add_now + (_str[add_now] <= ' '); last_space = start; } } tmp.rtrim(); TToken_string::operator=(tmp); } } // Temporary strings generator: a little step for a man, a big step for campo! TToken_string& get_tmp_string(int len) { static TString_array ararar(128); static int next = 0; TToken_string* str = (TToken_string*)ararar.objptr(next); if (str == NULL) { str = new TToken_string(max(len,50)); ararar.add(str, next); } else { if (str->size() < len) str->resize(len, false); str->cut(0); } if (++next >= ararar.size()) next = 0; return *str; }