package kit: Add API for parsing resolvable expression strings

* Add BPackageInfo::ParseResolvableExpressionString().
* Add BPackageResolvableExpression constructor and SetTo() taking an
  expression string.
This commit is contained in:
Ingo Weinhold 2013-11-21 12:51:23 +01:00
parent 23c521cf5e
commit 88706cfaa5
6 changed files with 133 additions and 58 deletions

View File

@ -196,6 +196,10 @@ public:
bool revisionIsOptional,
BPackageVersion& _version,
ParseErrorListener* listener = NULL);
static status_t ParseResolvableExpressionString(
const BString& string,
BPackageResolvableExpression& _expression,
ParseErrorListener* listener = NULL);
public:
static const char* const kElementNames[];

View File

@ -45,12 +45,12 @@ public:
BPackageResolvableExpression(
const BPackageResolvableExpressionData& data
);
explicit BPackageResolvableExpression(
const BString& expressionString);
BPackageResolvableExpression(
const BString& name,
BPackageResolvableOperator _op
= B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT,
const BPackageVersion& version
= BPackageVersion());
BPackageResolvableOperator _operator,
const BPackageVersion& version);
status_t InitCheck() const;
@ -60,11 +60,10 @@ public:
BString ToString() const;
status_t SetTo(const BString& expressionString);
void SetTo(const BString& name,
BPackageResolvableOperator _op
= B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT,
const BPackageVersion& version
= BPackageVersion());
BPackageResolvableOperator _operator,
const BPackageVersion& version);
void Clear();
bool Matches(const BPackageVersion& version,

View File

@ -1112,6 +1112,14 @@ BPackageInfo::ParseVersionString(const BString& string, bool revisionIsOptional,
}
/*static*/ status_t
BPackageInfo::ParseResolvableExpressionString(const BString& string,
BPackageResolvableExpression& _expression, ParseErrorListener* listener)
{
return Parser(listener).ParseResolvableExpression(string, _expression);
}
status_t
BPackageInfo::_ReadFromPackageFile(const PackageFileLocation& fileLocation)
{

View File

@ -103,6 +103,31 @@ BPackageInfo::Parser::ParseVersion(const BString& versionString,
}
status_t
BPackageInfo::Parser::ParseResolvableExpression(const BString& expressionString,
BPackageResolvableExpression& _expression)
{
fPos = expressionString.String();
try {
Token token(TOKEN_STRING, fPos, expressionString.Length());
_ParseResolvableExpression(_NextToken(), _expression, NULL);
} catch (const ParseError& error) {
if (fListener != NULL) {
int32 offset = error.pos - expressionString.String();
fListener->OnError(error.message, 1, offset);
}
return B_BAD_DATA;
} catch (const std::bad_alloc& e) {
if (fListener != NULL)
fListener->OnError("out of memory", 0, 0);
return B_NO_MEMORY;
}
return B_OK;
}
BPackageInfo::Parser::Token
BPackageInfo::Parser::_NextToken()
{
@ -399,6 +424,61 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
}
void
BPackageInfo::Parser::_ParseResolvableExpression(const Token& token,
BPackageResolvableExpression& _value, BString* _basePackage)
{
if (token.type != TOKEN_STRING) {
throw ParseError("expected word (a resolvable name)",
token.pos);
}
int32 errorPos;
if (!_IsValidResolvableName(token.text, &errorPos)) {
throw ParseError("invalid character in resolvable name",
token.pos + errorPos);
}
BPackageVersion version;
Token op = _NextToken();
BPackageResolvableOperator resolvableOperator;
if (op.type == TOKEN_OPERATOR_LESS
|| op.type == TOKEN_OPERATOR_LESS_EQUAL
|| op.type == TOKEN_OPERATOR_EQUAL
|| op.type == TOKEN_OPERATOR_NOT_EQUAL
|| op.type == TOKEN_OPERATOR_GREATER_EQUAL
|| op.type == TOKEN_OPERATOR_GREATER) {
_ParseVersionValue(&version, true);
if (_basePackage != NULL) {
Token base = _NextToken();
if (base.type == TOKEN_STRING && base.text == "base") {
if (!_basePackage->IsEmpty()) {
throw ParseError("multiple packages marked as base package",
token.pos);
}
*_basePackage = token.text;
} else
_RewindTo(base);
}
resolvableOperator = (BPackageResolvableOperator)
(op.type - TOKEN_OPERATOR_LESS);
} else if (op.type == TOKEN_ITEM_SEPARATOR
|| op.type == TOKEN_CLOSE_BRACE || op.type == TOKEN_EOF) {
_RewindTo(op);
resolvableOperator = B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT;
} else {
throw ParseError(
"expected '<', '<=', '==', '!=', '>=', '>', comma or '}'",
op.pos);
}
_value.SetTo(token.text, resolvableOperator, version);
}
void
BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
bool allowSingleNonListElement)
@ -587,56 +667,9 @@ BPackageInfo::Parser::_ParseResolvableExprList(
virtual void operator()(const Token& token)
{
if (token.type != TOKEN_STRING) {
throw ParseError("expected word (a resolvable name)",
token.pos);
}
int32 errorPos;
if (!_IsValidResolvableName(token.text, &errorPos)) {
throw ParseError("invalid character in resolvable name",
token.pos + errorPos);
}
BPackageVersion version;
Token op = parser._NextToken();
BPackageResolvableOperator resolvableOperator;
if (op.type == TOKEN_OPERATOR_LESS
|| op.type == TOKEN_OPERATOR_LESS_EQUAL
|| op.type == TOKEN_OPERATOR_EQUAL
|| op.type == TOKEN_OPERATOR_NOT_EQUAL
|| op.type == TOKEN_OPERATOR_GREATER_EQUAL
|| op.type == TOKEN_OPERATOR_GREATER) {
parser._ParseVersionValue(&version, true);
if (basePackage != NULL) {
Token base = parser._NextToken();
if (base.type == TOKEN_STRING && base.text == "base") {
if (!basePackage->IsEmpty()) {
throw ParseError(
"multiple packages marked as base package",
token.pos);
}
*basePackage = token.text;
} else
parser._RewindTo(base);
}
resolvableOperator = (BPackageResolvableOperator)
(op.type - TOKEN_OPERATOR_LESS);
} else if (op.type == TOKEN_ITEM_SEPARATOR
|| op.type == TOKEN_CLOSE_BRACE) {
parser._RewindTo(op);
resolvableOperator = B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT;
} else {
throw ParseError(
"expected '<', '<=', '==', '!=', '>=', '>', comma or '}'",
op.pos);
}
value->AddItem(new BPackageResolvableExpression(token.text,
resolvableOperator, version));
BPackageResolvableExpression expression;
parser._ParseResolvableExpression(token, expression, basePackage);
value->AddItem(new BPackageResolvableExpression(expression));
}
} resolvableExpressionParser(*this, value, _basePackage);

View File

@ -26,6 +26,9 @@ public:
status_t ParseVersion(const BString& versionString,
bool revisionIsOptional,
BPackageVersion& _version);
status_t ParseResolvableExpression(
const BString& expressionString,
BPackageResolvableExpression& _expression);
private:
struct ParseError;
@ -63,6 +66,10 @@ private:
static void _ParseVersionValue(Token& word,
BPackageVersion* value,
bool revisionIsOptional);
void _ParseResolvableExpression(
const Token& token,
BPackageResolvableExpression& _value,
BString* _basePackage);
void _ParseList(ListElementParser& elementParser,
bool allowSingleNonListElement);
void _ParseStringList(BStringList* value,

View File

@ -7,6 +7,7 @@
#include <package/PackageResolvableExpression.h>
#include <package/hpkg/PackageInfoAttributeValue.h>
#include <package/PackageInfo.h>
#include <package/PackageResolvable.h>
@ -54,6 +55,17 @@ BPackageResolvableExpression::BPackageResolvableExpression(const BString& name,
}
BPackageResolvableExpression::BPackageResolvableExpression(
const BString& expressionString)
:
fName(),
fOperator(B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT),
fVersion()
{
SetTo(expressionString);
}
status_t
BPackageResolvableExpression::InitCheck() const
{
@ -102,6 +114,18 @@ BPackageResolvableExpression::ToString() const
}
status_t
BPackageResolvableExpression::SetTo(const BString& expressionString)
{
fName.Truncate(0);
fOperator = B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT;
fVersion.Clear();
return BPackageInfo::ParseResolvableExpressionString(expressionString,
*this);
}
void
BPackageResolvableExpression::SetTo(const BString& name,
BPackageResolvableOperator _operator, const BPackageVersion& version)