/* * Baltisot * Copyright (C) 1999-2007 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: String.cc,v 1.51 2008-01-29 14:10:40 pixel Exp $ */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_GMP #include #endif #include "BString.h" #include "Exceptions.h" #include "gettext.h" char ** gruikptr; extern "C" { double dateCalc(char *, char *); int isDateArgument(char *); } char String::t[BUFSIZ + 1]; String::String(const String & s) : str((char *) malloc(s.siz + 1)), siz(s.siz) { memcpy(str, s.str, siz); str[siz] = 0; #ifdef DEBUG fprintf(stderr, _("Duplicating string `%s', from %p to %p, from this %p to this %p\n"), str, s.str, str, &s, this); #endif } #ifndef asprintf //extern "C" int asprintf(char **, const char *, ...); #endif String::String(char c) : siz(1) { #ifdef DEBUG fprintf(stderr, _("Creating a string with `%c' at %p, this = %p\n"), c, str, this); #endif str = (char *) malloc(2); str[0] = c; str[1] = 0; } String::String(const char * s, int _siz) : str(0), siz(_siz < 0 ? ::strlen(s) : _siz) { str = (char *) malloc(siz + 1); memcpy(str, s, siz); str[siz] = 0; #ifdef DEBUG fprintf(stderr, _("Creating a string with `%s' at %p from %p, this = %p\n"), str, str, s, this); #endif } String::String(int hs, char * s) : str(s), siz(hs) { #ifdef DEBUG fprintf(stderr, _("Fast-Creating a string with `%s' at %p from %p, this = %p\n"), str, str, s, this); #endif } String::String(int i) { #ifndef HAVE_ASPRINTF char t[20]; sprintf(t, "%i", i); str = Base::strdup(t); #else asprintf(&str, "%i", i); #endif siz = ::strlen(str); } String::String(unsigned int i) { #ifndef HAVE_ASPRINTF char t[20]; sprintf(t, "%u", i); str = Base::strdup(t); #else asprintf(&str, "%u", i); #endif siz = ::strlen(str); } String::String(int64 l) { #ifndef HAVE_ASPRINTF char t[40]; sprintf(t, "%lld", l); str = Base::strdup(t); #else asprintf(&str, "%lld", l); #endif siz = ::strlen(str); } String::String(Uint64 l) { #ifndef HAVE_ASPRINTF char t[40]; sprintf(t, "%llu", l); str = Base::strdup(t); #else asprintf(&str, "%llu", l); #endif siz = ::strlen(str); } String::String(double d) { #ifndef HAVE_ASPRINTF char t[30]; sprintf(t, "%.14g", d); str = Base::strdup(t); #else asprintf(&str, "%g", d); #endif siz = ::strlen(str); } String::~String() { #ifdef DEBUG fprintf(stderr, _("Destroying string @ %p, freeing %p.\n"), this, str); #endif free(str); } const char * String::set(const char * s, va_list ap) { const char * r; free(str); if (!s) { str = Base::strdup(""); return str; } #ifdef HAVE_GMP gmp_vasprintf(&str, s, ap); r = str; #else // !HAVE_GMP #ifdef HAVE_VASPRINTF vasprintf(&str, s, ap); r = str; #else // !HAVE_VASPRINTF #ifdef HAVE_VSNPRINTF LOCK; vsnprintf(t, BUFSIZ, s, ap); str = Base::strdup(r = t); UNLOCK; #else // !HAVE_VSNPRINTF #ifdef _WIN32 #ifdef _MSC_VER r = str = (char *) malloc(_vscprintf(s, ap) + 1); vsprintf(str, s, ap); #else LOCK; _vsnprintf(t, BUFSIZ, s, ap); str = Base::strdup(r = t); UNLOCK; #endif #else LOCK; vsprintf(t, s, ap); str = Base::strdup(r = t); UNLOCK; #endif #endif // HAVE_VSNPRINTF #endif // HAVE_VASPRINTF #endif // HAVE_GMP siz = ::strlen(str); return r; } const char * String::set(const char * s, ...) { const char * r; va_list ap; va_start(ap, s); r = set(s, ap); va_end(ap); return r; } const char * String::set(const ugly_string & s, ...) { const char * r; va_list ap; va_start(ap, s); r = set(s.p, ap); va_end(ap); return r; } #ifdef HAVE_VSSCANF int String::scanf(const char * s, ...) const { va_list ap; int t; va_start(ap, s); #ifdef HAVE_GMP t = gmp_vsscanf(str, s, ap); #else t = vsscanf(str, s, ap); #endif va_end(ap); return t; } int String::scanf(const ugly_string & s, ...) const { va_list ap; int t; va_start(ap, s); #ifdef HAVE_GMP t = gmp_vsscanf(str, s.p, ap); #else t = vsscanf(str, s.p, ap); #endif va_end(ap); return t; } #endif const char * String::to_charp(size_t from, ssize_t to) const throw (GeneralException) { if (to < 0) { return str + from; } else { if (((size_t) to) >= siz) { to = siz - 1; } if ((((size_t) to) - from) > BUFSIZ) { from -= (to - from) - BUFSIZ; } if (((size_t) to) >= from) { size_t i; for (i = 0; i <= ((size_t) to) - from; i++) { t[i] = str[i + from]; } t[i] = '\0'; } else { t[0] = '\0'; } } //throw GeneralException("This usage of String is deprecated."); return t; } String String::extract(size_t from, ssize_t to) const { return String(to_charp(from, to)); } char * String::strdup(size_t from, ssize_t to) const { char * r; LOCK; r = Base::strdup(to_charp(from, to)); UNLOCK; return r; } int String::to_int(const char * fmt) const { int r; sscanf(str, fmt, &r); return r; } double String::to_double(void) const { double r; sscanf(str, "%lf", &r); return r; } String & String::operator=(const String & s) { if (str != s.str) { // On évite l'autodestruction... free(str); str = s.strdup(); siz = s.siz; } return *this; } String String::operator+(const String & s) const { char * t = (char *) malloc(s.siz + siz + 1), * u; strcpy((u = t), str); u += siz; strcpy(u, s.str); return String(siz + s.siz, t); } String & String::operator+=(const String & s) { char * t = (char *) malloc(s.siz + siz + 1), * u; strcpy((u = t), str); u += siz; strcat(u, s.str); free(str); str = t; siz += s.siz; return (*this); } std::ostream & operator<<(std::ostream & os, const String & s) { return (os << s.to_charp()); } std::istream & operator>>(std::istream & is, String & s) { char c = 0; s.set(""); while (!is.eof()) { c = is.get(); if (c == '\n') return is; if (c == '\r') continue; s += c; } return is; } bool String::operator!=(const String & s) const { return (strcmp(str, s.str) != 0); } bool String::operator==(const String & s) const { if (siz != s.siz) return false; return (strcmp(str, s.str) == 0); } bool String::operator<=(const String & s) const { return (strcmp(str, s.str) <= 0); } bool String::operator>=(const String & s) const { return (strcmp(str, s.str) >= 0); } bool String::operator<(const String & s) const { return (strcmp(str, s.str) < 0); } bool String::operator>(const String & s) const { return (strcmp(str, s.str) > 0); } size_t String::strlen() const { return (siz); } char String::operator[](size_t i) const { if (i >= siz) { return 0; } else { return str[i]; } } char & String::operator[](size_t i) { static char zero = 0; if (i >= siz) { return zero; } else { return str[i]; } } ssize_t String::strchr(char c, size_t from) const { for (size_t i = from; i < siz; i++) { if (str[i] == c) return i; } return -1; } ssize_t String::strrchr(char c) const { for (size_t i = siz - 1; i >= 0; i--) { if (str[i] == c) return i; } return -1; } ssize_t String::strstr(const String & s) const { char * p = ::strstr(str, s.str); if (p) { return p - str; } else { return -1; } } int String::strchrcnt(char c) const { size_t i, cnt = 0; for (i = 0; i < siz; i++) { if (str[i] == c) cnt++; } return cnt; } String String::to_sqldate(void) const { /* DD/MM/YYYY ==> YYYYMMMDD */ return (is_date() ? extract(6, 9) + extract(3, 4) + extract(0, 1) : ""); } String String::to_sqltime(void) const { /* h:m ==> h * 60 + m */ int p = strchr(':'); return (is_time() ? String(extract(0, p - 1).to_int() * 60 + extract(p + 1).to_int()) : ""); } String String::from_sqldate(void) const { /* YYYYMMDD ==> DD/MM/YYYY */ return ((strlen() == 8) && is_number() ? extract(6, 7) + '/' + extract(4, 5) + '/' + extract(0, 3) : ""); } String String::from_sqltime(void) const { /* t ==> (t / 60):(t % 60) */ int t = to_int(); return (is_number() ? String((int) (t / 60)) + ':' + (t % 60) : ""); } bool String::is_date(void) const { /* 'DD/MM/YYYY' 0123456789 */ if (strlen() != 10) return false; if ((str[2] != '/') || (str[5] != '/') || (!extract(0, 1).is_number()) || (!extract(3, 4).is_number()) || (!extract(6, 9).is_number())) { return (isDateArgument(to_sqldate().str) != 0); } return true; } double String::datedif(const String & s) const { double r; if (is_date() && s.is_date()) { r = dateCalc(to_sqldate().str, s.to_sqldate().str); return r < 0 ? -r : r; } return -1; } bool String::is_number(void) const { for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) { if ((str[i] > '9') || (str[i] < '0')) return false; } return true; } bool String::is_float(void) const { bool seendot = false; for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) { if ((str[i] > '9') || (str[i] < '0')) { if ((str[i] == '.') && !seendot) { seendot = true; } else { return false; } } } return true; } bool String::is_time(void) const { int p = strchr(':'); if (p == -1) return false; // On accepte les heures sous le format xxxxxx:yy pour pouvoir indiquer des durées. if ((!extract(0, p - 1).is_number()) || (!extract(p + 1).is_number())) return false; return (extract(p + 1).to_int() < 60) ? true : false; } String operator+(const char * a, const String & b) { return String(a) + b; } String::operator ugly_string() const { ugly_string r; r.p = str; return r; } String & String::toupper() { for (unsigned int i = 0; i < strlen(); i++) { str[i] = ::toupper(str[i]); } return *this; } String & String::tolower() { for (unsigned int i = 0; i < strlen(); i++) { str[i] = ::tolower(str[i]); } return *this; } String String::upper() const { String r = *this; r.toupper(); return r; } String String::lower() const { String r = *this; r.tolower(); return r; } String String::ltrim() const { char * d = (char *) malloc(strlen() + 1), * p, * r; int s; r = d; for (p = str; *p && *p == ' '; p++); for (s = 0; *p; *(d++) = *(p++), s++); *d = 0; return String(s, r); } String String::rtrim() const { char * d = strdup(), * r; int s = strlen(); r = d; for (d += s - 1; s && (*d == ' '); *(d--) = 0, s--); return String(s, r); } String String::trim() const { return rtrim().ltrim(); } String & String::iconv(const String & from, const String & _to) { iconv_t cd; String to = _to + "//TRANSLIT"; #ifdef __linux__ char * inbuf; #else const char * inbuf; #endif char * outbuf; size_t inleft, outleft; if ((cd = iconv_open(to.str, from.str)) == (iconv_t) (-1)) { return *this; } LOCK; inbuf = str; outbuf = t; inleft = siz; outleft = BUFSIZ; memset(t, 0, BUFSIZ + 1); ::iconv (cd, &inbuf, &inleft, &outbuf, &outleft); free(str); siz = outbuf - t; // let's pad up to 4 bytes in order to be safe with wchar_t's str = (char *) malloc(siz + 4); memcpy(str, t, siz); str[siz + 0] = 0; str[siz + 1] = 0; str[siz + 2] = 0; str[siz + 3] = 0; UNLOCK; iconv_close(cd); return *this; }