2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Distributed under the terms of the MIT License.
7 #include "PackageInfoParser.h"
17 namespace BPackageKit
{
20 BPackageInfo::ParseErrorListener::~ParseErrorListener()
25 BPackageInfo::Parser::Parser(ParseErrorListener
* listener
)
34 BPackageInfo::Parser::Parse(const BString
& packageInfoString
,
35 BPackageInfo
* packageInfo
)
37 if (packageInfo
== NULL
)
40 fPos
= packageInfoString
.String();
44 } catch (const ParseError
& error
) {
45 if (fListener
!= NULL
) {
46 // map error position to line and column
49 int32 offset
= error
.pos
- packageInfoString
.String();
50 int32 newlinePos
= packageInfoString
.FindLast('\n', offset
- 1);
52 inLineOffset
= offset
;
54 inLineOffset
= offset
- newlinePos
- 1;
57 newlinePos
= packageInfoString
.FindLast('\n',
59 } while (newlinePos
>= 0);
63 for (int i
= 0; i
< inLineOffset
; i
++) {
65 if (error
.pos
[i
- inLineOffset
] == '\t')
66 column
= (column
+ 3) / 4 * 4;
69 fListener
->OnError(error
.message
, line
, column
+ 1);
72 } catch (const std::bad_alloc
& e
) {
73 if (fListener
!= NULL
)
74 fListener
->OnError("out of memory", 0, 0);
83 BPackageInfo::Parser::ParseVersion(const BString
& versionString
,
84 bool revisionIsOptional
, BPackageVersion
& _version
)
86 fPos
= versionString
.String();
89 Token
token(TOKEN_STRING
, fPos
, versionString
.Length());
90 _ParseVersionValue(token
, &_version
, revisionIsOptional
);
91 } catch (const ParseError
& error
) {
92 if (fListener
!= NULL
) {
93 int32 offset
= error
.pos
- versionString
.String();
94 fListener
->OnError(error
.message
, 1, offset
);
97 } catch (const std::bad_alloc
& e
) {
98 if (fListener
!= NULL
)
99 fListener
->OnError("out of memory", 0, 0);
108 BPackageInfo::Parser::ParseResolvableExpression(const BString
& expressionString
,
109 BPackageResolvableExpression
& _expression
)
111 fPos
= expressionString
.String();
114 Token
token(TOKEN_STRING
, fPos
, expressionString
.Length());
115 _ParseResolvableExpression(_NextToken(), _expression
, NULL
);
116 } catch (const ParseError
& error
) {
117 if (fListener
!= NULL
) {
118 int32 offset
= error
.pos
- expressionString
.String();
119 fListener
->OnError(error
.message
, 1, offset
);
122 } catch (const std::bad_alloc
& e
) {
123 if (fListener
!= NULL
)
124 fListener
->OnError("out of memory", 0, 0);
132 BPackageInfo::Parser::Token
133 BPackageInfo::Parser::_NextToken()
135 // Eat any whitespace, comments, or escaped new lines. Also eat ';' -- they
136 // have the same function as newlines. We remember the last encountered ';'
137 // or '\n' and return it as a token afterwards.
138 const char* itemSeparatorPos
= NULL
;
139 bool inComment
= false;
140 while ((inComment
&& *fPos
!= '\0') || isspace(*fPos
) || *fPos
== ';'
141 || *fPos
== '#' || *fPos
== '\\') {
144 } else if (!inComment
&& *fPos
== '\\') {
147 // ignore escaped line breaks
149 } else if (*fPos
== '\n') {
150 itemSeparatorPos
= fPos
;
152 } else if (!inComment
&& *fPos
== ';')
153 itemSeparatorPos
= fPos
;
157 if (itemSeparatorPos
!= NULL
) {
158 return Token(TOKEN_ITEM_SEPARATOR
, itemSeparatorPos
);
161 const char* tokenPos
= fPos
;
164 return Token(TOKEN_EOF
, fPos
);
168 return Token(TOKEN_OPEN_BRACE
, tokenPos
);
172 return Token(TOKEN_CLOSE_BRACE
, tokenPos
);
178 return Token(TOKEN_OPERATOR_LESS_EQUAL
, tokenPos
, 2);
180 return Token(TOKEN_OPERATOR_LESS
, tokenPos
, 1);
186 return Token(TOKEN_OPERATOR_EQUAL
, tokenPos
, 2);
188 return Token(TOKEN_OPERATOR_ASSIGN
, tokenPos
, 1);
191 if (fPos
[1] == '=') {
193 return Token(TOKEN_OPERATOR_NOT_EQUAL
, tokenPos
, 2);
201 return Token(TOKEN_OPERATOR_GREATER_EQUAL
, tokenPos
, 2);
203 return Token(TOKEN_OPERATOR_GREATER
, tokenPos
, 1);
208 char quoteChar
= '\0';
210 for (; *fPos
!= '\0'; fPos
++) {
212 if (quoteChar
!= '\0') {
213 // within a quoted string segment
214 if (c
== quoteChar
) {
220 // next char is escaped
223 throw ParseError("unterminated quoted-string",
235 // unquoted string segment
239 // quoted string start
249 // a separator character -- this ends the string
253 // next char is escaped
256 throw ParseError("'\\' at end of string",
273 return Token(TOKEN_STRING
, tokenPos
, fPos
- tokenPos
,
278 BString error
= BString("unknown token '") << *fPos
<< "' encountered";
279 throw ParseError(error
.String(), fPos
);
284 BPackageInfo::Parser::_RewindTo(const Token
& token
)
291 BPackageInfo::Parser::_ParseStringValue(BString
* value
, const char** _tokenPos
)
293 Token string
= _NextToken();
294 if (string
.type
!= TOKEN_STRING
)
295 throw ParseError("expected string", string
.pos
);
297 *value
= string
.text
;
298 if (_tokenPos
!= NULL
)
299 *_tokenPos
= string
.pos
;
304 BPackageInfo::Parser::_ParseArchitectureValue(BPackageArchitecture
* value
)
306 Token arch
= _NextToken();
307 if (arch
.type
== TOKEN_STRING
) {
308 for (int i
= 0; i
< B_PACKAGE_ARCHITECTURE_ENUM_COUNT
; ++i
) {
309 if (arch
.text
.ICompare(BPackageInfo::kArchitectureNames
[i
]) == 0) {
310 *value
= (BPackageArchitecture
)i
;
316 BString
error("architecture must be one of: [");
317 for (int i
= 0; i
< B_PACKAGE_ARCHITECTURE_ENUM_COUNT
; ++i
) {
320 error
<< BPackageInfo::kArchitectureNames
[i
];
323 throw ParseError(error
, arch
.pos
);
328 BPackageInfo::Parser::_ParseVersionValue(BPackageVersion
* value
,
329 bool revisionIsOptional
)
331 Token word
= _NextToken();
332 _ParseVersionValue(word
, value
, revisionIsOptional
);
337 BPackageInfo::Parser::_ParseVersionValue(Token
& word
, BPackageVersion
* value
,
338 bool revisionIsOptional
)
340 if (word
.type
!= TOKEN_STRING
)
341 throw ParseError("expected string (a version)", word
.pos
);
343 // get the revision number
345 int32 dashPos
= word
.text
.FindLast('-');
348 long long number
= strtoll(word
.text
.String() + dashPos
+ 1, &end
,
350 if (*end
!= '\0' || number
< 0 || number
> UINT_MAX
) {
351 throw ParseError("revision must be a number > 0 and < UINT_MAX",
352 word
.pos
+ dashPos
+ 1);
355 revision
= (uint32
)number
;
356 word
.text
.Truncate(dashPos
);
359 if (revision
== 0 && !revisionIsOptional
) {
360 throw ParseError("expected revision number (-<number> suffix)",
361 word
.pos
+ word
.text
.Length());
364 // get the pre-release string
366 int32 tildePos
= word
.text
.FindLast('~');
368 word
.text
.CopyInto(preRelease
, tildePos
+ 1,
369 word
.text
.Length() - tildePos
- 1);
370 word
.text
.Truncate(tildePos
);
372 if (preRelease
.IsEmpty()) {
373 throw ParseError("invalid empty pre-release string",
374 word
.pos
+ tildePos
+ 1);
378 if (!_IsAlphaNumUnderscore(preRelease
, ".", &errorPos
)) {
379 throw ParseError("invalid character in pre-release string",
380 word
.pos
+ tildePos
+ 1 + errorPos
);
384 // get major, minor, and micro strings
388 int32 firstDotPos
= word
.text
.FindFirst('.');
392 word
.text
.CopyInto(major
, 0, firstDotPos
);
393 int32 secondDotPos
= word
.text
.FindFirst('.', firstDotPos
+ 1);
394 if (secondDotPos
== firstDotPos
+ 1)
395 throw ParseError("expected minor version", word
.pos
+ secondDotPos
);
397 if (secondDotPos
< 0) {
398 word
.text
.CopyInto(minor
, firstDotPos
+ 1, word
.text
.Length());
400 word
.text
.CopyInto(minor
, firstDotPos
+ 1,
401 secondDotPos
- (firstDotPos
+ 1));
402 word
.text
.CopyInto(micro
, secondDotPos
+ 1, word
.text
.Length());
405 if (!_IsAlphaNumUnderscore(micro
, ".", &errorPos
)) {
406 throw ParseError("invalid character in micro version string",
407 word
.pos
+ secondDotPos
+ 1 + errorPos
);
412 if (!_IsAlphaNumUnderscore(minor
, "", &errorPos
)) {
413 throw ParseError("invalid character in minor version string",
414 word
.pos
+ firstDotPos
+ 1 + errorPos
);
419 if (!_IsAlphaNumUnderscore(major
, "", &errorPos
)) {
420 throw ParseError("invalid character in major version string",
421 word
.pos
+ errorPos
);
424 value
->SetTo(major
, minor
, micro
, preRelease
, revision
);
429 BPackageInfo::Parser::_ParseResolvableExpression(const Token
& token
,
430 BPackageResolvableExpression
& _value
, BString
* _basePackage
)
432 if (token
.type
!= TOKEN_STRING
) {
433 throw ParseError("expected word (a resolvable name)",
438 if (!_IsValidResolvableName(token
.text
, &errorPos
)) {
439 throw ParseError("invalid character in resolvable name",
440 token
.pos
+ errorPos
);
443 BPackageVersion version
;
444 Token op
= _NextToken();
445 BPackageResolvableOperator resolvableOperator
;
446 if (op
.type
== TOKEN_OPERATOR_LESS
447 || op
.type
== TOKEN_OPERATOR_LESS_EQUAL
448 || op
.type
== TOKEN_OPERATOR_EQUAL
449 || op
.type
== TOKEN_OPERATOR_NOT_EQUAL
450 || op
.type
== TOKEN_OPERATOR_GREATER_EQUAL
451 || op
.type
== TOKEN_OPERATOR_GREATER
) {
452 _ParseVersionValue(&version
, true);
454 if (_basePackage
!= NULL
) {
455 Token base
= _NextToken();
456 if (base
.type
== TOKEN_STRING
&& base
.text
== "base") {
457 if (!_basePackage
->IsEmpty()) {
458 throw ParseError("multiple packages marked as base package",
462 *_basePackage
= token
.text
;
467 resolvableOperator
= (BPackageResolvableOperator
)
468 (op
.type
- TOKEN_OPERATOR_LESS
);
469 } else if (op
.type
== TOKEN_ITEM_SEPARATOR
470 || op
.type
== TOKEN_CLOSE_BRACE
|| op
.type
== TOKEN_EOF
) {
472 resolvableOperator
= B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT
;
475 "expected '<', '<=', '==', '!=', '>=', '>', comma or '}'",
479 _value
.SetTo(token
.text
, resolvableOperator
, version
);
484 BPackageInfo::Parser::_ParseList(ListElementParser
& elementParser
,
485 bool allowSingleNonListElement
)
487 Token openBracket
= _NextToken();
488 if (openBracket
.type
!= TOKEN_OPEN_BRACE
) {
489 if (!allowSingleNonListElement
)
490 throw ParseError("expected start of list ('{')", openBracket
.pos
);
492 elementParser(openBracket
);
497 Token token
= _NextToken();
498 if (token
.type
== TOKEN_CLOSE_BRACE
)
501 if (token
.type
== TOKEN_ITEM_SEPARATOR
)
504 elementParser(token
);
510 BPackageInfo::Parser::_ParseStringList(BStringList
* value
,
511 bool requireResolvableName
, bool convertToLowerCase
)
513 struct StringParser
: public ListElementParser
{
515 bool requireResolvableName
;
516 bool convertToLowerCase
;
518 StringParser(BStringList
* value
, bool requireResolvableName
,
519 bool convertToLowerCase
)
522 requireResolvableName(requireResolvableName
),
523 convertToLowerCase(convertToLowerCase
)
527 virtual void operator()(const Token
& token
)
529 if (token
.type
!= TOKEN_STRING
)
530 throw ParseError("expected string", token
.pos
);
532 if (requireResolvableName
) {
534 if (!_IsValidResolvableName(token
.text
, &errorPos
)) {
535 throw ParseError("invalid character in resolvable name",
536 token
.pos
+ errorPos
);
540 BString
element(token
.text
);
541 if (convertToLowerCase
)
546 } stringParser(value
, requireResolvableName
, convertToLowerCase
);
548 _ParseList(stringParser
, true);
553 BPackageInfo::Parser::_ParseFlags()
555 struct FlagParser
: public ListElementParser
{
564 virtual void operator()(const Token
& token
)
566 if (token
.type
!= TOKEN_STRING
)
567 throw ParseError("expected word (a flag)", token
.pos
);
569 if (token
.text
.ICompare("approve_license") == 0)
570 flags
|= B_PACKAGE_FLAG_APPROVE_LICENSE
;
571 else if (token
.text
.ICompare("system_package") == 0)
572 flags
|= B_PACKAGE_FLAG_SYSTEM_PACKAGE
;
575 "expected 'approve_license' or 'system_package'",
581 _ParseList(flagParser
, true);
583 return flagParser
.flags
;
588 BPackageInfo::Parser::_ParseResolvableList(
589 BObjectList
<BPackageResolvable
>* value
)
591 struct ResolvableParser
: public ListElementParser
{
593 BObjectList
<BPackageResolvable
>* value
;
595 ResolvableParser(Parser
& parser_
,
596 BObjectList
<BPackageResolvable
>* value_
)
603 virtual void operator()(const Token
& token
)
605 if (token
.type
!= TOKEN_STRING
) {
606 throw ParseError("expected word (a resolvable name)",
611 if (!_IsValidResolvableName(token
.text
, &errorPos
)) {
612 throw ParseError("invalid character in resolvable name",
613 token
.pos
+ errorPos
);
617 BPackageVersion version
;
618 Token op
= parser
._NextToken();
619 if (op
.type
== TOKEN_OPERATOR_ASSIGN
) {
620 parser
._ParseVersionValue(&version
, true);
621 } else if (op
.type
== TOKEN_ITEM_SEPARATOR
622 || op
.type
== TOKEN_CLOSE_BRACE
) {
623 parser
._RewindTo(op
);
625 throw ParseError("expected '=', comma or '}'", op
.pos
);
627 // parse compatible version
628 BPackageVersion compatibleVersion
;
629 Token compatible
= parser
._NextToken();
630 if (compatible
.type
== TOKEN_STRING
631 && (compatible
.text
== "compat"
632 || compatible
.text
== "compatible")) {
633 op
= parser
._NextToken();
634 if (op
.type
== TOKEN_OPERATOR_GREATER_EQUAL
) {
635 parser
._ParseVersionValue(&compatibleVersion
, true);
637 parser
._RewindTo(compatible
);
639 parser
._RewindTo(compatible
);
641 value
->AddItem(new BPackageResolvable(token
.text
, version
,
644 } resolvableParser(*this, value
);
646 _ParseList(resolvableParser
, false);
651 BPackageInfo::Parser::_ParseResolvableExprList(
652 BObjectList
<BPackageResolvableExpression
>* value
, BString
* _basePackage
)
654 struct ResolvableExpressionParser
: public ListElementParser
{
656 BObjectList
<BPackageResolvableExpression
>* value
;
657 BString
* basePackage
;
659 ResolvableExpressionParser(Parser
& parser
,
660 BObjectList
<BPackageResolvableExpression
>* value
,
661 BString
* basePackage
)
665 basePackage(basePackage
)
669 virtual void operator()(const Token
& token
)
671 BPackageResolvableExpression expression
;
672 parser
._ParseResolvableExpression(token
, expression
, basePackage
);
673 value
->AddItem(new BPackageResolvableExpression(expression
));
675 } resolvableExpressionParser(*this, value
, _basePackage
);
677 _ParseList(resolvableExpressionParser
, false);
682 BPackageInfo::Parser::_ParseGlobalWritableFileInfos(
683 GlobalWritableFileInfoList
* infos
)
685 struct GlobalWritableFileInfoParser
: public ListElementParser
{
687 GlobalWritableFileInfoList
* infos
;
689 GlobalWritableFileInfoParser(Parser
& parser
,
690 GlobalWritableFileInfoList
* infos
)
697 virtual void operator()(const Token
& token
)
699 if (token
.type
!= TOKEN_STRING
) {
700 throw ParseError("expected string (a file path)",
704 BWritableFileUpdateType updateType
705 = B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT
;
706 bool isDirectory
= false;
708 Token nextToken
= parser
._NextToken();
709 if (nextToken
.type
== TOKEN_STRING
710 && nextToken
.text
== "directory") {
712 nextToken
= parser
._NextToken();
715 if (nextToken
.type
== TOKEN_STRING
) {
716 const char* const* end
= kWritableFileUpdateTypes
717 + B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT
;
718 const char* const* found
= std::find(kWritableFileUpdateTypes
,
719 end
, nextToken
.text
);
721 throw ParseError(BString("expected an update type"),
724 updateType
= (BWritableFileUpdateType
)(
725 found
- kWritableFileUpdateTypes
);
726 } else if (nextToken
.type
== TOKEN_ITEM_SEPARATOR
727 || nextToken
.type
== TOKEN_CLOSE_BRACE
) {
728 parser
._RewindTo(nextToken
);
731 "expected 'included', semicolon, new line or '}'",
735 if (!infos
->AddItem(new BGlobalWritableFileInfo(token
.text
,
736 updateType
, isDirectory
))) {
737 throw std::bad_alloc();
740 } resolvableExpressionParser(*this, infos
);
742 _ParseList(resolvableExpressionParser
, false);
747 BPackageInfo::Parser::_ParseUserSettingsFileInfos(
748 UserSettingsFileInfoList
* infos
)
750 struct UserSettingsFileInfoParser
: public ListElementParser
{
752 UserSettingsFileInfoList
* infos
;
754 UserSettingsFileInfoParser(Parser
& parser
,
755 UserSettingsFileInfoList
* infos
)
762 virtual void operator()(const Token
& token
)
764 if (token
.type
!= TOKEN_STRING
) {
765 throw ParseError("expected string (a settings file path)",
769 BString templatePath
;
770 bool isDirectory
= false;
772 Token nextToken
= parser
._NextToken();
773 if (nextToken
.type
== TOKEN_STRING
774 && nextToken
.text
== "directory") {
776 } else if (nextToken
.type
== TOKEN_STRING
777 && nextToken
.text
== "template") {
778 nextToken
= parser
._NextToken();
779 if (nextToken
.type
!= TOKEN_STRING
) {
781 "expected string (a settings template file path)",
784 templatePath
= nextToken
.text
;
785 } else if (nextToken
.type
== TOKEN_ITEM_SEPARATOR
786 || nextToken
.type
== TOKEN_CLOSE_BRACE
) {
787 parser
._RewindTo(nextToken
);
790 "expected 'template', semicolon, new line or '}'",
795 ? !infos
->AddItem(new BUserSettingsFileInfo(token
.text
, true))
796 : !infos
->AddItem(new BUserSettingsFileInfo(token
.text
,
798 throw std::bad_alloc();
801 } resolvableExpressionParser(*this, infos
);
803 _ParseList(resolvableExpressionParser
, false);
808 BPackageInfo::Parser::_ParseUsers(UserList
* users
)
810 struct UserParser
: public ListElementParser
{
814 UserParser(Parser
& parser
, UserList
* users
)
821 virtual void operator()(const Token
& token
)
823 if (token
.type
!= TOKEN_STRING
824 || !BUser::IsValidUserName(token
.text
)) {
825 throw ParseError("expected a user name", token
.pos
);
834 Token nextToken
= parser
._NextToken();
835 if (nextToken
.type
!= TOKEN_STRING
) {
836 parser
._RewindTo(nextToken
);
840 if (nextToken
.text
== "real-name") {
841 nextToken
= parser
._NextToken();
842 if (nextToken
.type
!= TOKEN_STRING
) {
843 throw ParseError("expected string (a user real name)",
846 realName
= nextToken
.text
;
847 } else if (nextToken
.text
== "home") {
848 nextToken
= parser
._NextToken();
849 if (nextToken
.type
!= TOKEN_STRING
) {
850 throw ParseError("expected string (a home path)",
853 home
= nextToken
.text
;
854 } else if (nextToken
.text
== "shell") {
855 nextToken
= parser
._NextToken();
856 if (nextToken
.type
!= TOKEN_STRING
) {
857 throw ParseError("expected string (a shell path)",
860 shell
= nextToken
.text
;
861 } else if (nextToken
.text
== "groups") {
863 nextToken
= parser
._NextToken();
864 if (nextToken
.type
== TOKEN_STRING
865 && BUser::IsValidUserName(nextToken
.text
)) {
866 if (!groups
.Add(nextToken
.text
))
867 throw std::bad_alloc();
868 } else if (nextToken
.type
== TOKEN_ITEM_SEPARATOR
869 || nextToken
.type
== TOKEN_CLOSE_BRACE
) {
870 parser
._RewindTo(nextToken
);
873 throw ParseError("expected a group name",
880 "expected 'real-name', 'home', 'shell', or 'groups'",
885 BString templatePath
;
887 Token nextToken
= parser
._NextToken();
888 if (nextToken
.type
== TOKEN_STRING
889 && nextToken
.text
== "template") {
890 nextToken
= parser
._NextToken();
891 if (nextToken
.type
!= TOKEN_STRING
) {
893 "expected string (a settings template file path)",
896 templatePath
= nextToken
.text
;
897 } else if (nextToken
.type
== TOKEN_ITEM_SEPARATOR
898 || nextToken
.type
== TOKEN_CLOSE_BRACE
) {
899 parser
._RewindTo(nextToken
);
902 "expected 'template', semicolon, new line or '}'",
906 if (!users
->AddItem(new BUser(token
.text
, realName
, home
, shell
,
908 throw std::bad_alloc();
911 } resolvableExpressionParser(*this, users
);
913 _ParseList(resolvableExpressionParser
, false);
918 BPackageInfo::Parser::_Parse(BPackageInfo
* packageInfo
)
920 bool seen
[B_PACKAGE_INFO_ENUM_COUNT
];
921 for (int i
= 0; i
< B_PACKAGE_INFO_ENUM_COUNT
; ++i
)
924 const char* const* names
= BPackageInfo::kElementNames
;
926 while (Token t
= _NextToken()) {
927 if (t
.type
== TOKEN_ITEM_SEPARATOR
)
930 if (t
.type
!= TOKEN_STRING
)
931 throw ParseError("expected string (a variable name)", t
.pos
);
933 BPackageInfoAttributeID attribute
= B_PACKAGE_INFO_ENUM_COUNT
;
934 for (int i
= 0; i
< B_PACKAGE_INFO_ENUM_COUNT
; i
++) {
935 if (names
[i
] != NULL
&& t
.text
.ICompare(names
[i
]) == 0) {
936 attribute
= (BPackageInfoAttributeID
)i
;
941 if (attribute
== B_PACKAGE_INFO_ENUM_COUNT
) {
942 BString error
= BString("unknown attribute \"") << t
.text
<< '"';
943 throw ParseError(error
, t
.pos
);
946 if (seen
[attribute
]) {
947 BString error
= BString(names
[attribute
]) << " already seen!";
948 throw ParseError(error
, t
.pos
);
952 case B_PACKAGE_INFO_NAME
:
956 _ParseStringValue(&name
, &namePos
);
959 if (!_IsValidResolvableName(name
, &errorPos
)) {
960 throw ParseError("invalid character in package name",
964 packageInfo
->SetName(name
);
968 case B_PACKAGE_INFO_SUMMARY
:
971 _ParseStringValue(&summary
);
972 if (summary
.FindFirst('\n') >= 0)
973 throw ParseError("the summary contains linebreaks", t
.pos
);
974 packageInfo
->SetSummary(summary
);
978 case B_PACKAGE_INFO_DESCRIPTION
:
979 _ParseStringValue(&packageInfo
->fDescription
);
982 case B_PACKAGE_INFO_VENDOR
:
983 _ParseStringValue(&packageInfo
->fVendor
);
986 case B_PACKAGE_INFO_PACKAGER
:
987 _ParseStringValue(&packageInfo
->fPackager
);
990 case B_PACKAGE_INFO_BASE_PACKAGE
:
991 _ParseStringValue(&packageInfo
->fBasePackage
);
994 case B_PACKAGE_INFO_ARCHITECTURE
:
995 _ParseArchitectureValue(&packageInfo
->fArchitecture
);
998 case B_PACKAGE_INFO_VERSION
:
999 _ParseVersionValue(&packageInfo
->fVersion
, false);
1002 case B_PACKAGE_INFO_COPYRIGHTS
:
1003 _ParseStringList(&packageInfo
->fCopyrightList
);
1006 case B_PACKAGE_INFO_LICENSES
:
1007 _ParseStringList(&packageInfo
->fLicenseList
);
1010 case B_PACKAGE_INFO_URLS
:
1011 _ParseStringList(&packageInfo
->fURLList
);
1014 case B_PACKAGE_INFO_SOURCE_URLS
:
1015 _ParseStringList(&packageInfo
->fSourceURLList
);
1018 case B_PACKAGE_INFO_GLOBAL_WRITABLE_FILES
:
1019 _ParseGlobalWritableFileInfos(
1020 &packageInfo
->fGlobalWritableFileInfos
);
1023 case B_PACKAGE_INFO_USER_SETTINGS_FILES
:
1024 _ParseUserSettingsFileInfos(
1025 &packageInfo
->fUserSettingsFileInfos
);
1028 case B_PACKAGE_INFO_USERS
:
1029 _ParseUsers(&packageInfo
->fUsers
);
1032 case B_PACKAGE_INFO_GROUPS
:
1033 _ParseStringList(&packageInfo
->fGroups
);
1036 case B_PACKAGE_INFO_POST_INSTALL_SCRIPTS
:
1037 _ParseStringList(&packageInfo
->fPostInstallScripts
);
1040 case B_PACKAGE_INFO_PROVIDES
:
1041 _ParseResolvableList(&packageInfo
->fProvidesList
);
1044 case B_PACKAGE_INFO_REQUIRES
:
1045 packageInfo
->fBasePackage
.Truncate(0);
1046 _ParseResolvableExprList(&packageInfo
->fRequiresList
,
1047 &packageInfo
->fBasePackage
);
1050 case B_PACKAGE_INFO_SUPPLEMENTS
:
1051 _ParseResolvableExprList(&packageInfo
->fSupplementsList
);
1054 case B_PACKAGE_INFO_CONFLICTS
:
1055 _ParseResolvableExprList(&packageInfo
->fConflictsList
);
1058 case B_PACKAGE_INFO_FRESHENS
:
1059 _ParseResolvableExprList(&packageInfo
->fFreshensList
);
1062 case B_PACKAGE_INFO_REPLACES
:
1063 _ParseStringList(&packageInfo
->fReplacesList
, true);
1066 case B_PACKAGE_INFO_FLAGS
:
1067 packageInfo
->SetFlags(_ParseFlags());
1071 // can never get here
1075 seen
[attribute
] = true;
1078 // everything up to and including 'provides' is mandatory
1079 for (int i
= 0; i
<= B_PACKAGE_INFO_PROVIDES
; ++i
) {
1081 BString error
= BString(names
[i
]) << " is not being set anywhere!";
1082 throw ParseError(error
, fPos
);
1088 /*static*/ inline bool
1089 BPackageInfo::Parser::_IsAlphaNumUnderscore(const BString
& string
,
1090 const char* additionalChars
, int32
* _errorPos
)
1092 return _IsAlphaNumUnderscore(string
.String(),
1093 string
.String() + string
.Length(), additionalChars
, _errorPos
);
1097 /*static*/ inline bool
1098 BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* string
,
1099 const char* additionalChars
, int32
* _errorPos
)
1101 return _IsAlphaNumUnderscore(string
, string
+ strlen(string
),
1102 additionalChars
, _errorPos
);
1107 BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* start
, const char* end
,
1108 const char* additionalChars
, int32
* _errorPos
)
1110 for (const char* c
= start
; c
< end
; c
++) {
1111 if (!isalnum(*c
) && *c
!= '_' && strchr(additionalChars
, *c
) == NULL
) {
1112 if (_errorPos
!= NULL
)
1113 *_errorPos
= c
- start
;
1123 BPackageInfo::Parser::_IsValidResolvableName(const char* string
,
1126 for (const char* c
= string
; *c
!= '\0'; c
++) {
1141 if (_errorPos
!= NULL
)
1142 *_errorPos
= c
- string
;
1149 } // namespace BPackageKit