/* * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT license. */ #include "Utilities.h" #include #include #if __GNUC__ < 4 #define va_copy __va_copy #endif #include #include #include #undef TR_CONTEXT #define TR_CONTEXT "Utilities" BString trim_string(const char* string, size_t len) { BString trimmed; size_t i = 0; bool addSpace = false; while (i < len) { // skip space block while (i < len && isspace(string[i])) i++; // write non-spaced (if any) if (i < len && !isspace(string[i])) { // pad with a single space, for all but the first block if (addSpace) trimmed << ' '; else addSpace = true; // append chars while (i < len && !isspace(string[i])) trimmed << string[i++]; } } return trimmed; } void parse_named_url(const BString& namedURL, BString& name, BString& url) { int32 urlStart = namedURL.FindFirst('<'); int32 urlEnd = namedURL.FindLast('>'); if (urlStart < 0 || urlEnd < 0 || urlStart + 1 >= urlEnd) { name = namedURL; url = namedURL; return; } url.SetTo(namedURL.String() + urlStart + 1, urlEnd - urlStart - 1); if (urlStart > 0) name = trim_string(namedURL, urlStart); else name = url; } // #pragma mark - StringVector StringVector::StringVector() : fStrings(NULL), fCount(0) { } StringVector::StringVector(const char* string,...) : fStrings(NULL), fCount(0) { if (string == NULL) return; va_list list; va_start(list, string); SetTo(string, list); va_end(list); } StringVector::StringVector(const BMessage& strings, const char* fieldName) : fStrings(NULL), fCount(0) { SetTo(strings, fieldName); } StringVector::StringVector(const StringVector& other) : fStrings(NULL), fCount(0) { if (other.fCount == 0) return; fStrings = new BString[other.fCount]; fCount = other.fCount; for (int32 i = 0; i < fCount; i++) fStrings[i] = other.fStrings[i]; } StringVector::~StringVector() { Unset(); } void StringVector::SetTo(const char* string,...) { va_list list; va_start(list, string); SetTo(string, list); va_end(list); } void StringVector::SetTo(const char* string, va_list _list) { // free old strings Unset(); if (string == NULL) return; // count strings va_list list; va_copy(list, _list); fCount = 1; while (va_arg(list, const char*) != NULL) fCount++; va_end(list); // create array and copy them fStrings = new BString[fCount]; fStrings[0] = string; va_copy(list, _list); for (int32 i = 1; i < fCount; i++) fStrings[i] = va_arg(list, const char*); va_end(list); } void StringVector::SetTo(const BMessage& strings, const char* fieldName, const char* prefix) { Unset(); type_code type; int32 count; if (strings.GetInfo(fieldName, &type, &count) != B_OK || type != B_STRING_TYPE) { return; } fStrings = new BString[count]; for (int32 i = 0; i < count; i++) { if (strings.FindString(fieldName, i, &fStrings[i]) != B_OK) return; if (prefix != NULL) fStrings[i].Prepend(prefix); fCount++; } } void StringVector::Unset() { delete[] fStrings; fStrings = NULL; fCount = 0; } const char* StringVector::StringAt(int32 index) const { return (index >= 0 && index < fCount ? fStrings[index].String() : NULL); } // #pragma mark - PackageCredit PackageCredit::PackageCredit(const char* packageName) : fPackageName(packageName) { } PackageCredit::PackageCredit(const BMessage& packageDescription) { const char* package; const char* copyright; const char* url; // package and copyright are mandatory if (packageDescription.FindString("Package", &package) != B_OK || packageDescription.FindString("Copyright", ©right) != B_OK) { return; } // URL is optional if (packageDescription.FindString("URL", &url) != B_OK) url = NULL; fPackageName = package; fCopyrights.SetTo(packageDescription, "Copyright", COPYRIGHT_STRING); fLicenses.SetTo(packageDescription, "License"); fSources.SetTo(packageDescription, "SourceURL"); fURL = url; } PackageCredit::PackageCredit(const PackageCredit& other) : fPackageName(other.fPackageName), fCopyrights(other.fCopyrights), fLicenses(other.fLicenses), fSources(other.fSources), fURL(other.fURL) { } PackageCredit::~PackageCredit() { } bool PackageCredit::IsValid() const { // should have at least a package name and a copyright return fPackageName.Length() > 0 && !fCopyrights.IsEmpty(); } bool PackageCredit::IsBetterThan(const PackageCredit& other) const { // We prefer credits with licenses. if (CountLicenses() > 0 && other.CountLicenses() == 0) return true; // Scan the copyrights for year numbers and let the greater one win. return _MaxCopyrightYear() > other._MaxCopyrightYear(); } PackageCredit& PackageCredit::SetCopyrights(const char* copyright,...) { va_list list; va_start(list, copyright); fCopyrights.SetTo(copyright, list); va_end(list); return *this; } PackageCredit& PackageCredit::SetCopyright(const char* copyright) { return SetCopyrights(copyright, NULL); } PackageCredit& PackageCredit::SetLicenses(const char* license,...) { va_list list; va_start(list, license); fLicenses.SetTo(license, list); va_end(list); return *this; } PackageCredit& PackageCredit::SetLicense(const char* license) { return SetLicenses(license, NULL); } PackageCredit& PackageCredit::SetSources(const char* source,...) { va_list list; va_start(list, source); fSources.SetTo(source, list); va_end(list); return *this; } PackageCredit& PackageCredit::SetSource(const char* source) { return SetSources(source, NULL); } PackageCredit& PackageCredit::SetURL(const char* url) { fURL = url; return *this; } const char* PackageCredit::PackageName() const { return fPackageName.String(); } const StringVector& PackageCredit::Copyrights() const { return fCopyrights; } int32 PackageCredit::CountCopyrights() const { return fCopyrights.CountStrings(); } const char* PackageCredit::CopyrightAt(int32 index) const { return fCopyrights.StringAt(index); } const StringVector& PackageCredit::Licenses() const { return fLicenses; } int32 PackageCredit::CountLicenses() const { return fLicenses.CountStrings(); } const char* PackageCredit::LicenseAt(int32 index) const { return fLicenses.StringAt(index); } const StringVector& PackageCredit::Sources() const { return fSources; } int32 PackageCredit::CountSources() const { return fSources.CountStrings(); } const char* PackageCredit::SourceAt(int32 index) const { return fSources.StringAt(index); } const char* PackageCredit::URL() const { return fURL.Length() > 0 ? fURL.String() : NULL; } /*static*/ bool PackageCredit::NameLessInsensitive(const PackageCredit* a, const PackageCredit* b) { return a->fPackageName.ICompare(b->fPackageName) < 0; } int PackageCredit::_MaxCopyrightYear() const { int maxYear = 0; for (int32 i = 0; const char* string = CopyrightAt(i); i++) { // iterate through the numbers int32 start = 0; while (true) { // find the next number start while (string[start] != '\0' && !isdigit(string[start])) start++; if (string[start] == '\0') break; // find the end int32 end = start + 1; while (string[end] != '\0' && isdigit(string[end])) end++; if (end - start == 4) { int year = atoi(string + start); if (year > 1900 && year < 2200 && year > maxYear) maxYear = year; } start = end; } } return maxYear; }