haiku/src/apps/aboutsystem/Utilities.cpp

467 lines
7.3 KiB
C++

/*
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT license.
*/
#include "Utilities.h"
#include <ctype.h>
#include <stdlib.h>
#if __GNUC__ < 4
#define va_copy __va_copy
#endif
#include <Catalog.h>
#include <Locale.h>
#include <Message.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_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", &copyright) != 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;
}