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", ©right) != 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