/******************************************************************************* * BString.cc Beams String Class * T.Barnaby, BEAm Ltd, 15/7/92 * updated by D.Korchagin, CERN AB-BI-SW, 2007-08-31 ******************************************************************************* */ #ifndef __Lynx__ #else #include #endif #include #include #include #include #include #include #include #if TARGET_win32 int vasprintf(char** sptr, const char* fmt, va_list argv){ int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv); if((wanted < 0) || ((*sptr = (char*)malloc( 1 + wanted )) == NULL)) return -1; return vsprintf(*sptr, fmt, argv); } #else #include #endif #ifndef __Lynx__ #else inline int vasprintf(char **resultp, const char *format, va_list args) { int ret_val; int size = 512 * sizeof (char); *resultp = (char *) malloc (size); while ((((ret_val = vsprintf(*resultp, format, args)) >= size) || (ret_val < 0)) && (*resultp != NULL)) *resultp = (char *) realloc (*resultp, size = (ret_val < 0) ? (2 * size) : (size + sizeof('\0'))); return ret_val; } #endif # define STRIP 0x7f # define MINUS '-' static int gmatch(const char *s, const char *p){ int scc; char c; if (scc = *s++) { if ((scc &= STRIP) == 0) scc=0200; } switch (c = *p++) { case '[': { int ok; int lc; int notflag = 0; ok = 0; lc = 077777; if (*p == '!') { notflag = 1; p++; } while (c = *p++) { if (c == ']') return(ok ? gmatch(s, p) : 0); else if (c == MINUS) { if (notflag) { if (scc < lc || scc > *(p++)) ok++; else return(0); } else { if (lc <= scc && scc <= (*p++)) ok++; } } else { lc = c & STRIP; if (notflag) { if (scc && scc != lc) ok++; else return(0); } else { if (scc == lc) ok++; } } } return(0); } default: if ((c & STRIP) != scc) return(0); case '?': return(scc ? gmatch(s, p) : 0); case '\\': c = *p++; if((c & STRIP) != scc) return(0); case '*': while (*p == '*') p++; if (*p == 0) return(1); --s; while (*s) { if (gmatch(s++, p)) return(1); } return(0); case '!': return !gmatch(--s, p); case 0: return(scc == 0); } } BString::~BString(){ if(ostr && (ostr->deleteRef() == 0)){ delete ostr; } ostr = 0; } BString::BString(){ ostr = 0; } BString::BString(const BString& string){ if(string.ostr) ostr = string.ostr->addRef(); else ostr = 0; } BString::BString(const char* str){ if(str && str[0]){ ostr = new BRefData(strlen(str) + 1); strcpy(ostr->data(), str); } else { ostr = 0; } } BString::BString(const char* str, unsigned int len){ if(str && len && str[0]){ ostr = new BRefData(len + 1); strncpy(ostr->data(), str, len); ostr->data()[len] = '\0'; } else { ostr = 0; } } BString::BString(char ch){ ostr = new BRefData(2); ostr->data()[0] = ch; ostr->data()[1] = 0; } BString::BString(BInt value){ char buf[32]; sprintf(buf, "%d", value); ostr = new BRefData(strlen(buf) + 1); strcpy(ostr->data(), buf); } BString::BString(BUInt value){ char buf[32]; sprintf(buf, "%u", value); ostr = new BRefData(strlen(buf) + 1); strcpy(ostr->data(), buf); } BString::BString(BUInt64 value){ char buf[32]; #if __WORDSIZE == 64 sprintf(buf, "%ld", value); #else sprintf(buf, "%lld", value); #endif ostr = new BRefData(strlen(buf) + 1); strcpy(ostr->data(), buf); } BString::BString(double value){ char buf[32]; sprintf(buf, "%f", value); ostr = new BRefData(strlen(buf) + 1); strcpy(ostr->data(), buf); } void BString::init(const char* str) { if(str && str[0]){ ostr = new BRefData(strlen(str) + 1); strcpy(ostr->data(), str); } else { ostr = 0; } } BString BString::convert(char value){ char buf[128]; sprintf(buf, "%c", value); return buf; } BString BString::convert(BInt value){ char buf[128]; sprintf(buf, "%d", value); return buf; } BString BString::convert(BUInt value){ char buf[128]; sprintf(buf, "%u", value); return buf; } BString BString::convert(double value, int eFormat){ char buf[128]; if(eFormat) sprintf(buf, "%e", value); else sprintf(buf, "%f", value); return buf; } BString BString::convert(BUInt64 value){ char buf[128]; #if __WORDSIZE == 64 sprintf(buf, "%ld", value); #else sprintf(buf, "%lld", value); #endif return buf; } BString BString::convertHex(BInt value){ char buf[128]; sprintf(buf, "0x%x", value); return buf; } BString BString::convertHex(BUInt value){ char buf[128]; sprintf(buf, "0x%x", value); return buf; } BString BString::copy() const { BString s; s = retStr(); return s; } int BString::len() const { int l = 0; if(ostr && ostr->len()) l = ostr->len() - 1; return l; } BString& BString::truncate(int l) { if(ostr){ ostr = ostr->copy(); if(l < len()){ ostr->setLen(l + 1); ostr->data()[l] = '\0'; } } return *this; } void BString::clear(){ if(ostr && (ostr->deleteRef() == 0)){ delete ostr; } ostr = 0; } BString& BString::pad(int l) { if(ostr){ ostr = ostr->copy(); } while(l > len()){ *this = *this + " "; } return *this; } BString& BString::toUpper(){ char* s; if(ostr){ ostr = ostr->copy(); for(s = ostr->data(); *s; s++) *s = toupper(*s); } return *this; } BString& BString::toLower(){ char* s; if(ostr){ ostr = ostr->copy(); for(s = ostr->data(); *s; s++) *s = tolower(*s); } return *this; } BString BString::lowerFirst(){ BString s; if(ostr && len()){ s = retStr(); s[0] = tolower(s[0]); } return s; } void BString::removeNL(){ if(ostr){ ostr = ostr->copy(); if((len() > 1) && (ostr->data()[len() - 1] == '\n') && (ostr->data()[len() - 2] == '\r')) truncate(len() - 2); else if(len() && (ostr->data()[len() - 1] == '\n')) truncate(len() - 1); } } BString BString::justify(int leftMargin, int width){ BString r; char* s; int x = 0; if(ostr){ for(s = ostr->data(); *s; s++){ if(x > width){ r = r + "\n"; x = 0; } if(x == 0){ while(x < leftMargin){ r = r + " "; x++; } } if(*s == '\n'){ r = r + *s; x = 0; } else if((x > (7 * width) / 8) && isspace(*s)){ r = r + "\n"; x = 0; } else { r = r + *s; x++; } } } return r; } BString BString::fixedLen(int length, int rightJustify){ BString str; int l; int ls = length; int p = 0; str.ostr = new BRefData(length + 1); str.ostr->data()[length] = '\0'; if(len() < ls) ls = len(); if(rightJustify){ l = length - len(); while(l-- > 0) str.ostr->data()[p++] = ' '; } for(l = 0; l < ls; l++){ str.ostr->data()[p++] = get(l); } if(!rightJustify){ while(l++ < length) str.ostr->data()[p++] = ' '; } return str; } BString BString::firstLine(){ return subString(0, find('\n')); } BString BString::translateChar(char ch, BString replace){ BString s; char c; int i; for(i = 0; i < len(); i++){ c = get(i); if(c == ch) s += replace; else s += c; } return s; } BString BString::csvEncode() const { BString s; char c; int i; for(i = 0; i < len(); i++){ c = get(i); if(c == ',') s += "\\,"; else if(c == '\n') s += "\\n"; else s += c; } return s; } BString& BString::csvDecode(const BString str){ char c; int i; clear(); for(i = 0; i < str.len(); i++){ c = str[i]; if((c == '\\') && (i < (len() - 2))) *this += get(++i); else *this += c; } return *this; } // Base64 functions BString BString::base64Encode() const { const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const BUInt8* data = (const BUInt8*)retStr(); BUInt resultIndex = 0; int x; BUInt32 n = 0; int padCount = len() % 3; BUInt8 n0, n1, n2, n3; BString str; for(x = 0; x < len(); x += 3){ n = ((uint32_t)data[x]) << 16; if((x + 1) < len()) n += ((BUInt32)data[x + 1]) << 8; if((x + 2) < len()) n += data[x + 2]; /* This 24-bit number gets separated into four 6-bit numbers */ n0 = (BUInt8)(n >> 18) & 63; n1 = (BUInt8)(n >> 12) & 63; n2 = (BUInt8)(n >> 6) & 63; n3 = (BUInt8)n & 63; str += char(base64chars[n0]); str += char(base64chars[n1]); if((x + 1) < len()){ str += char(base64chars[n2]); } if((x + 2) < len()){ str += char(base64chars[n3]); } } if(padCount > 0){ for(; padCount < 3; padCount++){ str += '='; } } return str; } static const BUInt8 base64_decode_table[] = { 66,66,66,66,66,66,66,66,66,66,64,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,62,66,66,66,63,52,53, 54,55,56,57,58,59,60,61,66,66,66,65,66,66,66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,66,66,66,66,66,66,26,27,28, 29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,66,66, 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66 }; BError BString::base64Decode(BString& str) const { BError err; const char* in = retStr(); const char* end = in + len(); char iter = 0; uint32_t buf = 0; size_t len = 0; while(in < end){ BUInt8 c = base64_decode_table[int(*in++)]; switch(c){ case 64: // Skip whitespace continue; case 66: // Error return err.set(1); case 65: // Pad character, end of data in = end; continue; default: buf = buf << 6 | c; iter++; if(iter == 4){ str += char((buf >> 16) & 255); str += char((buf >> 8) & 255); str += char(buf & 255); buf = 0; iter = 0; } } } if(iter == 3){ str += char((buf >> 10) & 255); str += char((buf >> 2) & 255); } else if(iter == 2) { str += char((buf >> 4) & 255); } return err; } BString BString::reverse() const { BString s = copy(); int f; int t; if(ostr){ for(t = 0, f = len() - 1; t < len(); t++, f--) s.ostr->data()[t] = ostr->data()[f]; } return s; } BString BString::subString(int start, int l) const { BString s; if(ostr && inString(start) && len()){ if(l >= 0){ if(l > (len() - start)) l = len() - start; s = BString(&ostr->data()[start], l); } else { s = &ostr->data()[start]; } } return s; } int BString::inString(int pos) const { int r = 0; if((pos >= 0) && (pos <= len())) r = 1; return r; } int BString::del(int start, int l){ char* d; char* s; int r = 0; if(ostr){ ostr = ostr->copy(); if(inString(start) && len()){ if(l > (len() - start)) l = len() - start; d = &ostr->data()[start]; s = &ostr->data()[start + l]; while(*d++ = *s++); ostr->setLen(ostr->len() - l); r = 1; } } return r; } int BString::insert(int start, BString str){ BString s; int r = 0; if(inString(start)){ if(start) s = subString(0, start); s = s + str; s = s + subString(start, -1); *this = s; r = 1; } return r; } BString& BString::printf(const char* fmt, ...) { va_list ap; int l; char* s = 0; if(ostr && ostr->deleteRef() == 0) delete ostr; ostr = 0; va_start(ap, fmt); l = vasprintf(&s, fmt, ap); va_end(ap); if(l >= 0){ *this = s; free(s); } return *this; } int BString::find(char ch) const { char* a; int p = -1; if(ostr && (a = strchr(ostr->data(), ch))) p = a - ostr->data(); return p; } int BString::find(BString str) const { char* a; int p = -1; if(ostr && (a = strstr(ostr->data(), str))) p = a - ostr->data(); return p; } int BString::findReverse(char ch) const { char* a; int p = -1; if(ostr && (a = strrchr(ostr->data(), ch))) p = a - ostr->data(); return p; } int BString::isSpace(char ch) const { return ((ch == ',') || (ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r')); } BString BString::field(int field) const { char* ps; char* pe; BString s; if(ostr){ ps = ostr->data(); while(field && ps && *ps){ while(*ps && !isSpace(*ps)){ if(*ps == '"'){ ps++; while(*ps && (*ps != '"')) ps++; } else if(*ps == '('){ ps++; while(*ps && (*ps != ')')) ps++; } ps++; } while(*ps && isSpace(*ps)) ps++; field--; } pe = ps; while(*pe && !isSpace(*pe)){ if(*pe == '"'){ pe++; while(*pe && (*pe != '"')) pe++; } else if(*pe == '('){ pe++; while(*pe && (*pe != ')')) pe++; } pe++; } if(*ps == '"'){ ps++; pe--; } s = ps; s.truncate(pe - ps); } return s; } char** BString::fields(){ BString a; char** r; char** o; int f; o = r = new char* [64 + 1]; for(f = 0; f < 64; f++){ a = field(f); if(a != ""){ *o = new char [a.len() + 1]; strcpy(*o, a.retStr()); } else { break; } o++; } *o = 0; return r; } BList BString::getTokenList(BString separators){ BList list; BString s = *this; BString t; while((t = s.pullToken(separators)) != ""){ list.append(t.removeSeparators(separators)); } return list; } BList BString::getTokenList(char separator){ BList list; int s = 0; int e = s; while(s < len()){ e = s; while((e < len()) && (ostr->data()[e] != separator)){ e++; } list.append(subString(s, e - s)); s = ++e; } return list; } BString BString::pullToken(BString terminators){ char* p = 0; int s; int e; int n; BString ret; if(ostr){ p = ostr->data(); s = 0; while(*p && strchr(terminators, *p)){ s++; p++; } e = s; while(*p && !strchr(terminators, *p)){ e++; p++; } n = e; while(*p && strchr(terminators, *p)){ n++; p++; } ret = subString(s, e - s); *this = subString(n, -1); } return ret; } BString BString::removeSeparators(BString separators){ char* p = 0; int s; int e; BString r; if(ostr){ p = ostr->data(); s = 0; while(*p && strchr(separators, *p)){ s++; p++; } e = len() - 1; if(e > 0){ p = ostr->data() + len() - 1; while(*p && strchr(separators, *p)){ e--; p--; } } r =subString(s, e - s + 1); } return r; } BString BString::pullSeparators(BString separators){ char* p = 0; int e; BString ret; if(ostr){ p = ostr->data(); e = 0; while(*p && strchr(separators, *p)){ e++; p++; } ret = subString(0, e); *this = subString(e, -1); } return ret; } BString BString::pullWord(){ return pullToken(" \t\n"); } BString BString::pullLine(){ return pullToken("\n"); } BList BString::split(char splitChar){ BList list; int s = 0; int e = 0; char c = 0; while(s < len()){ e = s; while((e < len()) && ((c = get(e)) != splitChar)) e++; list.append(subString(s, e - s)); s = e + 1; } if(c == splitChar) list.append(""); return list; } int BString::compare(const BString& string) const { int r; r = strcmp(retStr(), string.retStr()); return r; } int BString::compareWild(const BString& string) const { int r; r = gmatch(retStr(), string.retStr()); return r; } int BString::compareWildExpression(const BString& string) const { BString e; int n; int r = 0; for(n = 0; (e = string.field(n)) != ""; n++){ if(e[0] == '!'){ if(gmatch(retStr(), e.retStr() + 1)){ r = 0; break; } } else { if(gmatch(retStr(), e.retStr())){ r = 1; break; } } } return r; } #if !TARGET_win32 int BString::compareRegex(const BString& pattern, int ignoreCase) const { int r = 0; regex_t re; int reFlags = REG_EXTENDED | REG_NOSUB; if(ignoreCase) reFlags |= REG_ICASE; if(regcomp(&re, pattern, reFlags) != 0) return 0; if(regexec(&re, retStr(), 0, NULL, 0) == 0) r = 1; regfree(&re); return r; } #endif const char* BString::retStr() const { static char z[] = ""; char* r = z; if(ostr) r = ostr->data(); return r; } char* BString::retStrDup() const { char* r; if(ostr) r = strdup(ostr->data()); else r = strdup(""); return r; } int BString::retInt() const { int r = 0; if(ostr) r = strtol(ostr->data(), NULL, 0); return r; } unsigned int BString::retUInt() const { unsigned int r = 0; if(ostr) r = strtoul(ostr->data(), NULL, 0); return r; } double BString::retDouble() const { double r = 0; if(ostr) r = strtod(ostr->data(), NULL); return r; } int BString::append(const BString& string) { if(ostr){ if(string.ostr){ ostr = ostr->copy(); ostr->setLen(len() + string.len() + 1); strcat(ostr->data(), string.ostr->data()); } } else { if(string.ostr){ ostr = string.ostr->addRef(); } } return 0; } BString BString::add(const BString& string) const { BString s; if(ostr || string.ostr){ s.ostr = new BRefData(len() + string.len() + 1); s.ostr->data()[0] = '\0'; if(ostr) strcat(s.ostr->data(), ostr->data()); if(string.ostr) strcat(s.ostr->data(), string.ostr->data()); } return s; } BString& BString::operator=(const BString& string) { if(this != &string){ if(ostr && (ostr->deleteRef() == 0)) delete ostr; if(string.ostr) ostr = string.ostr->addRef(); else ostr = 0; } return *this; } char& BString::get(int pos){ char* p = (char*)""; if(ostr){ p = &ostr->data()[pos]; } else { fprintf(stderr, "BString: array operator out of range\n"); exit(1); } return *p; } const char& BString::get(int pos) const{ char* p = (char*)""; if(ostr){ p = &ostr->data()[pos]; } else { fprintf(stderr, "BString: array operator out of range\n"); exit(1); } return *p; } char& BString::operator[](int pos){ char* p = (char*)""; if(ostr){ p = &ostr->data()[pos]; } else { fprintf(stderr, "BString: array operator out of range\n"); exit(1); } return *p; } BString BString::dirname(){ BString r; int e; if((e = findReverse('/')) >= 0){ r = subString(0, e); } return r; } BString BString::basename(){ int s; int e; if((s = findReverse('/')) >= 0) s = s + 1; else s = 0; if((e = findReverse('.')) >= 0) e = e - s; return subString(s, e); } BString BString::extension(){ BString r; int s; if((s = findReverse('.')) >= 0) r = subString(s + 1, -1); return r; } BUInt32 BString::hash() const { BUInt32 hash = 0; char* p = 0; int c; if(ostr && (p = ostr->data())){ hash = 5381; while(c = *p++){ hash = ((hash << 5) + hash) + c; // hash * 33 + c } } return hash; } #ifdef ZAP BString operator+(const char* a1, BString& a2) { return (BString)a1 + a2; } #endif std::ostream& operator<<(std::ostream& o, BString& s){ o << s.retStr(); return o; } std::istream& operator>>(std::istream& i, BString& s){ char buf[1024]; i >> buf; s = (BString)buf; return i; } int bstringListinList(BStringList& list, BString s){ BIter i; int r = 0; for(list.start(i); !list.isEnd(i); list.next(i)){ if(list[i] == s) return 1; } return r; } BString blistToString(const BStringList& list){ BString s; BIter i; for(list.start(i); !list.isEnd(i); list.next(i)){ if(s.len()) s += ","; s = s + list[i]; } return s; } BStringList bstringToList(BString str, int stripSpaces){ BList list; int s = 0; int e = 0; int em = 0; char c = 0; while(s < str.len()){ e = s; while((e < str.len()) && ((c = str[e]) != ',')) e++; em = e; if(stripSpaces){ while((s < em) && isspace(str[s])) s++; while((em > s) && isspace(str[em - 1])) em--; } list.append(str.subString(s, em - s)); s = e + 1; } if(c == ',') list.append(""); return list; } BStringList charToList(const char** str){ BList list; while(*str){ list.append(*str); str++; } return list; } BString barrayToString(const BStringArray& list){ BString s; BUInt i; for(i = 0; i < list.size(); i++){ if(s.len()) s += ","; s = s + list[i]; } return s; } BStringArray bstringToArray(BString str, int stripSpaces){ BStringArray list; int s = 0; int e = 0; int em = 0; char c = 0; while(s < str.len()){ e = s; while((e < str.len()) && ((c = str[e]) != ',')) e++; em = e; if(stripSpaces){ while((s < em) && isspace(str[s])) s++; while((em > s) && isspace(str[em - 1])) em--; } list.append(str.subString(s, em - s)); s = e + 1; } if(c == ',') list.append(""); return list; } BStringArray charToArray(const char** str){ BStringArray list; while(*str){ list.append(*str); str++; } return list; } // String conversion functions void toBString(BString& v, BString& s){ s = v; } void toBString(BStringList& v, BString& s){ s = blistToString(v); } void toBString(BInt32& v, BString& s){ s = BString::convert(v); } void toBString(BUInt32& v, BString& s){ s = BString::convert(v); } void toBString(BUInt64& v, BString& s){ s.printf("%lld", v); } void toBString(BFloat64& v, BString& s){ s.printf("%.8e", v); } void fromBString(BString& s, BString& v){ v = s; } void fromBString(BString& s, BStringList& v){ v = bstringToList(s); } void fromBString(BString& s, BInt32& v){ v = s.retInt(); } void fromBString(BString& s, BUInt32& v){ v = s.retUInt(); } void fromBString(BString& s, BUInt64& v){ v = strtoull(s.retStr(), NULL, 0); } void fromBString(BString& s, BFloat64& v){ v = s.retDouble(); }