467 lines
7.3 KiB
C++
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", ©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;
|
|
}
|