New string helper function: property path matching
Match property path strings against template strings containing wild card characters.
This commit is contained in:
parent
9223f30f08
commit
60d1c87cef
@ -754,6 +754,81 @@ bool to_bool(const std::string& s)
|
||||
return false;
|
||||
}
|
||||
|
||||
enum PropMatchState
|
||||
{
|
||||
MATCH_LITERAL = 0,
|
||||
MATCH_WILD_INDEX,
|
||||
MATCH_WILD_NAME
|
||||
};
|
||||
|
||||
bool matchPropPathToTemplate(const std::string& path, const std::string& templatePath)
|
||||
{
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* pathPtr = path.c_str();
|
||||
const char* tPtr = templatePath.c_str();
|
||||
PropMatchState state = MATCH_LITERAL;
|
||||
|
||||
while (true) {
|
||||
bool advanceInTemplate = true;
|
||||
const char p = *pathPtr;
|
||||
if (p == 0) {
|
||||
// ran out of chars in the path. If we are matching a trailing
|
||||
// wildcard, this is a match, otherwise it's a fail
|
||||
if (state == MATCH_WILD_NAME) {
|
||||
// check this is the last * in the template string
|
||||
if (*(tPtr + 1) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case MATCH_LITERAL:
|
||||
if (*tPtr != p) {
|
||||
// literal mismatch
|
||||
return false;
|
||||
}
|
||||
++pathPtr;
|
||||
break;
|
||||
case MATCH_WILD_NAME:
|
||||
if ((p == '-') || isalpha(p)) {
|
||||
advanceInTemplate = false;
|
||||
++pathPtr;
|
||||
} else {
|
||||
// something else, we will advance in the template
|
||||
}
|
||||
break;
|
||||
case MATCH_WILD_INDEX:
|
||||
if (isdigit(p)) {
|
||||
advanceInTemplate = false;
|
||||
++pathPtr;
|
||||
} else {
|
||||
// something else, we will advance in the template
|
||||
}
|
||||
break;
|
||||
} // of state switch
|
||||
|
||||
if (advanceInTemplate) {
|
||||
const char nextTemplate = *(++tPtr);
|
||||
if (nextTemplate == 0) {
|
||||
// end of template, successful match
|
||||
return true;
|
||||
} else if (nextTemplate == '*') {
|
||||
state = (*(tPtr - 1) == '[') ? MATCH_WILD_INDEX : MATCH_WILD_NAME;
|
||||
} else {
|
||||
state = MATCH_LITERAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unreachable
|
||||
}
|
||||
|
||||
} // end namespace strutils
|
||||
|
||||
} // end namespace simgear
|
||||
|
@ -265,6 +265,20 @@ namespace simgear {
|
||||
*/
|
||||
std::string error_string(int errnum);
|
||||
|
||||
|
||||
/**
|
||||
* Match a property path, obtained from prop->getPath(), against a
|
||||
* template string. Templates are allowed to contain widlcards denoted by
|
||||
* an asterix in certain places - at the end of names, or inside indices.
|
||||
* Note that paths returned by getPath() always include an index on every
|
||||
* path component, so template strings should be structured accordingly.
|
||||
*
|
||||
* Examples:
|
||||
* /foo[*]/bar* will match /foo/barber, /foo[2]/bargain
|
||||
* /views[0]/view[*]/f* will match /views[0]/view[99]/foo,
|
||||
* /views[0]/view[4]/fig, /views[0]/view[1000]/flight
|
||||
*/
|
||||
bool matchPropPathToTemplate(const std::string& path, const std::string& templatePath);
|
||||
} // end namespace strutils
|
||||
} // end namespace simgear
|
||||
|
||||
|
@ -175,6 +175,32 @@ void test_md5_hex()
|
||||
SG_CHECK_EQUAL(strutils::md5("test"), "098f6bcd4621d373cade4e832627b4f6");
|
||||
}
|
||||
|
||||
void test_propPathMatch()
|
||||
{
|
||||
const char* testTemplate1 = "/sim[*]/views[*]/render";
|
||||
SG_VERIFY(strutils::matchPropPathToTemplate("/sim[0]/views[50]/render-buildings[0]", testTemplate1));
|
||||
SG_VERIFY(strutils::matchPropPathToTemplate("/sim[1]/views[0]/rendering-enabled", testTemplate1));
|
||||
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/sim[0]/views[50]/something-else", testTemplate1));
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/sim[0]/gui[0]/wibble", testTemplate1));
|
||||
|
||||
// test explicit index matching
|
||||
const char* testTemplate2 = "/view[5]/*";
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/view[2]/render-buildings[0]", testTemplate2));
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/sim[1]/foo", testTemplate2));
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/view[50]/foo", testTemplate2));
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/view[55]/foo", testTemplate2));
|
||||
|
||||
SG_VERIFY(strutils::matchPropPathToTemplate("/view[5]/foo", testTemplate2));
|
||||
SG_VERIFY(strutils::matchPropPathToTemplate("/view[5]/child[3]/bar", testTemplate2));
|
||||
|
||||
|
||||
const char* testTemplate3 = "/*[*]/fdm*[*]/aero*";
|
||||
|
||||
SG_VERIFY(strutils::matchPropPathToTemplate("/position[2]/fdm-jsb[0]/aerodynamic", testTemplate3));
|
||||
SG_VERIFY(!strutils::matchPropPathToTemplate("/position[2]/foo[0]/aerodynamic", testTemplate3));
|
||||
}
|
||||
|
||||
void test_error_string()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
@ -210,6 +236,7 @@ int main(int argc, char* argv[])
|
||||
test_compare_versions();
|
||||
test_md5_hex();
|
||||
test_error_string();
|
||||
test_propPathMatch();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user