git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26687 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-07-30 16:29:57 +00:00
parent 37de5a0d83
commit f5d5ca18f6
+117 -84
View File
@@ -88,8 +88,9 @@ class Term {
void SetParent(Term* parent) { fParent = parent; }
Term* Parent() const { return fParent; }
virtual status_t Match(Inode *inode,const char *attribute = NULL,int32 type = 0,
const uint8 *key = NULL,size_t size = 0) = 0;
virtual status_t Match(Inode* inode, const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0) = 0;
virtual void Complement() = 0;
virtual void CalculateScore(Index& index) = 0;
@@ -117,7 +118,7 @@ class Term {
class Equation : public Term {
public:
Equation(char **expr);
Equation(char** expression);
virtual ~Equation();
virtual status_t InitCheck();
@@ -125,12 +126,13 @@ class Equation : public Term {
status_t ParseQuotedString(char** _start, char** _end);
char* CopyString(char* start, char* end);
virtual status_t Match(Inode *inode, const char *attribute = NULL, int32 type = 0,
const uint8 *key = NULL, size_t size = 0);
virtual status_t Match(Inode* inode, const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0);
virtual void Complement();
status_t PrepareQuery(Volume *volume, Index &index, TreeIterator **iterator,
bool queryNonIndexed);
status_t PrepareQuery(Volume* volume, Index& index,
TreeIterator** iterator, bool queryNonIndexed);
status_t GetNextMatching(Volume* volume, TreeIterator* iterator,
struct dirent* dirent, size_t bufferSize);
@@ -142,8 +144,8 @@ class Equation : public Term {
#endif
private:
Equation(const Equation &);
Equation &operator=(const Equation &);
Equation(const Equation& other);
Equation& operator=(const Equation& other);
// no implementation
status_t ConvertValue(type_code type);
@@ -165,14 +167,15 @@ class Equation : public Term {
class Operator : public Term {
public:
Operator(Term *,int8,Term *);
Operator(Term* left, int8 op, Term* right);
virtual ~Operator();
Term* Left() const { return fLeft; }
Term* Right() const { return fRight; }
virtual status_t Match(Inode *inode, const char *attribute = NULL, int32 type = 0,
const uint8 *key = NULL, size_t size = 0);
virtual status_t Match(Inode* inode, const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0);
virtual void Complement();
virtual void CalculateScore(Index& index);
@@ -180,21 +183,21 @@ class Operator : public Term {
virtual status_t InitCheck();
//Term *Copy() const;
#ifdef DEBUG
virtual void PrintToStream();
#endif
private:
Operator(const Operator &);
Operator &operator=(const Operator &);
Operator(const Operator& other);
Operator& operator=(const Operator& other);
// no implementation
Term *fLeft,*fRight;
Term* fLeft;
Term* fRight;
};
//---------------------------------
// #pragma mark -
void
@@ -210,7 +213,8 @@ void
skipWhitespaceReverse(char** expr, char* stop)
{
char* string = *expr;
while (string > stop && (*string == ' ' || *string == '\t')) string--;
while (string > stop && (*string == ' ' || *string == '\t'))
string--;
*expr = string;
}
@@ -227,8 +231,12 @@ utf8ToUnicode(char **string)
switch (bytes[0] & 0xf0) {
case 0xc0:
case 0xd0: length = 2; break;
case 0xe0: length = 3; break;
case 0xd0:
length = 2;
break;
case 0xe0:
length = 3;
break;
case 0xf0:
mask = 0x0f;
length = 4;
@@ -308,12 +316,10 @@ isValidPattern(char *pattern)
}
/** Matches the string against the given wildcard pattern.
* Returns either MATCH_OK, or NO_MATCH when everything went fine,
* or values < 0 (see enum at the top of Query.cpp) if an error
* occurs
/*! Matches the string against the given wildcard pattern.
Returns either MATCH_OK, or NO_MATCH when everything went fine, or
values < 0 (see enum at the top of Query.cpp) if an error occurs.
*/
status_t
matchString(char* pattern, char* string)
{
@@ -398,7 +404,8 @@ matchString(char *pattern, char *string)
if (first == c) {
matched = true;
break;
} else if (pattern[0] == '-' && pattern[1] != ']' && pattern[1]) {
} else if (pattern[0] == '-' && pattern[1] != ']'
&& pattern[1]) {
pattern++;
if (pattern[0] == '\\') {
@@ -465,7 +472,8 @@ Equation::Equation(char **expr)
// Since the equation is the integral part of any query, we're just parsing
// the whole thing here.
// The whitespace at the start is already removed in Expression::ParseEquation()
// The whitespace at the start is already removed in
// Expression::ParseEquation()
if (*start == '"' || *start == '\'') {
// string is quoted (start has to be on the beginning of a string)
@@ -475,16 +483,18 @@ Equation::Equation(char **expr)
// set string to a valid start of the equation symbol
string = end + 2;
skipWhitespace(&string);
if (*string != '=' && *string != '<' && *string != '>' && *string != '!') {
if (*string != '=' && *string != '<' && *string != '>'
&& *string != '!') {
*expr = string;
return;
}
} else {
// search the (in)equation for the actual equation symbol (and for other operators
// in case the equation is malformed)
while (*string && *string != '=' && *string != '<' && *string != '>' && *string != '!'
&& *string != '&' && *string != '|')
while (*string && *string != '=' && *string != '<' && *string != '>'
&& *string != '!' && *string != '&' && *string != '|') {
string++;
}
// get the attribute string (and trim whitespace), in case
// the string was not quoted
@@ -496,9 +506,9 @@ Equation::Equation(char **expr)
if (start > end)
return;
// at this point, "start" points to the beginning of the string, "end" points
// to the last character of the string, and "string" points to the first
// character of the equation symbol
// At this point, "start" points to the beginning of the string, "end"
// points to the last character of the string, and "string" points to the
// first character of the equation symbol
// test for the right symbol (as this doesn't need any memory)
switch (*string) {
@@ -506,10 +516,12 @@ Equation::Equation(char **expr)
fOp = OP_EQUAL;
break;
case '>':
fOp = *(string + 1) == '=' ? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN;
fOp = *(string + 1) == '='
? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN;
break;
case '<':
fOp = *(string + 1) == '=' ? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN;
fOp = *(string + 1) == '='
? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN;
break;
case '!':
if (*(string + 1) != '=')
@@ -522,6 +534,7 @@ Equation::Equation(char **expr)
*expr = string;
return;
}
// lets change "start" to point to the first character after the symbol
if (*(string + 1) == '=')
string++;
@@ -583,9 +596,7 @@ Equation::Equation(char **expr)
Equation::~Equation()
{
if (fAttribute != NULL)
free(fAttribute);
if (fString != NULL)
free(fString);
}
@@ -593,9 +604,7 @@ Equation::~Equation()
status_t
Equation::InitCheck()
{
if (fAttribute == NULL
|| fString == NULL
|| fOp == OP_NONE)
if (fAttribute == NULL || fString == NULL || fOp == OP_NONE)
return B_BAD_VALUE;
return B_OK;
@@ -703,16 +712,16 @@ Equation::ConvertValue(type_code type)
}
/** Returns true when the key matches the equation. You have to
* call ConvertValue() before this one.
/*! Returns true when the key matches the equation. You have to
call ConvertValue() before this one.
*/
bool
Equation::CompareTo(const uint8* value, uint16 size)
{
int32 compare;
// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or OP_UNEQUAL
// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
// OP_UNEQUAL
if (fIsPattern) {
// we have already validated the pattern, so we don't check for failing
// here - if something is broken, and matchString() returns an error,
@@ -722,7 +731,8 @@ Equation::CompareTo(const uint8 *value, uint16 size)
// the index is a shifted int64 index, but we have to match
// against an unshifted value (i.e. the last_modified index)
int64 timeValue = *(int64*)value >> INODE_TIME_SHIFT;
compare = compareKeys(fType, &timeValue, sizeof(int64), &fValue.Int64, sizeof(int64));
compare = compareKeys(fType, &timeValue, sizeof(int64), &fValue.Int64,
sizeof(int64));
} else
compare = compareKeys(fType, value, size, Value(), fSize);
@@ -779,12 +789,13 @@ Equation::MatchEmptyString()
}
/** Matches the inode's attribute value with the equation.
* Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went wrong
/*! Matches the inode's attribute value with the equation.
Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
wrong.
*/
status_t
Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8 *key, size_t size)
Equation::Match(Inode* inode, const char* attributeName, int32 type,
const uint8* key, size_t size)
{
// get a pointer to the attribute in question
NodeGetter nodeGetter(inode->GetVolume());
@@ -808,7 +819,7 @@ Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8
recursive_lock_lock(&inode->SmallDataLock());
locked = true;
// if not, check for "fake" attributes, "name", "size", "last_modified",
// if not, check for "fake" attributes ("name", "size", "last_modified")
buffer = (uint8*)inode->Name(nodeGetter.Node());
if (buffer == NULL) {
recursive_lock_unlock(&inode->SmallDataLock());
@@ -838,7 +849,8 @@ Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8
Inode* attribute;
recursive_lock_lock(&inode->SmallDataLock());
small_data *smallData = inode->FindSmallData(nodeGetter.Node(), fAttribute);
small_data* smallData = inode->FindSmallData(nodeGetter.Node(),
fAttribute);
if (smallData != NULL) {
buffer = smallData->Data();
type = smallData->type;
@@ -913,7 +925,8 @@ Equation::CalculateScore(Index &index)
status_t
Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator, bool queryNonIndexed)
Equation::PrepareQuery(Volume* /*volume*/, Index& index,
TreeIterator** iterator, bool queryNonIndexed)
{
status_t status = index.SetTo(fAttribute);
@@ -923,8 +936,8 @@ Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator
type_code type;
// special case for OP_UNEQUAL - it will always operate through the whole index
// but we need the call to the original index to get the correct type
// Special case for OP_UNEQUAL - it will always operate through the whole
// index but we need the call to the original index to get the correct type
if (status < B_OK || fOp == OP_UNEQUAL) {
// Try to get an index that holds all files (name)
// Also sets the default type for all attributes without index
@@ -951,14 +964,14 @@ Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator
if (*iterator == NULL)
return B_NO_MEMORY;
if ((fOp == OP_EQUAL || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL
|| fIsPattern)
if ((fOp == OP_EQUAL || fOp == OP_GREATER_THAN
|| fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern)
&& fHasIndex) {
// set iterator to the exact position
int32 keySize = index.KeySize();
// at this point, fIsPattern is only true if it's a string type, and fOp
// At this point, fIsPattern is only true if it's a string type, and fOp
// is either OP_EQUAL or OP_UNEQUAL
if (fIsPattern) {
// let's see if we can use the beginning of the key for positioning
@@ -977,8 +990,8 @@ Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator
// The empty string is a special case - we normally don't check
// for the trailing null byte, in the case for the empty string
// we do it explicitly, because there can't be keys in the B+tree
// with a length of zero
// we do it explicitly, because there can't be keys in the
// B+tree with a length of zero
if (keySize == 0)
keySize = 1;
} else
@@ -996,7 +1009,8 @@ Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator
if (fOp == OP_EQUAL && !fIsPattern)
return status;
else if (status == B_ENTRY_NOT_FOUND
&& (fIsPattern || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL))
&& (fIsPattern || fOp == OP_GREATER_THAN
|| fOp == OP_GREATER_THAN_OR_EQUAL))
return B_OK;
}
@@ -1024,10 +1038,12 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
// only compare against the index entry when this is the correct
// index for the equation
if (fHasIndex && duplicate < 2 && !CompareTo((uint8 *)&indexValue, keyLength)) {
// They aren't equal? let the operation decide what to do
// Since we always start at the beginning of the index (or the correct
// position), only some needs to be stopped if the entry doesn't fit.
if (fHasIndex && duplicate < 2
&& !CompareTo((uint8*)&indexValue, keyLength)) {
// They aren't equal? Let the operation decide what to do. Since
// we always start at the beginning of the index (or the correct
// position), only some needs to be stopped if the entry doesn't
// fit.
if (fOp == OP_LESS_THAN
|| fOp == OP_LESS_THAN_OR_EQUAL
|| (fOp == OP_EQUAL && !fIsPattern))
@@ -1042,12 +1058,13 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
Inode* inode;
if ((status = vnode.Get(&inode)) != B_OK) {
REPORT_ERROR(status);
FATAL(("could not get inode %Ld in index \"%s\"!\n", offset, fAttribute));
FATAL(("could not get inode %Ld in index \"%s\"!\n", offset,
fAttribute));
// try with next
continue;
}
// ToDo: check user permissions here - but which one?!
// TODO: check user permissions here - but which one?!
// we could filter out all those where we don't have
// read access... (we should check for every parent
// directory if the X_OK is allowed)
@@ -1077,7 +1094,8 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
other = parent->Left();
if (other == NULL) {
FATAL(("&&-operator has only one child... (parent = %p)\n", parent));
FATAL(("&&-operator has only one child... (parent = %p)\n",
parent));
break;
}
status = other->Match(inode);
@@ -1095,8 +1113,10 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
dirent->d_pdev = volume->ID();
dirent->d_pino = volume->ToVnode(inode->Parent());
if (inode->GetName(dirent->d_name) < B_OK)
FATAL(("inode %Ld in query has no name!\n", inode->BlockNumber()));
if (inode->GetName(dirent->d_name) < B_OK) {
FATAL(("inode %Ld in query has no name!\n",
inode->BlockNumber()));
}
dirent->d_reclen = sizeof(struct dirent) + strlen(dirent->d_name);
}
@@ -1131,7 +1151,8 @@ Operator::~Operator()
status_t
Operator::Match(Inode *inode, const char *attribute, int32 type, const uint8 *key, size_t size)
Operator::Match(Inode* inode, const char* attribute, int32 type,
const uint8* key, size_t size)
{
if (fOp == OP_AND) {
status_t status = fLeft->Match(inode, attribute, type, key, size);
@@ -1219,7 +1240,8 @@ Operator::Copy() const
return term;
}
Term *left = NULL, *right = NULL;
Term* left = NULL;
Term* right = NULL;
if (fLeft != NULL && (left = fLeft->Copy()) == NULL)
return NULL;
@@ -1242,6 +1264,7 @@ Operator::Copy() const
// #pragma mark -
#ifdef DEBUG
void
Operator::PrintToStream()
{
@@ -1279,7 +1302,7 @@ Equation::PrintToStream()
D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString));
}
#endif /* DEBUG */
#endif // DEBUG
// #pragma mark -
@@ -1370,7 +1393,8 @@ Expression::ParseAnd(char **expr)
Term* right = ParseAnd(expr);
Term* newParent = NULL;
if (right == NULL || (newParent = new Operator(left, OP_AND, right)) == NULL) {
if (right == NULL
|| (newParent = new Operator(left, OP_AND, right)) == NULL) {
delete left;
delete right;
@@ -1394,7 +1418,8 @@ Expression::ParseOr(char **expr)
Term* right = ParseAnd(expr);
Term* newParent = NULL;
if (right == NULL || (newParent = new Operator(left, OP_OR, right)) == NULL) {
if (right == NULL
|| (newParent = new Operator(left, OP_OR, right)) == NULL) {
delete left;
delete right;
@@ -1492,13 +1517,15 @@ Query::Rewind()
stack.Push(op->Left());
stack.Push(op->Right());
} else {
// For OP_AND, we can use the scoring system to decide which path to add
// For OP_AND, we can use the scoring system to decide which
// path to add
if (op->Right()->Score() > op->Left()->Score())
stack.Push(op->Right());
else
stack.Push(op->Left());
}
} else if (term->Op() == OP_EQUATION || fStack.Push((Equation *)term) < B_OK)
} else if (term->Op() == OP_EQUATION
|| fStack.Push((Equation*)term) < B_OK)
FATAL(("Unknown term on stack or stack error"));
}
@@ -1522,7 +1549,8 @@ Query::GetNextEntry(struct dirent *dirent, size_t size)
if (fCurrent == NULL)
RETURN_ERROR(B_ERROR);
status_t status = fCurrent->GetNextMatching(fVolume, fIterator, dirent, size);
status_t status = fCurrent->GetNextMatching(fVolume, fIterator, dirent,
size);
if (status < B_OK) {
delete fIterator;
fIterator = NULL;
@@ -1551,16 +1579,19 @@ Query::SetLiveMode(port_id port, int32 token)
void
Query::LiveUpdate(Inode *inode, const char *attribute, int32 type, const uint8 *oldKey,
size_t oldLength, const uint8 *newKey, size_t newLength)
Query::LiveUpdate(Inode* inode, const char* attribute, int32 type,
const uint8* oldKey, size_t oldLength, const uint8* newKey,
size_t newLength)
{
if (fPort < 0 || fExpression == NULL || attribute == NULL)
return;
// ToDo: check if the attribute is part of the query at all...
// TODO: check if the attribute is part of the query at all...
status_t oldStatus = fExpression->Root()->Match(inode, attribute, type, oldKey, oldLength);
status_t newStatus = fExpression->Root()->Match(inode, attribute, type, newKey, newLength);
status_t oldStatus = fExpression->Root()->Match(inode, attribute, type,
oldKey, oldLength);
status_t newStatus = fExpression->Root()->Match(inode, attribute, type,
newKey, newLength);
const char* name = NULL;
bool entryCreated;
@@ -1575,12 +1606,14 @@ Query::LiveUpdate(Inode *inode, const char *attribute, int32 type, const uint8 *
// entry got removed
entryCreated = false;
} else {
// the entry stays in the query - only notify in case the name of the inode was changed
// The entry stays in the query - only notify in case the name of the
// inode was changed
if (oldKey == NULL || strcmp(attribute, "name"))
return;
notify_query_entry_removed(fPort, fToken, fVolume->ID(),
fVolume->ToVnode(inode->Parent()), (const char *)oldKey, inode->ID());
fVolume->ToVnode(inode->Parent()), (const char*)oldKey,
inode->ID());
name = (const char*)newKey;
entryCreated = true;
}