File indexing completed on 2024-11-17 04:50:40
0001 /* -*- c++ -*- 0002 impl/lexer.h 0003 0004 Internal header file. Subject to change without notice. DO NOT USE. 0005 0006 This file is part of KSieve, 0007 the KDE internet mail/usenet news message filtering library. 0008 SPDX-FileCopyrightText: 2003 Marc Mutz <mutz@kde.org> 0009 0010 SPDX-License-Identifier: GPL-2.0-only 0011 */ 0012 0013 #pragma once 0014 0015 #include "error.h" 0016 #include "lexer.h" 0017 0018 #include <QStack> 0019 0020 namespace KSieve 0021 { 0022 class Lexer::Impl 0023 { 0024 public: 0025 Impl(const char *scursor, const char *send, int options); 0026 0027 bool ignoreComments() const 0028 { 0029 return mIgnoreComments; 0030 } 0031 0032 bool ignoreLineFeeds() const 0033 { 0034 return mIgnoreLF; 0035 } 0036 0037 const Error &error() const 0038 { 0039 return mState.error; 0040 } 0041 0042 bool atEnd() const 0043 { 0044 return mState.cursor >= mEnd; 0045 } 0046 0047 int column() const 0048 { 0049 return mState.cursor - mState.beginOfLine; 0050 } 0051 0052 int line() const 0053 { 0054 return mState.line; 0055 } 0056 0057 void save() 0058 { 0059 mStateStack.push(mState); 0060 } 0061 0062 void restore() 0063 { 0064 mState = mStateStack.pop(); 0065 } 0066 0067 Lexer::Token nextToken(QString &tokenValue); 0068 0069 private: 0070 /** Cursor must be positioned on the \r or the \n. */ 0071 bool eatCRLF(); 0072 0073 /** Cursor must be positioned after the opening hash (#). If 0074 parsing is successful, cursor is positioned behind the CRLF 0075 that ended the comment's line (or past the end). */ 0076 bool parseHashComment(QString &result, bool reallySave = false); 0077 0078 /** Cursor must be positioned after the opening slash-asterisk */ 0079 bool parseBracketComment(QString &result, bool reallySave = false); 0080 0081 /** Cursor must be positioned on the opening '/'or '#' */ 0082 bool parseComment(QString &result, bool reallySave = false); 0083 0084 /** Eats whitespace, but not comments */ 0085 bool eatWS(); 0086 0087 /** Eats comments and whitespace */ 0088 bool eatCWS(); 0089 0090 /** Cursor must be positioned on the first character */ 0091 bool parseIdentifier(QString &result); 0092 0093 /** Cursor must be positioned after the initial ':' */ 0094 bool parseTag(QString &result); 0095 0096 /** Cursor must be positioned on the first digit */ 0097 bool parseNumber(QString &result); 0098 0099 /** Cursor must be positioned after the "text:" token. */ 0100 bool parseMultiLine(QString &result); 0101 0102 /** Cursor must be positioned after the initial " */ 0103 bool parseQuotedString(QString &result); 0104 0105 struct State { 0106 State(const char *s = nullptr) 0107 : cursor(s) 0108 , beginOfLine(s) 0109 , error() 0110 { 0111 } 0112 0113 const char *cursor; 0114 int line = 0; 0115 const char *beginOfLine; 0116 Error error; 0117 } mState; 0118 0119 const char *const mEnd; 0120 const bool mIgnoreComments : 1; 0121 const bool mIgnoreLF : 1; 0122 QStack<State> mStateStack; 0123 0124 const char *beginOfLine() const 0125 { 0126 return mState.beginOfLine; 0127 } 0128 0129 int _strnicmp(const char *left, const char *right, size_t len) const 0130 { 0131 return charsLeft() >= len ? qstrnicmp(left, right, len) : 1; 0132 } 0133 0134 void clearErrors() 0135 { 0136 mState.error = Error(); 0137 } 0138 0139 unsigned int charsLeft() const 0140 { 0141 return mEnd - mState.cursor < 0 ? 0 : mEnd - mState.cursor; 0142 } 0143 0144 void makeError(Error::Type e) 0145 { 0146 makeError(e, line(), column()); 0147 } 0148 0149 void makeError(Error::Type e, int errorLine, int errorCol) 0150 { 0151 mState.error = Error(e, errorLine, errorCol); 0152 } 0153 0154 void makeIllegalCharError(char ch); 0155 void makeIllegalCharError() 0156 { 0157 makeIllegalCharError(*mState.cursor); 0158 } 0159 0160 /** Defines the current char to end a line. 0161 Warning: increases @p mCursor! 0162 **/ 0163 void newLine() 0164 { 0165 ++mState.line; 0166 mState.beginOfLine = ++mState.cursor; 0167 } 0168 0169 bool skipTo(char c, bool acceptEnd = false) 0170 { 0171 while (!atEnd()) { 0172 if (*mState.cursor == '\n' || *mState.cursor == '\r') { 0173 if (!eatCRLF()) { 0174 return false; 0175 } 0176 } else if (*mState.cursor == c) { 0177 return true; 0178 } else { 0179 ++mState.cursor; 0180 } 0181 } 0182 return acceptEnd; 0183 } 0184 0185 bool skipToCRLF(bool acceptEnd = true) 0186 { 0187 for (; !atEnd(); ++mState.cursor) { 0188 if (*mState.cursor == '\n' || *mState.cursor == '\r') { 0189 return eatCRLF(); 0190 } 0191 } 0192 return acceptEnd; 0193 } 0194 0195 void skipTo8BitEnd() 0196 { 0197 while (!atEnd() && (signed char)*mState.cursor < 0) { 0198 ++mState.cursor; 0199 } 0200 } 0201 0202 void skipToDelim(); 0203 }; 0204 }