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 }