+ Updated all the parsing code to use std::strings everywhere

instead of const char*'s to allow for rules with NULL characters
  embedded in them.
+ Updated Rule::Sniff() to actually return a useful value


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@662 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Tyler Dauwalder
2002-08-09 10:30:38 +00:00
parent 10cde11f08
commit fe70cd16af
5 changed files with 493 additions and 486 deletions
+14 -14
View File
@@ -43,23 +43,24 @@ status_t parse(const char *rule, Rule *result, BString *parseError = NULL);
*/ */
class CharStream { class CharStream {
public: public:
CharStream(const char *string = NULL); CharStream(const std::string &string);
CharStream();
~CharStream(); ~CharStream();
status_t SetTo(const char *string); status_t SetTo(const std::string &string);
void Unset(); void Unset();
status_t InitCheck() const; status_t InitCheck() const;
bool IsEmpty() const; bool IsEmpty() const;
ssize_t Pos() const; ssize_t Pos() const;
const char *String() const; const std::string& String() const;
char Get(); char Get();
void Unget(); void Unget();
private: private:
char *fString; std::string fString;
ssize_t fPos; ssize_t fPos;
ssize_t fLen; // ssize_t fLen;
status_t fCStatus; status_t fCStatus;
CharStream(const CharStream &ref); CharStream(const CharStream &ref);
@@ -95,9 +96,8 @@ const char* tokenTypeToString(TokenType type);
class Token { class Token {
public: public:
Token(TokenType type = EmptyToken, const ssize_t pos = -1); Token(TokenType type = EmptyToken, const ssize_t pos = -1);
virtual ~Token();
TokenType Type() const; TokenType Type() const;
virtual const char* String() const; virtual const std::string& String() const;
virtual int32 Int() const; virtual int32 Int() const;
virtual double Float() const; virtual double Float() const;
ssize_t Pos() const; ssize_t Pos() const;
@@ -114,11 +114,10 @@ protected:
*/ */
class StringToken : public Token { class StringToken : public Token {
public: public:
StringToken(const char *string, const ssize_t pos); StringToken(const std::string &str, const ssize_t pos);
virtual ~StringToken(); virtual const std::string& String() const;
virtual const char* String() const;
protected: protected:
char *fString; std::string fString;
}; };
//! Integer token class //! Integer token class
@@ -157,10 +156,11 @@ protected:
*/ */
class TokenStream { class TokenStream {
public: public:
TokenStream(const char *string = NULL); TokenStream(const std::string &string);
TokenStream();
~TokenStream(); ~TokenStream();
status_t SetTo(const char *string); status_t SetTo(const std::string &string);
void Unset(); void Unset();
status_t InitCheck() const; status_t InitCheck() const;
@@ -177,7 +177,7 @@ public:
private: private:
void AddToken(TokenType type, ssize_t pos); void AddToken(TokenType type, ssize_t pos);
void AddString(const char *str, ssize_t pos); void AddString(const std::string &str, ssize_t pos);
void AddInt(const char *str, ssize_t pos); void AddInt(const char *str, ssize_t pos);
void AddFloat(const char *str, ssize_t pos); void AddFloat(const char *str, ssize_t pos);
+3 -2
View File
@@ -23,7 +23,8 @@ class Err;
/*! The byte string and mask (if supplied) must be of the same length. */ /*! The byte string and mask (if supplied) must be of the same length. */
class Pattern { class Pattern {
public: public:
Pattern(const char *string, const char *mask = NULL); Pattern(const std::string &string, const std::string &mask);
Pattern(const std::string &string);
~Pattern(); ~Pattern();
status_t InitCheck() const; status_t InitCheck() const;
@@ -31,7 +32,7 @@ public:
bool Sniff(Range range, BPositionIO *data) const; bool Sniff(Range range, BPositionIO *data) const;
status_t SetTo(const char *string, const char *mask = NULL); status_t SetTo(const std::string &string, const std::string &mask);
private: private:
bool Sniff(off_t start, off_t size, BPositionIO *data) const; bool Sniff(off_t start, off_t size, BPositionIO *data) const;
+426 -433
View File
@@ -65,13 +65,19 @@ Sniffer::parse(const char *rule, Rule *result, BString *parseError) {
// CharStream // CharStream
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
CharStream::CharStream(const char *string) CharStream::CharStream(const std::string &string)
: fString(NULL) : fString(string)
, fPos(0)
// , fLen(-1)
, fCStatus(B_OK)
{
}
CharStream::CharStream()
: fString("")
, fPos(0) , fPos(0)
, fLen(-1)
, fCStatus(B_NO_INIT) , fCStatus(B_NO_INIT)
{ {
SetTo(string);
} }
CharStream::~CharStream() { CharStream::~CharStream() {
@@ -79,27 +85,18 @@ CharStream::~CharStream() {
} }
status_t status_t
CharStream::SetTo(const char *string) { CharStream::SetTo(const std::string &string) {
Unset(); fString = string;
if (string) { fPos = 0;
fString = new(nothrow) char[strlen(string)+1]; fCStatus = B_OK;
if (!fString)
fCStatus = B_NO_MEMORY;
else {
strcpy(fString, string);
fLen = strlen(fString);
fCStatus = B_OK;
}
}
return fCStatus; return fCStatus;
} }
void void
CharStream::Unset() { CharStream::Unset() {
delete fString; fString = "";
fCStatus = B_NO_INIT;
fPos = 0; fPos = 0;
fLen = -1; fCStatus = B_NO_INIT;
} }
status_t status_t
@@ -109,7 +106,7 @@ CharStream::InitCheck() const {
bool bool
CharStream::IsEmpty() const { CharStream::IsEmpty() const {
return fPos >= fLen; return fPos >= fString.length();
} }
ssize_t ssize_t
@@ -117,7 +114,7 @@ CharStream::Pos() const {
return fPos; return fPos;
} }
const char* const std::string&
CharStream::String() const { CharStream::String() const {
return fString; return fString;
} }
@@ -126,7 +123,7 @@ char
CharStream::Get() { CharStream::Get() {
if (fCStatus != B_OK) if (fCStatus != B_OK)
throw new Err("Sniffer parser error: CharStream::Get() called on uninitialized CharStream object", -1); throw new Err("Sniffer parser error: CharStream::Get() called on uninitialized CharStream object", -1);
if (fPos < fLen) if (fPos < fString.length())
return fString[fPos++]; return fString[fPos++];
else { else {
fPos++; // Increment fPos to keep Unget()s consistent fPos++; // Increment fPos to keep Unget()s consistent
@@ -156,15 +153,12 @@ Token::Token(TokenType type, const ssize_t pos)
// cout << "New Token, fType == " << tokenTypeToString(fType) << endl; // cout << "New Token, fType == " << tokenTypeToString(fType) << endl;
} }
Token::~Token() {
}
TokenType TokenType
Token::Type() const { Token::Type() const {
return fType; return fType;
} }
const char* const std::string&
Token::String() const { Token::String() const {
throw new Err("Sniffer scanner error: Token::String() called on non-string token", fPos); throw new Err("Sniffer scanner error: Token::String() called on non-string token", fPos);
} }
@@ -194,6 +188,9 @@ Token::operator==(Token &ref) const {
// printf(" str2 == '%s'\n", ref.String()); // printf(" str2 == '%s'\n", ref.String());
// printf(" strcmp() == %d\n", strcmp(String(), ref.String())); // printf(" strcmp() == %d\n", strcmp(String(), ref.String()));
{ {
return String() == ref.String();
/*
// strcmp() seems to choke on certain, non-normal ASCII chars // strcmp() seems to choke on certain, non-normal ASCII chars
// (i.e. chars outside the usual alphabets, but still valid // (i.e. chars outside the usual alphabets, but still valid
// as far as ASCII is concerned), so we'll just compare the // as far as ASCII is concerned), so we'll just compare the
@@ -212,6 +209,7 @@ Token::operator==(Token &ref) const {
} }
} }
return true; return true;
*/
} }
// return strcmp(String(), ref.String()) == 0; // return strcmp(String(), ref.String()) == 0;
@@ -232,22 +230,13 @@ Token::operator==(Token &ref) const {
// StringToken // StringToken
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
StringToken::StringToken(const char *string, const ssize_t pos) StringToken::StringToken(const std::string &str, const ssize_t pos)
: Token(CharacterString, pos) : Token(CharacterString, pos)
, fString(NULL) , fString(str)
{ {
if (string) {
fString = new(nothrow) char[strlen(string)+1];
if (fString)
strcpy(fString, string);
}
} }
StringToken::~StringToken() { const std::string&
delete fString;
}
const char*
StringToken::String() const { StringToken::String() const {
return fString; return fString;
} }
@@ -291,7 +280,7 @@ FloatToken::Float() const {
// TokenStream // TokenStream
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
TokenStream::TokenStream(const char *string = NULL) TokenStream::TokenStream(const std::string &string)
: fCStatus(B_NO_INIT) : fCStatus(B_NO_INIT)
, fPos(-1) , fPos(-1)
, fStrLen(-1) , fStrLen(-1)
@@ -299,435 +288,439 @@ TokenStream::TokenStream(const char *string = NULL)
SetTo(string); SetTo(string);
} }
TokenStream::TokenStream()
: fCStatus(B_NO_INIT)
, fPos(-1)
, fStrLen(-1)
{
}
TokenStream::~TokenStream() { TokenStream::~TokenStream() {
Unset(); Unset();
} }
status_t status_t
TokenStream::SetTo(const char *string) { TokenStream::SetTo(const std::string &string) {
int q = 0;
Unset(); Unset();
if (string) { fStrLen = string.length();
fStrLen = strlen(string); CharStream stream(string);
CharStream stream(string); if (stream.InitCheck() != B_OK)
if (stream.InitCheck() != B_OK) throw new Err("Sniffer scanner error: Unable to intialize character stream", -1);
throw new Err("Sniffer scanner error: Unable to intialize character stream", -1);
typedef enum TokenStreamScannerState { typedef enum TokenStreamScannerState {
tsssStart, tsssStart,
tsssOneSingle, tsssOneSingle,
tsssOneDouble, tsssOneDouble,
tsssOneZero, tsssOneZero,
tsssZeroX, tsssZeroX,
tsssOneHex, tsssOneHex,
tsssTwoHex, tsssTwoHex,
tsssHexStringEnd, tsssHexStringEnd,
tsssIntOrFloat, tsssIntOrFloat,
tsssFloat, tsssFloat,
tsssLonelyDecimalPoint, tsssLonelyDecimalPoint,
tsssLonelyMinusOrPlus, tsssLonelyMinusOrPlus,
tsssLonelyFloatExtension, tsssLonelyFloatExtension,
tsssLonelyFloatExtensionWithSign, tsssLonelyFloatExtensionWithSign,
tsssExtendedFloat, tsssExtendedFloat,
tsssUnquoted, tsssUnquoted,
tsssEscape, tsssEscape,
tsssEscapeX, tsssEscapeX,
tsssEscapeOneOctal, tsssEscapeOneOctal,
tsssEscapeTwoOctal, tsssEscapeTwoOctal,
tsssEscapeOneHex, tsssEscapeOneHex,
tsssEscapeTwoHex tsssEscapeTwoHex
}; };
TokenStreamScannerState state = tsssStart; TokenStreamScannerState state = tsssStart;
TokenStreamScannerState escapedState; TokenStreamScannerState escapedState;
// Used to remember which state to return to from an escape sequence // Used to remember which state to return to from an escape sequence
std::string charStr; // Used to build up character strings std::string charStr; // Used to build up character strings
char lastChar; // For two char lookahead char lastChar; // For two char lookahead
char lastLastChar; // For three char lookahead char lastLastChar; // For three char lookahead (have I mentioned I hate octal?)
bool keepLooping = true; bool keepLooping = true;
ssize_t startPos; ssize_t startPos;
while (keepLooping) { while (keepLooping) {
ssize_t pos = stream.Pos(); ssize_t pos = stream.Pos();
char ch = stream.Get(); char ch = stream.Get();
switch (state) { switch (state) {
case tsssStart: case tsssStart:
startPos = pos; startPos = pos;
switch (ch) { switch (ch) {
case 0x3: // End-Of-Text case 0x3: // End-Of-Text
if (stream.IsEmpty()) if (stream.IsEmpty())
keepLooping = false; keepLooping = false;
else else
throw new Err(std::string("Sniffer pattern error: invalid character '") + ch + "'", pos);
break;
case '\t':
case '\n':
case ' ':
// Whitespace, so ignore it.
break;
case '"':
charStr = "";
state = tsssOneDouble;
break;
case '\'':
charStr = "";
state = tsssOneSingle;
break;
case '+':
case '-':
charStr = ch;
state = tsssLonelyMinusOrPlus;
break;
case '.':
charStr = ch;
state = tsssLonelyDecimalPoint;
break;
case '0':
charStr = ch;
state = tsssOneZero;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
charStr = ch;
state = tsssIntOrFloat;
break;
case '&': AddToken(Ampersand, pos); break;
case '(': AddToken(LeftParen, pos); break;
case ')': AddToken(RightParen, pos); break;
case ':': AddToken(Colon, pos); break;
case '[': AddToken(LeftBracket, pos); break;
case '\\':
charStr = ""; // Clear our string
state = tsssEscape;
escapedState = tsssUnquoted; // Unquoted strings begin with an escaped character
break;
case ']': AddToken(RightBracket, pos); break;
case '|': AddToken(Divider, pos); break;
default:
throw new Err(std::string("Sniffer pattern error: invalid character '") + ch + "'", pos); throw new Err(std::string("Sniffer pattern error: invalid character '") + ch + "'", pos);
} break;
break;
case tsssOneSingle: case '\t':
switch (ch) { case '\n':
case '\\': case ' ':
escapedState = state; // Save our state // Whitespace, so ignore it.
state = tsssEscape; // Handle the escape sequence break;
break;
case '\'':
AddString(charStr.c_str(), startPos);
state = tsssStart;
break;
case 0x3:
if (stream.IsEmpty())
throw new Err(std::string("Sniffer pattern error: unterminated single-quoted string"), pos);
else
charStr += ch;
break;
default:
charStr += ch;
break;
}
break;
case tsssOneDouble: case '"':
switch (ch) { charStr = "";
case '\\': state = tsssOneDouble;
escapedState = state; // Save our state break;
state = tsssEscape; // Handle the escape sequence
break;
case '"':
AddString(charStr.c_str(), startPos);
state = tsssStart;
break;
case 0x3:
if (stream.IsEmpty())
throw new Err(std::string("Sniffer pattern error: unterminated double-quoted string"), pos);
else
charStr += ch;
break;
default:
charStr += ch;
break;
}
break;
case tsssOneZero: case '\'':
if (ch == 'x') { charStr = "";
charStr = ""; // Reinit, since we actually have a hex string state = tsssOneSingle;
state = tsssZeroX; break;
} else if ('0' <= ch && ch <= '9') {
charStr += ch;
state = tsssIntOrFloat;
} else if (ch == '.') {
charStr += ch;
state = tsssFloat;
} else if (ch == 'e' || ch == 'E') {
charStr += ch;
state = tsssLonelyFloatExtension;
} else {
// Terminate the number
AddInt(charStr.c_str(), startPos);
// Push the last char back on and try again case '+':
stream.Unget(); case '-':
state = tsssStart; charStr = ch;
} state = tsssLonelyMinusOrPlus;
break; break;
case tsssZeroX: case '.':
if (isHexChar(ch)) { charStr = ch;
lastChar = ch;
state = tsssOneHex;
} else
throw new Err(std::string("Sniffer pattern error: incomplete hex code"), pos);
break;
case tsssOneHex:
if (isHexChar(ch)) {
try {
charStr += hexToChar(lastChar, ch);
} catch (Err *err) {
if (err)
err->SetPos(pos);
throw err;
}
state = tsssTwoHex;
} else
throw new Err(std::string("Sniffer pattern error: bad hex literal"), pos); // Same as R5
break;
case tsssTwoHex:
if (isHexChar(ch)) {
lastChar = ch;
state = tsssOneHex;
} else {
AddString(charStr.c_str(), startPos);
stream.Unget(); // So punctuation gets handled properly
state = tsssStart;
}
break;
case tsssIntOrFloat:
if (isDecimalChar(ch))
charStr += ch;
else if (ch == '.') {
charStr += ch;
state = tsssFloat;
} else if (ch == 'e' || ch == 'E') {
charStr += ch;
state = tsssLonelyFloatExtension;
} else {
// Terminate the number
AddInt(charStr.c_str(), startPos);
// Push the last char back on and try again
stream.Unget();
state = tsssStart;
}
break;
case tsssFloat:
if (isDecimalChar(ch))
charStr += ch;
else if (ch == 'e' || ch == 'E') {
charStr += ch;
state = tsssLonelyFloatExtension;
} else {
// Terminate the number
AddFloat(charStr.c_str(), startPos);
// Push the last char back on and try again
stream.Unget();
state = tsssStart;
}
break;
case tsssLonelyDecimalPoint:
if (isDecimalChar(ch)) {
charStr += ch;
state = tsssFloat;
} else
throw new Err(std::string("Sniffer pattern error: incomplete floating point number"), pos);
break;
case tsssLonelyMinusOrPlus:
if (isDecimalChar(ch)) {
charStr += ch;
state = tsssIntOrFloat;
} else if (ch == '.') {
charStr += ch;
state = tsssLonelyDecimalPoint; state = tsssLonelyDecimalPoint;
} else break;
throw new Err(std::string("Sniffer pattern error: incomplete signed number"), pos);
break;
case tsssLonelyFloatExtension: case '0':
if (ch == '+' || ch == '-') { charStr = ch;
charStr += ch; state = tsssOneZero;
state = tsssLonelyFloatExtensionWithSign; break;
} else if (isDecimalChar(ch)) {
charStr += ch;
state = tsssExtendedFloat;
} else
throw new Err(std::string("Sniffer pattern error: incomplete extended-notation floating point number"), pos);
break;
case tsssLonelyFloatExtensionWithSign: case '1':
if (isDecimalChar(ch)) { case '2':
charStr += ch; case '3':
state = tsssExtendedFloat; case '4':
} else case '5':
throw new Err(std::string("Sniffer pattern error: incomplete extended-notation floating point number"), pos); case '6':
break; case '7':
case '8':
case '9':
charStr = ch;
state = tsssIntOrFloat;
break;
case tsssExtendedFloat: case '&': AddToken(Ampersand, pos); break;
if (isDecimalChar(ch)) { case '(': AddToken(LeftParen, pos); break;
charStr += ch; case ')': AddToken(RightParen, pos); break;
state = tsssExtendedFloat; case ':': AddToken(Colon, pos); break;
} else { case '[': AddToken(LeftBracket, pos); break;
// Terminate the number
AddFloat(charStr.c_str(), startPos);
// Push the last char back on and try again case '\\':
stream.Unget(); charStr = ""; // Clear our string
state = tsssStart; state = tsssEscape;
} escapedState = tsssUnquoted; // Unquoted strings begin with an escaped character
break; break;
case tsssUnquoted: case ']': AddToken(RightBracket, pos); break;
if (ch == '\\') { case '|': AddToken(Divider, pos); break;
default:
throw new Err(std::string("Sniffer pattern error: invalid character '") + ch + "'", pos);
}
break;
case tsssOneSingle:
switch (ch) {
case '\\':
escapedState = state; // Save our state escapedState = state; // Save our state
state = tsssEscape; // Handle the escape sequence state = tsssEscape; // Handle the escape sequence
} else if (isWhiteSpace(ch) || isPunctuation(ch)) { break;
AddString(charStr.c_str(), startPos); case '\'':
stream.Unget(); // In case it's punctuation, let tsssStart handle it AddString(charStr, startPos);
state = tsssStart; state = tsssStart;
} else if (ch == '\'' || ch == '"') { break;
throw new Err(std::string("Sniffer pattern error: illegal unquoted character '") + ch + "'", pos); case 0x3:
} else if (ch == 0x3 && stream.IsEmpty()) { if (stream.IsEmpty())
AddString(charStr.c_str(), startPos); throw new Err(std::string("Sniffer pattern error: unterminated single-quoted string"), pos);
keepLooping = false; else
} else { charStr += ch;
break;
default:
charStr += ch; charStr += ch;
break;
}
break;
case tsssOneDouble:
switch (ch) {
case '\\':
escapedState = state; // Save our state
state = tsssEscape; // Handle the escape sequence
break;
case '"':
AddString(charStr, startPos);
state = tsssStart;
break;
case 0x3:
if (stream.IsEmpty())
throw new Err(std::string("Sniffer pattern error: unterminated double-quoted string"), pos);
else
charStr += ch;
break;
default:
charStr += ch;
break;
}
break;
case tsssOneZero:
if (ch == 'x') {
charStr = ""; // Reinit, since we actually have a hex string
state = tsssZeroX;
} else if ('0' <= ch && ch <= '9') {
charStr += ch;
state = tsssIntOrFloat;
} else if (ch == '.') {
charStr += ch;
state = tsssFloat;
} else if (ch == 'e' || ch == 'E') {
charStr += ch;
state = tsssLonelyFloatExtension;
} else {
// Terminate the number
AddInt(charStr.c_str(), startPos);
// Push the last char back on and try again
stream.Unget();
state = tsssStart;
}
break;
case tsssZeroX:
if (isHexChar(ch)) {
lastChar = ch;
state = tsssOneHex;
} else
throw new Err(std::string("Sniffer pattern error: incomplete hex code"), pos);
break;
case tsssOneHex:
if (isHexChar(ch)) {
try {
charStr += hexToChar(lastChar, ch);
} catch (Err *err) {
if (err)
err->SetPos(pos);
throw err;
} }
break; state = tsssTwoHex;
} else
throw new Err(std::string("Sniffer pattern error: bad hex literal"), pos); // Same as R5
break;
case tsssEscape: case tsssTwoHex:
if (isOctalChar(ch)) { if (isHexChar(ch)) {
lastChar = ch; lastChar = ch;
state = tsssEscapeOneOctal; state = tsssOneHex;
} else if (ch == 'x') { } else {
state = tsssEscapeX; AddString(charStr, startPos);
} else { stream.Unget(); // So punctuation gets handled properly
// Check for a true end-of-text marker state = tsssStart;
if (ch == 0x3 && stream.IsEmpty()) }
throw new Err(std::string("Sniffer pattern error: incomplete escape sequence"), pos); break;
else {
charStr += escapeChar(ch); case tsssIntOrFloat:
state = escapedState; // Return to the state we were in before the escape if (isDecimalChar(ch))
} charStr += ch;
else if (ch == '.') {
charStr += ch;
state = tsssFloat;
} else if (ch == 'e' || ch == 'E') {
charStr += ch;
state = tsssLonelyFloatExtension;
} else {
// Terminate the number
AddInt(charStr.c_str(), startPos);
// Push the last char back on and try again
stream.Unget();
state = tsssStart;
}
break;
case tsssFloat:
if (isDecimalChar(ch))
charStr += ch;
else if (ch == 'e' || ch == 'E') {
charStr += ch;
state = tsssLonelyFloatExtension;
} else {
// Terminate the number
AddFloat(charStr.c_str(), startPos);
// Push the last char back on and try again
stream.Unget();
state = tsssStart;
}
break;
case tsssLonelyDecimalPoint:
if (isDecimalChar(ch)) {
charStr += ch;
state = tsssFloat;
} else
throw new Err(std::string("Sniffer pattern error: incomplete floating point number"), pos);
break;
case tsssLonelyMinusOrPlus:
if (isDecimalChar(ch)) {
charStr += ch;
state = tsssIntOrFloat;
} else if (ch == '.') {
charStr += ch;
state = tsssLonelyDecimalPoint;
} else
throw new Err(std::string("Sniffer pattern error: incomplete signed number"), pos);
break;
case tsssLonelyFloatExtension:
if (ch == '+' || ch == '-') {
charStr += ch;
state = tsssLonelyFloatExtensionWithSign;
} else if (isDecimalChar(ch)) {
charStr += ch;
state = tsssExtendedFloat;
} else
throw new Err(std::string("Sniffer pattern error: incomplete extended-notation floating point number"), pos);
break;
case tsssLonelyFloatExtensionWithSign:
if (isDecimalChar(ch)) {
charStr += ch;
state = tsssExtendedFloat;
} else
throw new Err(std::string("Sniffer pattern error: incomplete extended-notation floating point number"), pos);
break;
case tsssExtendedFloat:
if (isDecimalChar(ch)) {
charStr += ch;
state = tsssExtendedFloat;
} else {
// Terminate the number
AddFloat(charStr.c_str(), startPos);
// Push the last char back on and try again
stream.Unget();
state = tsssStart;
}
break;
case tsssUnquoted:
if (ch == '\\') {
escapedState = state; // Save our state
state = tsssEscape; // Handle the escape sequence
} else if (isWhiteSpace(ch) || isPunctuation(ch)) {
AddString(charStr, startPos);
stream.Unget(); // In case it's punctuation, let tsssStart handle it
state = tsssStart;
} else if (ch == '\'' || ch == '"') {
throw new Err(std::string("Sniffer pattern error: illegal unquoted character '") + ch + "'", pos);
} else if (ch == 0x3 && stream.IsEmpty()) {
AddString(charStr, startPos);
keepLooping = false;
} else {
charStr += ch;
}
break;
case tsssEscape:
if (isOctalChar(ch)) {
lastChar = ch;
state = tsssEscapeOneOctal;
} else if (ch == 'x') {
state = tsssEscapeX;
} else {
// Check for a true end-of-text marker
if (ch == 0x3 && stream.IsEmpty())
throw new Err(std::string("Sniffer pattern error: incomplete escape sequence"), pos);
else {
charStr += escapeChar(ch);
state = escapedState; // Return to the state we were in before the escape
} }
break; }
break;
case tsssEscapeX: case tsssEscapeX:
if (isHexChar(ch)) { if (isHexChar(ch)) {
lastChar = ch; lastChar = ch;
state = tsssEscapeOneHex; state = tsssEscapeOneHex;
} else } else
throw new Err(std::string("Sniffer pattern error: incomplete escaped hex code"), pos); throw new Err(std::string("Sniffer pattern error: incomplete escaped hex code"), pos);
break; break;
case tsssEscapeOneOctal: case tsssEscapeOneOctal:
if (isOctalChar(ch)) { if (isOctalChar(ch)) {
lastLastChar = lastChar; lastLastChar = lastChar;
lastChar = ch; lastChar = ch;
state = tsssEscapeTwoOctal; state = tsssEscapeTwoOctal;
} else { } else {
// First handle the octal // First handle the octal
try { try {
charStr += octalToChar(lastChar); charStr += octalToChar(lastChar);
} catch (Err *err) { } catch (Err *err) {
if (err) if (err)
err->SetPos(startPos); err->SetPos(startPos);
throw err; throw err;
}
// Push the new char back on and let the state we
// were in when the escape sequence was hit handle it.
stream.Unget();
state = escapedState;
} }
break;
case tsssEscapeTwoOctal: // Push the new char back on and let the state we
if (isOctalChar(ch)) { // were in when the escape sequence was hit handle it.
try { stream.Unget();
charStr += octalToChar(lastLastChar, lastChar, ch); state = escapedState;
} catch (Err *err) { }
if (err) break;
err->SetPos(startPos);
throw err;
}
state = escapedState;
} else {
// First handle the octal
try {
charStr += octalToChar(lastLastChar, lastChar);
} catch (Err *err) {
if (err)
err->SetPos(startPos);
throw err;
}
// Push the new char back on and let the state we case tsssEscapeTwoOctal:
// were in when the escape sequence was hit handle it. if (isOctalChar(ch)) {
stream.Unget(); try {
state = escapedState; charStr += octalToChar(lastLastChar, lastChar, ch);
} catch (Err *err) {
if (err)
err->SetPos(startPos);
throw err;
}
state = escapedState;
} else {
// First handle the octal
try {
charStr += octalToChar(lastLastChar, lastChar);
} catch (Err *err) {
if (err)
err->SetPos(startPos);
throw err;
} }
break;
case tsssEscapeOneHex: // Push the new char back on and let the state we
if (isHexChar(ch)) { // were in when the escape sequence was hit handle it.
try { stream.Unget();
charStr += hexToChar(lastChar, ch); state = escapedState;
} catch (Err *err) { }
if (err) break;
err->SetPos(pos);
throw err; case tsssEscapeOneHex:
} if (isHexChar(ch)) {
state = escapedState; try {
} else charStr += hexToChar(lastChar, ch);
throw new Err(std::string("Sniffer pattern error: incomplete escaped hex code"), pos); } catch (Err *err) {
break; if (err)
err->SetPos(pos);
throw err;
}
state = escapedState;
} else
throw new Err(std::string("Sniffer pattern error: incomplete escaped hex code"), pos);
break;
}
}
if (state == tsssStart) {
fCStatus = B_OK;
fPos = 0;
} else {
throw new Err("Sniffer pattern error: unterminated rule", stream.Pos());
} }
} }
if (state == tsssStart) {
fCStatus = B_OK;
fPos = 0;
} else {
throw new Err("Sniffer pattern error: unterminated rule", stream.Pos());
}
return fCStatus; return fCStatus;
} }
@@ -828,7 +821,7 @@ TokenStream::AddToken(TokenType type, ssize_t pos) {
} }
void void
TokenStream::AddString(const char *str, ssize_t pos) { TokenStream::AddString(const std::string &str, ssize_t pos) {
Token *token = new StringToken(str, pos); Token *token = new StringToken(str, pos);
fTokenList.push_back(token); fTokenList.push_back(token);
} }
@@ -1274,7 +1267,7 @@ Parser::ParsePattern() {
// String (i.e. Mask) // String (i.e. Mask)
const Token *t = stream.Get(); const Token *t = stream.Get();
if (t->Type() == CharacterString) { if (t->Type() == CharacterString) {
Pattern *result = new(nothrow) Pattern(str.c_str(), t->String()); Pattern *result = new(nothrow) Pattern(str, t->String());
if (!result) if (!result)
ThrowOutOfMemError(t->Pos()); ThrowOutOfMemError(t->Pos());
if (result->InitCheck() == B_OK) { if (result->InitCheck() == B_OK) {
@@ -1291,7 +1284,7 @@ Parser::ParsePattern() {
ThrowUnexpectedTokenError(CharacterString, t); ThrowUnexpectedTokenError(CharacterString, t);
} else { } else {
// No mask specified. // No mask specified.
Pattern *result = new(nothrow) Pattern(str.c_str()); Pattern *result = new(nothrow) Pattern(str);
if (result) { if (result) {
if (result->InitCheck() == B_OK) if (result->InitCheck() == B_OK)
return result; return result;
+34 -22
View File
@@ -14,13 +14,25 @@
using namespace Sniffer; using namespace Sniffer;
Pattern::Pattern(const char *string, const char *mask = NULL) Pattern::Pattern(const std::string &string, const std::string &mask)
: fCStatus(B_NO_INIT) : fCStatus(B_NO_INIT)
, fErrorMessage(NULL) , fErrorMessage(NULL)
{ {
SetTo(string, mask); SetTo(string, mask);
} }
Pattern::Pattern(const std::string &string)
: fCStatus(B_NO_INIT)
, fErrorMessage(NULL)
{
// Build a mask with all bits turned on of the
// appropriate length
std::string mask = "";
for (int i = 0; i < string.length(); i++)
mask += (char)0xFF;
SetTo(string, mask);
}
Pattern::~Pattern() { Pattern::~Pattern() {
delete fErrorMessage; delete fErrorMessage;
} }
@@ -38,29 +50,28 @@ Pattern::GetErr() const {
return new(nothrow) Err(*fErrorMessage); return new(nothrow) Err(*fErrorMessage);
} }
void dumpStr(const std::string &string, const char *label = NULL) {
if (label)
printf("%s: ", label);
for (int i = 0; i < string.length(); i++)
printf("%x ", string[i]);
printf("\n");
}
status_t status_t
Pattern::SetTo(const char *string, const char *mask) { Pattern::SetTo(const std::string &string, const std::string &mask) {
if (string) { fString = string;
fString = string; if (fString.length() == 0) {
if (fString.length() == 0) { SetStatus(B_BAD_VALUE, "Sniffer pattern error: illegal empty pattern");
SetStatus(B_BAD_VALUE, "Sniffer pattern error: illegal empty pattern");
} else {
if (mask) {
fMask = mask;
if (fString.length() != fMask.length()) {
SetStatus(B_BAD_VALUE, "Sniffer pattern error: pattern and mask lengths do not match");
} else {
SetStatus(B_OK);
}
} else {
fMask = "";
for (int i = 0; i < fString.length(); i++)
fMask += (char)0xFF;
SetStatus(B_OK);
}
}
} else { } else {
SetStatus(B_BAD_VALUE, "Sniffer parser error: NULL string parameter passed to Pattern::SetTo()"); fMask = mask;
// dumpStr(string, "data");
// dumpStr(mask, "mask");
if (fString.length() != fMask.length()) {
SetStatus(B_BAD_VALUE, "Sniffer pattern error: pattern and mask lengths do not match");
} else {
SetStatus(B_OK);
}
} }
} }
@@ -82,6 +93,7 @@ Pattern::Sniff(Range range, BPositionIO *data) const {
if (Sniff(i, size, data)) if (Sniff(i, size, data))
return true; return true;
} }
return false;
} }
// Assumes the BPositionIO object is in the correct // Assumes the BPositionIO object is in the correct
+1
View File
@@ -47,6 +47,7 @@ Rule::Sniff(BPositionIO *data) const {
if (*i) if (*i)
result &= (*i)->Sniff(data); result &= (*i)->Sniff(data);
} }
return result;
} }
} }