xref: /haiku/src/apps/aboutsystem/Utilities.cpp (revision 25a7b01d15612846f332751841da3579db313082)
1 /*
2  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT license.
4  */
5 
6 #include "Utilities.h"
7 
8 #include <ctype.h>
9 #include <stdlib.h>
10 
11 #if __GNUC__ < 4
12 #define va_copy		__va_copy
13 #endif
14 
15 #include <Catalog.h>
16 #include <Locale.h>
17 #include <Message.h>
18 
19 
20 #undef B_TRANSLATION_CONTEXT
21 #define B_TRANSLATION_CONTEXT "Utilities"
22 
23 
24 BString
trim_string(const char * string,size_t len)25 trim_string(const char* string, size_t len)
26 {
27 	BString trimmed;
28 	size_t i = 0;
29 	bool addSpace = false;
30 
31 	while (i < len) {
32 		// skip space block
33 		while (i < len && isspace(string[i]))
34 			i++;
35 
36 		// write non-spaced (if any)
37 		if (i < len && !isspace(string[i])) {
38 			// pad with a single space, for all but the first block
39 			if (addSpace)
40 				trimmed << ' ';
41 			else
42 				addSpace = true;
43 
44 			// append chars
45 			while (i < len && !isspace(string[i]))
46 				trimmed << string[i++];
47 		}
48 	}
49 
50 	return trimmed;
51 }
52 
53 
54 void
parse_named_url(const BString & namedURL,BString & name,BString & url)55 parse_named_url(const BString& namedURL, BString& name, BString& url)
56 {
57 	int32 urlStart = namedURL.FindFirst('<');
58 	int32 urlEnd = namedURL.FindLast('>');
59 	if (urlStart < 0 || urlEnd < 0 || urlStart + 1 >= urlEnd) {
60 		name = namedURL;
61 		url = namedURL;
62 		return;
63 	}
64 
65 	url.SetTo(namedURL.String() + urlStart + 1, urlEnd - urlStart - 1);
66 
67 	if (urlStart > 0)
68 		name = trim_string(namedURL, urlStart);
69 	else
70 		name = url;
71 }
72 
73 
74 // #pragma mark - StringVector
75 
76 
StringVector()77 StringVector::StringVector()
78 	:
79 	fStrings(NULL),
80 	fCount(0)
81 {
82 }
83 
84 
StringVector(const char * string,...)85 StringVector::StringVector(const char* string,...)
86 	:
87 	fStrings(NULL),
88 	fCount(0)
89 {
90 	if (string == NULL)
91 		return;
92 
93 	va_list list;
94 	va_start(list, string);
95 	SetTo(string, list);
96 	va_end(list);
97 }
98 
99 
StringVector(const BMessage & strings,const char * fieldName)100 StringVector::StringVector(const BMessage& strings, const char* fieldName)
101 	:
102 	fStrings(NULL),
103 	fCount(0)
104 {
105 	SetTo(strings, fieldName);
106 }
107 
108 
StringVector(const StringVector & other)109 StringVector::StringVector(const StringVector& other)
110 	:
111 	fStrings(NULL),
112 	fCount(0)
113 {
114 	if (other.fCount == 0)
115 		return;
116 
117 	fStrings = new BString[other.fCount];
118 	fCount = other.fCount;
119 
120 	for (int32 i = 0; i < fCount; i++)
121 		fStrings[i] = other.fStrings[i];
122 }
123 
124 
~StringVector()125 StringVector::~StringVector()
126 {
127 	Unset();
128 }
129 
130 
131 void
SetTo(const char * string,...)132 StringVector::SetTo(const char* string,...)
133 {
134 	va_list list;
135 	va_start(list, string);
136 	SetTo(string, list);
137 	va_end(list);
138 }
139 
140 
141 void
SetTo(const char * string,va_list _list)142 StringVector::SetTo(const char* string, va_list _list)
143 {
144 	// free old strings
145 	Unset();
146 
147 	if (string == NULL)
148 		return;
149 
150 	// count strings
151 	va_list list;
152 	va_copy(list, _list);
153 	fCount = 1;
154 	while (va_arg(list, const char*) != NULL)
155 		fCount++;
156 	va_end(list);
157 
158 	// create array and copy them
159 	fStrings = new BString[fCount];
160 	fStrings[0] = string;
161 
162 	va_copy(list, _list);
163 	for (int32 i = 1; i < fCount; i++)
164 		fStrings[i] = va_arg(list, const char*);
165 	va_end(list);
166 
167 }
168 
169 
170 void
SetTo(const BMessage & strings,const char * fieldName,const char * prefix)171 StringVector::SetTo(const BMessage& strings, const char* fieldName,
172 	const char* prefix)
173 {
174 	Unset();
175 
176 	type_code type;
177 	int32 count;
178 	if (strings.GetInfo(fieldName, &type, &count) != B_OK
179 		|| type != B_STRING_TYPE) {
180 		return;
181 	}
182 
183 	fStrings = new BString[count];
184 
185 	for (int32 i = 0; i < count; i++) {
186 		if (strings.FindString(fieldName, i, &fStrings[i]) != B_OK)
187 			return;
188 
189 		if (prefix != NULL)
190 			fStrings[i].Prepend(prefix);
191 
192 		fCount++;
193 	}
194 }
195 
196 
197 void
Unset()198 StringVector::Unset()
199 {
200 	delete[] fStrings;
201 	fStrings = NULL;
202 	fCount = 0;
203 }
204 
205 
206 const char*
StringAt(int32 index) const207 StringVector::StringAt(int32 index) const
208 {
209 	return (index >= 0 && index < fCount ? fStrings[index].String() : NULL);
210 }
211 
212 
213 // #pragma mark - PackageCredit
214 
215 
PackageCredit(const char * packageName)216 PackageCredit::PackageCredit(const char* packageName)
217 	:
218 	fPackageName(packageName)
219 {
220 }
221 
222 
PackageCredit(const BMessage & packageDescription)223 PackageCredit::PackageCredit(const BMessage& packageDescription)
224 {
225 	const char* package;
226 	const char* copyright;
227 	const char* url;
228 
229 	// package and copyright are mandatory
230 	if (packageDescription.FindString("Package", &package) != B_OK
231 		|| packageDescription.FindString("Copyright", &copyright) != B_OK) {
232 		return;
233 	}
234 
235 	// URL is optional
236 	if (packageDescription.FindString("URL", &url) != B_OK)
237 		url = NULL;
238 
239 	fPackageName = package;
240 	fCopyrights.SetTo(packageDescription, "Copyright", COPYRIGHT_STRING);
241 	fLicenses.SetTo(packageDescription, "License");
242 	fSources.SetTo(packageDescription, "SourceURL");
243 	fURL = url;
244 }
245 
246 
PackageCredit(const PackageCredit & other)247 PackageCredit::PackageCredit(const PackageCredit& other)
248 	:
249 	fPackageName(other.fPackageName),
250 	fCopyrights(other.fCopyrights),
251 	fLicenses(other.fLicenses),
252 	fSources(other.fSources),
253 	fURL(other.fURL)
254 {
255 }
256 
257 
~PackageCredit()258 PackageCredit::~PackageCredit()
259 {
260 }
261 
262 
263 bool
IsValid() const264 PackageCredit::IsValid() const
265 {
266 	// should have at least a package name and a copyright
267 	return fPackageName.Length() > 0 && !fCopyrights.IsEmpty();
268 }
269 
270 
271 bool
IsBetterThan(const PackageCredit & other) const272 PackageCredit::IsBetterThan(const PackageCredit& other) const
273 {
274 	// We prefer credits with licenses.
275 	if (CountLicenses() > 0 && other.CountLicenses() == 0)
276 		return true;
277 
278 	// Scan the copyrights for year numbers and let the greater one win.
279 	return _MaxCopyrightYear() > other._MaxCopyrightYear();
280 }
281 
282 
283 PackageCredit&
SetCopyrights(const char * copyright,...)284 PackageCredit::SetCopyrights(const char* copyright,...)
285 {
286 	va_list list;
287 	va_start(list, copyright);
288 	fCopyrights.SetTo(copyright, list);
289 	va_end(list);
290 
291 	return *this;
292 }
293 
294 
295 PackageCredit&
SetCopyright(const char * copyright)296 PackageCredit::SetCopyright(const char* copyright)
297 {
298 	return SetCopyrights(copyright, NULL);
299 }
300 
301 
302 PackageCredit&
SetLicenses(const char * license,...)303 PackageCredit::SetLicenses(const char* license,...)
304 {
305 	va_list list;
306 	va_start(list, license);
307 	fLicenses.SetTo(license, list);
308 	va_end(list);
309 
310 	return *this;
311 }
312 
313 
314 PackageCredit&
SetLicense(const char * license)315 PackageCredit::SetLicense(const char* license)
316 {
317 	return SetLicenses(license, NULL);
318 }
319 
320 
321 PackageCredit&
SetSources(const char * source,...)322 PackageCredit::SetSources(const char* source,...)
323 {
324 	va_list list;
325 	va_start(list, source);
326 	fSources.SetTo(source, list);
327 	va_end(list);
328 
329 	return *this;
330 }
331 
332 
333 PackageCredit&
SetSource(const char * source)334 PackageCredit::SetSource(const char* source)
335 {
336 	return SetSources(source, NULL);
337 }
338 
339 
340 PackageCredit&
SetURL(const char * url)341 PackageCredit::SetURL(const char* url)
342 {
343 	fURL = url;
344 
345 	return *this;
346 }
347 
348 
349 const char*
PackageName() const350 PackageCredit::PackageName() const
351 {
352 	return fPackageName.String();
353 }
354 
355 
356 const StringVector&
Copyrights() const357 PackageCredit::Copyrights() const
358 {
359 	return fCopyrights;
360 }
361 
362 
363 int32
CountCopyrights() const364 PackageCredit::CountCopyrights() const
365 {
366 	return fCopyrights.CountStrings();
367 }
368 
369 
370 const char*
CopyrightAt(int32 index) const371 PackageCredit::CopyrightAt(int32 index) const
372 {
373 	return fCopyrights.StringAt(index);
374 }
375 
376 
377 const StringVector&
Licenses() const378 PackageCredit::Licenses() const
379 {
380 	return fLicenses;
381 }
382 
383 
384 int32
CountLicenses() const385 PackageCredit::CountLicenses() const
386 {
387 	return fLicenses.CountStrings();
388 }
389 
390 
391 const char*
LicenseAt(int32 index) const392 PackageCredit::LicenseAt(int32 index) const
393 {
394 	return fLicenses.StringAt(index);
395 }
396 
397 
398 const StringVector&
Sources() const399 PackageCredit::Sources() const
400 {
401 	return fSources;
402 }
403 
404 
405 int32
CountSources() const406 PackageCredit::CountSources() const
407 {
408 	return fSources.CountStrings();
409 }
410 
411 
412 const char*
SourceAt(int32 index) const413 PackageCredit::SourceAt(int32 index) const
414 {
415 	return fSources.StringAt(index);
416 }
417 
418 
419 const char*
URL() const420 PackageCredit::URL() const
421 {
422 	return fURL.Length() > 0 ? fURL.String() : NULL;
423 }
424 
425 
426 /*static*/ bool
NameLessInsensitive(const PackageCredit * a,const PackageCredit * b)427 PackageCredit::NameLessInsensitive(const PackageCredit* a,
428 	const PackageCredit* b)
429 {
430 	return a->fPackageName.ICompare(b->fPackageName) < 0;
431 }
432 
433 
434 int
_MaxCopyrightYear() const435 PackageCredit::_MaxCopyrightYear() const
436 {
437 	int maxYear = 0;
438 
439 	for (int32 i = 0; const char* string = CopyrightAt(i); i++) {
440 		// iterate through the numbers
441 		int32 start = 0;
442 		while (true) {
443 			// find the next number start
444 			while (string[start] != '\0' && !isdigit(string[start]))
445 				start++;
446 
447 			if (string[start] == '\0')
448 				break;
449 
450 			// find the end
451 			int32 end = start + 1;
452 			while (string[end] != '\0' && isdigit(string[end]))
453 				end++;
454 
455 			if (end - start == 4) {
456 				int year = atoi(string + start);
457 				if (year > 1900 && year < 2200 && year > maxYear)
458 					maxYear = year;
459 			}
460 
461 			start = end;
462 		}
463 	}
464 
465 	return maxYear;
466 }
467