CMakePM: Add CMake source file parser

Files taken from the CMake repository https://gitlab.kitware.com/cmake/cmake.git

624461526f4707a2406ebbd40245a605b6bd41fa (tag: v3.26.3)

Change-Id: I9ef388908cd22eb2748b5c17d039848ee23585b9
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Cristian Adam
2023-04-06 15:30:13 +02:00
parent c118f8cae4
commit 71eb0ab9f8
9 changed files with 1690 additions and 0 deletions

View File

@@ -867,3 +867,40 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
### cmake
The CMake project manager uses the CMake lexer code for parsing CMake files
https://gitlab.kitware.com/cmake/cmake.git
CMake - Cross Platform Makefile Generator
Copyright 2000-2023 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Kitware, Inc. nor the names of Contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1059,5 +1059,47 @@
\include license-mit.qdocinc
\li \b cmake
The CMake project manager uses the CMake lexer code for parsing CMake files.
\list
\li \l https://gitlab.kitware.com/cmake/cmake.git
\endlist
CMake - Cross Platform Makefile Generator
Copyright 2000-2023 Kitware, Inc. and Contributors
All rights reserved.
\badcode
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Kitware, Inc. nor the names of Contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\endcode
\endlist
*/

View File

@@ -0,0 +1,136 @@
CMake - Cross Platform Makefile Generator
Copyright 2000-2023 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Kitware, Inc. nor the names of Contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
The following individuals and institutions are among the Contributors:
* Aaron C. Meadows <cmake@shadowguarddev.com>
* Adriaan de Groot <groot@kde.org>
* Aleksey Avdeev <solo@altlinux.ru>
* Alexander Neundorf <neundorf@kde.org>
* Alexander Smorkalov <alexander.smorkalov@itseez.com>
* Alexey Sokolov <sokolov@google.com>
* Alex Merry <alex.merry@kde.org>
* Alex Turbov <i.zaufi@gmail.com>
* Andreas Pakulat <apaku@gmx.de>
* Andreas Schneider <asn@cryptomilk.org>
* André Rigland Brodtkorb <Andre.Brodtkorb@ifi.uio.no>
* Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf
* Benjamin Eikel
* Bjoern Ricks <bjoern.ricks@gmail.com>
* Brad Hards <bradh@kde.org>
* Christopher Harvey
* Christoph Grüninger <foss@grueninger.de>
* Clement Creusot <creusot@cs.york.ac.uk>
* Daniel Blezek <blezek@gmail.com>
* Daniel Pfeifer <daniel@pfeifer-mail.de>
* Dawid Wróbel <me@dawidwrobel.com>
* Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
* Eran Ifrah <eran.ifrah@gmail.com>
* Esben Mose Hansen, Ange Optimization ApS
* Geoffrey Viola <geoffrey.viola@asirobots.com>
* Google Inc
* Gregor Jasny
* Helio Chissini de Castro <helio@kde.org>
* Ilya Lavrenov <ilya.lavrenov@itseez.com>
* Insight Software Consortium <insightsoftwareconsortium.org>
* Intel Corporation <www.intel.com>
* Jan Woetzel
* Jordan Williams <jordan@jwillikers.com>
* Julien Schueller
* Kelly Thompson <kgt@lanl.gov>
* Konstantin Podsvirov <konstantin@podsvirov.pro>
* Laurent Montel <montel@kde.org>
* Mario Bensi <mbensi@ipsquad.net>
* Martin Gräßlin <mgraesslin@kde.org>
* Mathieu Malaterre <mathieu.malaterre@gmail.com>
* Matthaeus G. Chajdas
* Matthias Kretz <kretz@kde.org>
* Matthias Maennich <matthias@maennich.net>
* Michael Hirsch, Ph.D. <www.scivision.co>
* Michael Stürmer
* Miguel A. Figueroa-Villanueva
* Mike Durso <rbprogrammer@gmail.com>
* Mike Jackson
* Mike McQuaid <mike@mikemcquaid.com>
* Nicolas Bock <nicolasbock@gmail.com>
* Nicolas Despres <nicolas.despres@gmail.com>
* Nikita Krupen'ko <krnekit@gmail.com>
* NVIDIA Corporation <www.nvidia.com>
* OpenGamma Ltd. <opengamma.com>
* Patrick Stotko <stotko@cs.uni-bonn.de>
* Per Øyvind Karlsen <peroyvind@mandriva.org>
* Peter Collingbourne <peter@pcc.me.uk>
* Petr Gotthard <gotthard@honeywell.com>
* Philip Lowman <philip@yhbt.com>
* Philippe Proulx <pproulx@efficios.com>
* Raffi Enficiaud, Max Planck Society
* Raumfeld <raumfeld.com>
* Roger Leigh <rleigh@codelibre.net>
* Rolf Eike Beer <eike@sf-mail.de>
* Roman Donchenko <roman.donchenko@itseez.com>
* Roman Kharitonov <roman.kharitonov@itseez.com>
* Ruslan Baratov
* Sebastian Holtermann <sebholt@xwmw.org>
* Stephen Kelly <steveire@gmail.com>
* Sylvain Joubert <joubert.sy@gmail.com>
* The Qt Company Ltd.
* Thomas Sondergaard <ts@medical-insight.com>
* Tobias Hunger <tobias.hunger@qt.io>
* Todd Gamblin <tgamblin@llnl.gov>
* Tristan Carel
* University of Dundee
* Vadim Zhukov
* Will Dicharry <wdicharry@stellarscience.com>
See version control history for details of individual contributions.
The above copyright and license notice applies to distributions of
CMake in source and binary form. Third-party software packages supplied
with CMake under compatible licenses provide their own copyright notices
documented in corresponding subdirectories or source files.
------------------------------------------------------------------------------
CMake was initially developed by Kitware with the following sponsorship:
* National Library of Medicine at the National Institutes of Health
as part of the Insight Segmentation and Registration Toolkit (ITK).
* US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
Visualization Initiative.
* National Alliance for Medical Image Computing (NAMIC) is funded by the
National Institutes of Health through the NIH Roadmap for Medical Research,
Grant U54 EB005149.
* Kitware, Inc.

View File

@@ -0,0 +1,4 @@
Files taken from the CMake repository https://gitlab.kitware.com/cmake/cmake.git
624461526f4707a2406ebbd40245a605b6bd41fa (tag: v3.26.3)

View File

@@ -0,0 +1,508 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#define cmListFileCache_cxx
#include "cmListFileCache.h"
#include <memory>
#include <sstream>
#include <utility>
#ifdef _WIN32
# include <cmsys/Encoding.hxx>
#endif
#include "cmListFileLexer.h"
#include "cmMessageType.h"
#include "cmMessenger.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
struct cmListFileParser
{
cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
cmMessenger* messenger);
~cmListFileParser();
cmListFileParser(const cmListFileParser&) = delete;
cmListFileParser& operator=(const cmListFileParser&) = delete;
void IssueFileOpenError(std::string const& text) const;
void IssueError(std::string const& text) const;
bool ParseFile(const char* filename);
bool ParseString(const char* str, const char* virtual_filename);
bool Parse();
bool ParseFunction(const char* name, long line);
bool AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim);
cm::optional<cmListFileContext> CheckNesting() const;
cmListFile* ListFile;
cmListFileBacktrace Backtrace;
cmMessenger* Messenger;
const char* FileName = nullptr;
cmListFileLexer* Lexer;
std::string FunctionName;
long FunctionLine;
long FunctionLineEnd;
std::vector<cmListFileArgument> FunctionArguments;
enum
{
SeparationOkay,
SeparationWarning,
SeparationError
} Separation;
};
cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
cmMessenger* messenger)
: ListFile(lf)
, Backtrace(std::move(lfbt))
, Messenger(messenger)
, Lexer(cmListFileLexer_New())
{
}
cmListFileParser::~cmListFileParser()
{
cmListFileLexer_Delete(this->Lexer);
}
void cmListFileParser::IssueFileOpenError(const std::string& text) const
{
this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text,
this->Backtrace);
}
void cmListFileParser::IssueError(const std::string& text) const
{
cmListFileContext lfc;
lfc.FilePath = this->FileName;
lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer);
cmListFileBacktrace lfbt = this->Backtrace;
lfbt = lfbt.Push(lfc);
this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text, lfbt);
cmSystemTools::SetFatalErrorOccurred();
}
bool cmListFileParser::ParseFile(const char* filename)
{
this->FileName = filename;
#ifdef _WIN32
std::string expandedFileName = cmsys::Encoding::ToNarrow(
cmSystemTools::ConvertToWindowsExtendedPath(filename));
filename = expandedFileName.c_str();
#endif
// Open the file.
cmListFileLexer_BOM bom;
if (!cmListFileLexer_SetFileName(this->Lexer, filename, &bom)) {
this->IssueFileOpenError("cmListFileCache: error can not open file.");
return false;
}
if (bom == cmListFileLexer_BOM_Broken) {
cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr);
this->IssueFileOpenError("Error while reading Byte-Order-Mark. "
"File not seekable?");
return false;
}
// Verify the Byte-Order-Mark, if any.
if (bom != cmListFileLexer_BOM_None && bom != cmListFileLexer_BOM_UTF8) {
cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr);
this->IssueFileOpenError(
"File starts with a Byte-Order-Mark that is not UTF-8.");
return false;
}
return this->Parse();
}
bool cmListFileParser::ParseString(const char* str,
const char* virtual_filename)
{
this->FileName = virtual_filename;
if (!cmListFileLexer_SetString(this->Lexer, str)) {
this->IssueFileOpenError("cmListFileCache: cannot allocate buffer.");
return false;
}
return this->Parse();
}
bool cmListFileParser::Parse()
{
// Use a simple recursive-descent parser to process the token
// stream.
bool haveNewline = true;
while (cmListFileLexer_Token* token = cmListFileLexer_Scan(this->Lexer)) {
if (token->type == cmListFileLexer_Token_Space) {
} else if (token->type == cmListFileLexer_Token_Newline) {
haveNewline = true;
} else if (token->type == cmListFileLexer_Token_CommentBracket) {
haveNewline = false;
} else if (token->type == cmListFileLexer_Token_Identifier) {
if (haveNewline) {
haveNewline = false;
if (this->ParseFunction(token->text, token->line)) {
this->ListFile->Functions.emplace_back(
std::move(this->FunctionName), this->FunctionLine,
this->FunctionLineEnd, std::move(this->FunctionArguments));
} else {
return false;
}
} else {
std::ostringstream error;
error << "Parse error. Expected a newline, got "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
this->IssueError(error.str());
return false;
}
} else {
std::ostringstream error;
error << "Parse error. Expected a command name, got "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
this->IssueError(error.str());
return false;
}
}
// Check if all functions are nested properly.
if (auto badNesting = this->CheckNesting()) {
this->Messenger->IssueMessage(
MessageType::FATAL_ERROR,
"Flow control statements are not properly nested.",
this->Backtrace.Push(*badNesting));
cmSystemTools::SetFatalErrorOccurred();
return false;
}
return true;
}
bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger,
cmListFileBacktrace const& lfbt)
{
if (!cmSystemTools::FileExists(filename) ||
cmSystemTools::FileIsDirectory(filename)) {
return false;
}
bool parseError = false;
{
cmListFileParser parser(this, lfbt, messenger);
parseError = !parser.ParseFile(filename);
}
return !parseError;
}
bool cmListFile::ParseString(const char* str, const char* virtual_filename,
cmMessenger* messenger,
const cmListFileBacktrace& lfbt)
{
bool parseError = false;
{
cmListFileParser parser(this, lfbt, messenger);
parseError = !parser.ParseString(str, virtual_filename);
}
return !parseError;
}
bool cmListFileParser::ParseFunction(const char* name, long line)
{
// Ininitialize a new function call.
this->FunctionName = name;
this->FunctionLine = line;
// Command name has already been parsed. Read the left paren.
cmListFileLexer_Token* token;
while ((token = cmListFileLexer_Scan(this->Lexer)) &&
token->type == cmListFileLexer_Token_Space) {
}
if (!token) {
std::ostringstream error;
/* clang-format off */
error << "Unexpected end of file.\n"
<< "Parse error. Function missing opening \"(\".";
/* clang-format on */
this->IssueError(error.str());
return false;
}
if (token->type != cmListFileLexer_Token_ParenLeft) {
std::ostringstream error;
error << "Parse error. Expected \"(\", got "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
this->IssueError(error.str());
return false;
}
// Arguments.
unsigned long parenDepth = 0;
this->Separation = SeparationOkay;
while ((token = cmListFileLexer_Scan(this->Lexer))) {
if (token->type == cmListFileLexer_Token_Space ||
token->type == cmListFileLexer_Token_Newline) {
this->Separation = SeparationOkay;
continue;
}
if (token->type == cmListFileLexer_Token_ParenLeft) {
parenDepth++;
this->Separation = SeparationOkay;
if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
return false;
}
} else if (token->type == cmListFileLexer_Token_ParenRight) {
if (parenDepth == 0) {
this->FunctionLineEnd = token->line;
return true;
}
parenDepth--;
this->Separation = SeparationOkay;
if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
return false;
}
this->Separation = SeparationWarning;
} else if (token->type == cmListFileLexer_Token_Identifier ||
token->type == cmListFileLexer_Token_ArgumentUnquoted) {
if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
return false;
}
this->Separation = SeparationWarning;
} else if (token->type == cmListFileLexer_Token_ArgumentQuoted) {
if (!this->AddArgument(token, cmListFileArgument::Quoted)) {
return false;
}
this->Separation = SeparationWarning;
} else if (token->type == cmListFileLexer_Token_ArgumentBracket) {
if (!this->AddArgument(token, cmListFileArgument::Bracket)) {
return false;
}
this->Separation = SeparationError;
} else if (token->type == cmListFileLexer_Token_CommentBracket) {
this->Separation = SeparationError;
} else {
// Error.
std::ostringstream error;
error << "Parse error. Function missing ending \")\". "
<< "Instead found "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
this->IssueError(error.str());
return false;
}
}
std::ostringstream error;
cmListFileContext lfc;
lfc.FilePath = this->FileName;
lfc.Line = line;
cmListFileBacktrace lfbt = this->Backtrace;
lfbt = lfbt.Push(lfc);
error << "Parse error. Function missing ending \")\". "
<< "End of file reached.";
this->Messenger->IssueMessage(MessageType::FATAL_ERROR, error.str(), lfbt);
return false;
}
bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim)
{
this->FunctionArguments.emplace_back(token->text, delim, token->line);
if (this->Separation == SeparationOkay) {
return true;
}
bool isError = (this->Separation == SeparationError ||
delim == cmListFileArgument::Bracket);
std::ostringstream m;
cmListFileContext lfc;
lfc.FilePath = this->FileName;
lfc.Line = token->line;
cmListFileBacktrace lfbt = this->Backtrace;
lfbt = lfbt.Push(lfc);
m << "Syntax " << (isError ? "Error" : "Warning") << " in cmake code at "
<< "column " << token->column << "\n"
<< "Argument not separated from preceding token by whitespace.";
/* clang-format on */
if (isError) {
this->Messenger->IssueMessage(MessageType::FATAL_ERROR, m.str(), lfbt);
return false;
}
this->Messenger->IssueMessage(MessageType::AUTHOR_WARNING, m.str(), lfbt);
return true;
}
namespace {
enum class NestingStateEnum
{
If,
Else,
While,
Foreach,
Function,
Macro,
Block
};
struct NestingState
{
NestingStateEnum State;
cmListFileContext Context;
};
bool TopIs(std::vector<NestingState>& stack, NestingStateEnum state)
{
return !stack.empty() && stack.back().State == state;
}
}
cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const
{
std::vector<NestingState> stack;
for (auto const& func : this->ListFile->Functions) {
auto const& name = func.LowerCaseName();
if (name == "if") {
stack.push_back({
NestingStateEnum::If,
cmListFileContext::FromListFileFunction(func, this->FileName),
});
} else if (name == "elseif") {
if (!TopIs(stack, NestingStateEnum::If)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.back() = {
NestingStateEnum::If,
cmListFileContext::FromListFileFunction(func, this->FileName),
};
} else if (name == "else") {
if (!TopIs(stack, NestingStateEnum::If)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.back() = {
NestingStateEnum::Else,
cmListFileContext::FromListFileFunction(func, this->FileName),
};
} else if (name == "endif") {
if (!TopIs(stack, NestingStateEnum::If) &&
!TopIs(stack, NestingStateEnum::Else)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
} else if (name == "while") {
stack.push_back({
NestingStateEnum::While,
cmListFileContext::FromListFileFunction(func, this->FileName),
});
} else if (name == "endwhile") {
if (!TopIs(stack, NestingStateEnum::While)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
} else if (name == "foreach") {
stack.push_back({
NestingStateEnum::Foreach,
cmListFileContext::FromListFileFunction(func, this->FileName),
});
} else if (name == "endforeach") {
if (!TopIs(stack, NestingStateEnum::Foreach)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
} else if (name == "function") {
stack.push_back({
NestingStateEnum::Function,
cmListFileContext::FromListFileFunction(func, this->FileName),
});
} else if (name == "endfunction") {
if (!TopIs(stack, NestingStateEnum::Function)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
} else if (name == "macro") {
stack.push_back({
NestingStateEnum::Macro,
cmListFileContext::FromListFileFunction(func, this->FileName),
});
} else if (name == "endmacro") {
if (!TopIs(stack, NestingStateEnum::Macro)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
} else if (name == "block") {
stack.push_back({
NestingStateEnum::Block,
cmListFileContext::FromListFileFunction(func, this->FileName),
});
} else if (name == "endblock") {
if (!TopIs(stack, NestingStateEnum::Block)) {
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
}
}
if (!stack.empty()) {
return stack.back().Context;
}
return cm::nullopt;
}
#include "cmConstStack.tcc"
template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
{
os << lfc.FilePath;
if (lfc.Line > 0) {
os << ":" << lfc.Line;
if (!lfc.Name.empty()) {
os << " (" << lfc.Name << ")";
}
} else if (lfc.Line == cmListFileContext::DeferPlaceholderLine) {
os << ":DEFERRED";
}
return os;
}
bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs)
{
if (lhs.Line != rhs.Line) {
return lhs.Line < rhs.Line;
}
return lhs.FilePath < rhs.FilePath;
}
bool operator==(const cmListFileContext& lhs, const cmListFileContext& rhs)
{
return lhs.Line == rhs.Line && lhs.FilePath == rhs.FilePath;
}
bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs)
{
return !(lhs == rhs);
}
std::ostream& operator<<(std::ostream& os, BT<std::string> const& s)
{
return os << s.Value;
}
std::vector<BT<std::string>> cmExpandListWithBacktrace(
std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs)
{
std::vector<BT<std::string>> result;
std::vector<std::string> tmp = cmExpandedList(list, emptyArgs);
result.reserve(tmp.size());
for (std::string& i : tmp) {
result.emplace_back(std::move(i), bt);
}
return result;
}

View File

@@ -0,0 +1,246 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <cm/optional>
#include "cmConstStack.h"
#include "cmSystemTools.h"
/** \class cmListFileCache
* \brief A class to cache list file contents.
*
* cmListFileCache is a class used to cache the contents of parsed
* cmake list files.
*/
class cmMessenger;
struct cmListFileArgument
{
enum Delimiter
{
Unquoted,
Quoted,
Bracket
};
cmListFileArgument() = default;
cmListFileArgument(std::string v, Delimiter d, long line)
: Value(std::move(v))
, Delim(d)
, Line(line)
{
}
bool operator==(const cmListFileArgument& r) const
{
return (this->Value == r.Value) && (this->Delim == r.Delim);
}
bool operator!=(const cmListFileArgument& r) const { return !(*this == r); }
std::string Value;
Delimiter Delim = Unquoted;
long Line = 0;
};
class cmListFileFunction
{
public:
cmListFileFunction(std::string name, long line, long lineEnd,
std::vector<cmListFileArgument> args)
: Impl{ std::make_shared<Implementation>(std::move(name), line, lineEnd,
std::move(args)) }
{
}
std::string const& OriginalName() const noexcept
{
return this->Impl->OriginalName;
}
std::string const& LowerCaseName() const noexcept
{
return this->Impl->LowerCaseName;
}
long Line() const noexcept { return this->Impl->Line; }
long LineEnd() const noexcept { return this->Impl->LineEnd; }
std::vector<cmListFileArgument> const& Arguments() const noexcept
{
return this->Impl->Arguments;
}
private:
struct Implementation
{
Implementation(std::string name, long line, long lineEnd,
std::vector<cmListFileArgument> args)
: OriginalName{ std::move(name) }
, LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) }
, Line{ line }
, LineEnd{ lineEnd }
, Arguments{ std::move(args) }
{
}
std::string OriginalName;
std::string LowerCaseName;
long Line = 0;
long LineEnd = 0;
std::vector<cmListFileArgument> Arguments;
};
std::shared_ptr<Implementation const> Impl;
};
class cmListFileContext
{
public:
std::string Name;
std::string FilePath;
long Line = 0;
static long const DeferPlaceholderLine = -1;
cm::optional<std::string> DeferId;
cmListFileContext() = default;
// This move constructor is marked `noexcept` yet `clang-tidy` 14 reports it
// as being able to throw an exception. Suppress the warning as there doesn't
// seem to be any way for this to happen given the member types.
// NOLINTNEXTLINE(bugprone-exception-escape)
cmListFileContext(cmListFileContext&& /*other*/) noexcept = default;
cmListFileContext(const cmListFileContext& /*other*/) = default;
cmListFileContext& operator=(const cmListFileContext& /*other*/) = default;
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
default;
#else
// The move assignment operators for several STL classes did not become
// noexcept until C++17, which causes some tools to warn about this move
// assignment operator throwing an exception when it shouldn't.
cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept =
delete;
#endif
cmListFileContext(std::string name, std::string filePath, long line)
: Name(std::move(name))
, FilePath(std::move(filePath))
, Line(line)
{
}
static cmListFileContext FromListFilePath(std::string const& filePath)
{
// We are entering a file-level scope but have not yet reached
// any specific line or command invocation within it. This context
// is useful to print when it is at the top but otherwise can be
// skipped during call stack printing.
cmListFileContext lfc;
lfc.FilePath = filePath;
return lfc;
}
static cmListFileContext FromListFileFunction(
cmListFileFunction const& lff, std::string const& fileName,
cm::optional<std::string> deferId = {})
{
cmListFileContext lfc;
lfc.FilePath = fileName;
lfc.Line = lff.Line();
lfc.Name = lff.OriginalName();
lfc.DeferId = std::move(deferId);
return lfc;
}
};
std::ostream& operator<<(std::ostream&, cmListFileContext const&);
bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs);
bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs);
bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);
// Represent a backtrace (call stack) with efficient value semantics.
class cmListFileBacktrace
: public cmConstStack<cmListFileContext, cmListFileBacktrace>
{
using cmConstStack::cmConstStack;
friend class cmConstStack<cmListFileContext, cmListFileBacktrace>;
};
#ifndef cmListFileCache_cxx
extern template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
#endif
// Wrap type T as a value with a backtrace. For purposes of
// ordering and equality comparison, only the original value is
// used. The backtrace is considered incidental.
template <typename T>
class BT
{
public:
BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
: Value(std::move(v))
, Backtrace(std::move(bt))
{
}
T Value;
cmListFileBacktrace Backtrace;
friend bool operator==(BT<T> const& l, BT<T> const& r)
{
return l.Value == r.Value;
}
friend bool operator<(BT<T> const& l, BT<T> const& r)
{
return l.Value < r.Value;
}
friend bool operator==(BT<T> const& l, T const& r) { return l.Value == r; }
friend bool operator==(T const& l, BT<T> const& r) { return l == r.Value; }
};
std::ostream& operator<<(std::ostream& os, BT<std::string> const& s);
// Wrap type T as a value with potentially multiple backtraces. For purposes
// of ordering and equality comparison, only the original value is used. The
// backtrace is considered incidental.
template <typename T>
class BTs
{
public:
BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
: Value(std::move(v))
{
this->Backtraces.emplace_back(std::move(bt));
}
T Value;
std::vector<cmListFileBacktrace> Backtraces;
friend bool operator==(BTs<T> const& l, BTs<T> const& r)
{
return l.Value == r.Value;
}
friend bool operator<(BTs<T> const& l, BTs<T> const& r)
{
return l.Value < r.Value;
}
friend bool operator==(BTs<T> const& l, T const& r) { return l.Value == r; }
friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; }
};
std::vector<BT<std::string>> cmExpandListWithBacktrace(
std::string const& list,
cmListFileBacktrace const& bt = cmListFileBacktrace(),
bool emptyArgs = false);
struct cmListFile
{
bool ParseFile(const char* path, cmMessenger* messenger,
cmListFileBacktrace const& lfbt);
bool ParseString(const char* str, const char* virtual_filename,
cmMessenger* messenger, cmListFileBacktrace const& lfbt);
std::vector<cmListFileFunction> Functions;
};

View File

@@ -0,0 +1,68 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* NOLINTNEXTLINE(modernize-use-using) */
typedef enum cmListFileLexer_Type_e
{
cmListFileLexer_Token_None,
cmListFileLexer_Token_Space,
cmListFileLexer_Token_Newline,
cmListFileLexer_Token_Identifier,
cmListFileLexer_Token_ParenLeft,
cmListFileLexer_Token_ParenRight,
cmListFileLexer_Token_ArgumentUnquoted,
cmListFileLexer_Token_ArgumentQuoted,
cmListFileLexer_Token_ArgumentBracket,
cmListFileLexer_Token_CommentBracket,
cmListFileLexer_Token_BadCharacter,
cmListFileLexer_Token_BadBracket,
cmListFileLexer_Token_BadString
} cmListFileLexer_Type;
/* NOLINTNEXTLINE(modernize-use-using) */
typedef struct cmListFileLexer_Token_s cmListFileLexer_Token;
struct cmListFileLexer_Token_s
{
cmListFileLexer_Type type;
char* text;
int length;
int line;
int column;
};
enum cmListFileLexer_BOM_e
{
cmListFileLexer_BOM_None,
cmListFileLexer_BOM_Broken,
cmListFileLexer_BOM_UTF8,
cmListFileLexer_BOM_UTF16BE,
cmListFileLexer_BOM_UTF16LE,
cmListFileLexer_BOM_UTF32BE,
cmListFileLexer_BOM_UTF32LE
};
/* NOLINTNEXTLINE(modernize-use-using) */
typedef enum cmListFileLexer_BOM_e cmListFileLexer_BOM;
/* NOLINTNEXTLINE(modernize-use-using) */
typedef struct cmListFileLexer_s cmListFileLexer;
cmListFileLexer* cmListFileLexer_New(void);
int cmListFileLexer_SetFileName(cmListFileLexer*, const char*,
cmListFileLexer_BOM* bom);
int cmListFileLexer_SetString(cmListFileLexer*, const char*);
cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer*);
long cmListFileLexer_GetCurrentLine(cmListFileLexer*);
long cmListFileLexer_GetCurrentColumn(cmListFileLexer*);
const char* cmListFileLexer_GetTypeAsString(cmListFileLexer*,
cmListFileLexer_Type);
void cmListFileLexer_Delete(cmListFileLexer*);
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -0,0 +1,560 @@
%{
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
/*
This file must be translated to C and modified to build everywhere.
Run flex >= 2.6 like this:
flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l
Modify cmListFileLexer.c:
- remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c
- remove blank lines at end of file: sed -i '${/^$/d;}' cmListFileLexer.c
- #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmListFileLexer.c
*/
/* IWYU pragma: no_forward_declare yyguts_t */
#ifdef _WIN32
#include "cmsys/Encoding.h"
#endif
/* Setup the proper cmListFileLexer_yylex declaration. */
#define YY_EXTRA_TYPE cmListFileLexer*
#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer)
#include "cmListFileLexer.h"
/*--------------------------------------------------------------------------*/
struct cmListFileLexer_s
{
cmListFileLexer_Token token;
int bracket;
int comment;
int line;
int column;
int size;
FILE* file;
size_t cr;
char* string_buffer;
char* string_position;
int string_left;
yyscan_t scanner;
};
static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
int length);
static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
int length);
static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
size_t bufferSize);
static void cmListFileLexerInit(cmListFileLexer* lexer);
static void cmListFileLexerDestroy(cmListFileLexer* lexer);
/* Replace the lexer input function. */
#undef YY_INPUT
#define YY_INPUT(buf, result, max_size) \
do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0)
/*--------------------------------------------------------------------------*/
%}
%option prefix="cmListFileLexer_yy"
%option reentrant
%option yylineno
%option noyywrap
%pointer
%x STRING
%x BRACKET
%x BRACKETEND
%x COMMENT
MAKEVAR \$\([A-Za-z0-9_]*\)
UNQUOTED ([^ \0\t\r\n\(\)#\\\"[=]|\\[^\0\n])
LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\"
%%
<INITIAL,COMMENT>\n {
lexer->token.type = cmListFileLexer_Token_Newline;
cmListFileLexerSetToken(lexer, yytext, yyleng);
++lexer->line;
lexer->column = 1;
BEGIN(INITIAL);
return 1;
}
#?\[=*\[\n? {
const char* bracket = yytext;
lexer->comment = yytext[0] == '#';
if (lexer->comment) {
lexer->token.type = cmListFileLexer_Token_CommentBracket;
bracket += 1;
} else {
lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
}
cmListFileLexerSetToken(lexer, "", 0);
lexer->bracket = strchr(bracket+1, '[') - bracket;
if (yytext[yyleng-1] == '\n') {
++lexer->line;
lexer->column = 1;
} else {
lexer->column += yyleng;
}
BEGIN(BRACKET);
}
# {
lexer->column += yyleng;
BEGIN(COMMENT);
}
<COMMENT>[^\0\n]* {
lexer->column += yyleng;
}
\( {
lexer->token.type = cmListFileLexer_Token_ParenLeft;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
\) {
lexer->token.type = cmListFileLexer_Token_ParenRight;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
[A-Za-z_][A-Za-z0-9_]* {
lexer->token.type = cmListFileLexer_Token_Identifier;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
<BRACKET>\]=* {
/* Handle ]]====]=======]*/
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
if (yyleng == lexer->bracket) {
BEGIN(BRACKETEND);
}
}
<BRACKETEND>\] {
lexer->column += yyleng;
/* Erase the partial bracket from the token. */
lexer->token.length -= lexer->bracket;
lexer->token.text[lexer->token.length] = 0;
BEGIN(INITIAL);
return 1;
}
<BRACKET>([^]\0\n])+ {
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
}
<BRACKET,BRACKETEND>\n {
cmListFileLexerAppend(lexer, yytext, yyleng);
++lexer->line;
lexer->column = 1;
BEGIN(BRACKET);
}
<BRACKET,BRACKETEND>[^\0\n] {
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
BEGIN(BRACKET);
}
<BRACKET,BRACKETEND><<EOF>> {
lexer->token.type = cmListFileLexer_Token_BadBracket;
BEGIN(INITIAL);
return 1;
}
({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* {
lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* {
lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
\[ {
lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
\" {
lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
cmListFileLexerSetToken(lexer, "", 0);
lexer->column += yyleng;
BEGIN(STRING);
}
<STRING>([^\\\0\n\"]|\\[^\0\n])+ {
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
}
<STRING>\\\n {
/* Continuation: text is not part of string */
++lexer->line;
lexer->column = 1;
}
<STRING>\n {
cmListFileLexerAppend(lexer, yytext, yyleng);
++lexer->line;
lexer->column = 1;
}
<STRING>\" {
lexer->column += yyleng;
BEGIN(INITIAL);
return 1;
}
<STRING>[^\0\n] {
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
}
<STRING><<EOF>> {
lexer->token.type = cmListFileLexer_Token_BadString;
BEGIN(INITIAL);
return 1;
}
[ \t\r]+ {
lexer->token.type = cmListFileLexer_Token_Space;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
. {
lexer->token.type = cmListFileLexer_Token_BadCharacter;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
<<EOF>> {
lexer->token.type = cmListFileLexer_Token_None;
cmListFileLexerSetToken(lexer, 0, 0);
return 0;
}
%%
/*--------------------------------------------------------------------------*/
static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
int length)
{
/* Set the token line and column number. */
lexer->token.line = lexer->line;
lexer->token.column = lexer->column;
/* Use the same buffer if possible. */
if (lexer->token.text) {
if (text && length < lexer->size) {
strcpy(lexer->token.text, text);
lexer->token.length = length;
return;
}
free(lexer->token.text);
lexer->token.text = 0;
lexer->size = 0;
}
/* Need to extend the buffer. */
if (text) {
lexer->token.text = strdup(text);
lexer->token.length = length;
lexer->size = length + 1;
} else {
lexer->token.length = 0;
}
}
/*--------------------------------------------------------------------------*/
static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
int length)
{
char* temp;
int newSize;
/* If the appended text will fit in the buffer, do not reallocate. */
newSize = lexer->token.length + length + 1;
if (lexer->token.text && newSize <= lexer->size) {
strcpy(lexer->token.text + lexer->token.length, text);
lexer->token.length += length;
return;
}
/* We need to extend the buffer. */
temp = malloc(newSize);
if (lexer->token.text) {
memcpy(temp, lexer->token.text, lexer->token.length);
free(lexer->token.text);
}
memcpy(temp + lexer->token.length, text, length);
temp[lexer->token.length + length] = 0;
lexer->token.text = temp;
lexer->token.length += length;
lexer->size = newSize;
}
/*--------------------------------------------------------------------------*/
static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
size_t bufferSize)
{
if (lexer) {
if (lexer->file) {
/* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
does not convert newlines on all platforms. Move any
trailing CR to the start of the buffer for the next read. */
size_t cr = lexer->cr;
size_t n;
buffer[0] = '\r';
n = fread(buffer + cr, 1, bufferSize - cr, lexer->file);
if (n) {
char* o = buffer;
const char* i = buffer;
const char* e;
n += cr;
cr = (buffer[n - 1] == '\r') ? 1 : 0;
e = buffer + n - cr;
while (i != e) {
if (i[0] == '\r' && i[1] == '\n') {
++i;
}
*o++ = *i++;
}
n = o - buffer;
} else {
n = cr;
cr = 0;
}
lexer->cr = cr;
return n;
} else if (lexer->string_left) {
int length = lexer->string_left;
if ((int)bufferSize < length) {
length = (int)bufferSize;
}
memcpy(buffer, lexer->string_position, length);
lexer->string_position += length;
lexer->string_left -= length;
return length;
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
static void cmListFileLexerInit(cmListFileLexer* lexer)
{
if (lexer->file || lexer->string_buffer) {
cmListFileLexer_yylex_init(&lexer->scanner);
cmListFileLexer_yyset_extra(lexer, lexer->scanner);
}
}
/*--------------------------------------------------------------------------*/
static void cmListFileLexerDestroy(cmListFileLexer* lexer)
{
cmListFileLexerSetToken(lexer, 0, 0);
if (lexer->file || lexer->string_buffer) {
cmListFileLexer_yylex_destroy(lexer->scanner);
if (lexer->file) {
fclose(lexer->file);
lexer->file = 0;
}
if (lexer->string_buffer) {
free(lexer->string_buffer);
lexer->string_buffer = 0;
lexer->string_left = 0;
lexer->string_position = 0;
}
}
}
/*--------------------------------------------------------------------------*/
cmListFileLexer* cmListFileLexer_New(void)
{
cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
if (!lexer) {
return 0;
}
memset(lexer, 0, sizeof(*lexer));
lexer->line = 1;
lexer->column = 1;
return lexer;
}
/*--------------------------------------------------------------------------*/
void cmListFileLexer_Delete(cmListFileLexer* lexer)
{
cmListFileLexer_SetFileName(lexer, 0, 0);
free(lexer);
}
/*--------------------------------------------------------------------------*/
static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f)
{
unsigned char b[2];
if (fread(b, 1, 2, f) == 2) {
if (b[0] == 0xEF && b[1] == 0xBB) {
if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) {
return cmListFileLexer_BOM_UTF8;
}
} else if (b[0] == 0xFE && b[1] == 0xFF) {
/* UTF-16 BE */
return cmListFileLexer_BOM_UTF16BE;
} else if (b[0] == 0 && b[1] == 0) {
if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) {
return cmListFileLexer_BOM_UTF32BE;
}
} else if (b[0] == 0xFF && b[1] == 0xFE) {
fpos_t p;
fgetpos(f, &p);
if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) {
return cmListFileLexer_BOM_UTF32LE;
}
if (fsetpos(f, &p) != 0) {
return cmListFileLexer_BOM_Broken;
}
return cmListFileLexer_BOM_UTF16LE;
}
}
if (fseek(f, 0, SEEK_SET) != 0) {
return cmListFileLexer_BOM_Broken;
}
return cmListFileLexer_BOM_None;
}
/*--------------------------------------------------------------------------*/
int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
cmListFileLexer_BOM* bom)
{
int result = 1;
cmListFileLexerDestroy(lexer);
if (name) {
#ifdef _WIN32
wchar_t* wname = cmsysEncoding_DupToWide(name);
lexer->file = _wfopen(wname, L"rb");
free(wname);
#else
lexer->file = fopen(name, "rb");
#endif
if (lexer->file) {
if (bom) {
*bom = cmListFileLexer_ReadBOM(lexer->file);
}
} else {
result = 0;
}
}
cmListFileLexerInit(lexer);
return result;
}
/*--------------------------------------------------------------------------*/
int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
{
int result = 1;
cmListFileLexerDestroy(lexer);
if (text) {
int length = (int)strlen(text);
lexer->string_buffer = (char*)malloc(length + 1);
if (lexer->string_buffer) {
strcpy(lexer->string_buffer, text);
lexer->string_position = lexer->string_buffer;
lexer->string_left = length;
} else {
result = 0;
}
}
cmListFileLexerInit(lexer);
return result;
}
/*--------------------------------------------------------------------------*/
cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
{
if (!lexer->file && !lexer->string_buffer) {
return 0;
}
if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
return &lexer->token;
} else {
cmListFileLexer_SetFileName(lexer, 0, 0);
return 0;
}
}
/*--------------------------------------------------------------------------*/
long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
{
return lexer->line;
}
/*--------------------------------------------------------------------------*/
long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
{
return lexer->column;
}
/*--------------------------------------------------------------------------*/
const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
cmListFileLexer_Type type)
{
(void)lexer;
switch (type) {
case cmListFileLexer_Token_None:
return "nothing";
case cmListFileLexer_Token_Space:
return "space";
case cmListFileLexer_Token_Newline:
return "newline";
case cmListFileLexer_Token_Identifier:
return "identifier";
case cmListFileLexer_Token_ParenLeft:
return "left paren";
case cmListFileLexer_Token_ParenRight:
return "right paren";
case cmListFileLexer_Token_ArgumentUnquoted:
return "unquoted argument";
case cmListFileLexer_Token_ArgumentQuoted:
return "quoted argument";
case cmListFileLexer_Token_ArgumentBracket:
return "bracket argument";
case cmListFileLexer_Token_CommentBracket:
return "bracket comment";
case cmListFileLexer_Token_BadCharacter:
return "bad character";
case cmListFileLexer_Token_BadBracket:
return "unterminated bracket";
case cmListFileLexer_Token_BadString:
return "unterminated string";
}
return "unknown token";
}

View File

@@ -0,0 +1,89 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#if defined(__linux)
/* Needed for glibc < 2.12 */
// NOLINTNEXTLINE(bugprone-reserved-identifier)
# define _XOPEN_SOURCE 600
#endif
#if !defined(_POSIX_C_SOURCE) && !defined(_WIN32) && !defined(__sun) && \
!defined(__OpenBSD__)
/* POSIX APIs are needed */
// NOLINTNEXTLINE(bugprone-reserved-identifier)
# define _POSIX_C_SOURCE 200809L
#endif
#if defined(__sun) && defined(__GNUC__) && !defined(__cplusplus)
/* C sources: for fileno and strdup */
// NOLINTNEXTLINE(bugprone-reserved-identifier)
# define _XOPEN_SOURCE 600
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
/* For isascii */
// NOLINTNEXTLINE(bugprone-reserved-identifier)
# define _XOPEN_SOURCE 700
#endif
#include "cmsys/Configure.h" // IWYU pragma: keep
/* Disable some warnings. */
#if defined(_MSC_VER)
# pragma warning(disable : 4018)
# pragma warning(disable : 4127)
# pragma warning(disable : 4131)
# pragma warning(disable : 4244)
# pragma warning(disable : 4251)
# pragma warning(disable : 4267)
# pragma warning(disable : 4305)
# pragma warning(disable : 4309)
# pragma warning(disable : 4706)
# pragma warning(disable : 4786)
#endif
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wsign-compare"
# endif
# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 403
# pragma GCC diagnostic ignored "-Wsign-conversion"
# endif
#endif
#if defined(__LCC__)
# pragma diag_suppress 1873 /* comparison between signed and unsigned */
#endif
#if defined(__NVCOMPILER)
# pragma diag_suppress 111 /* statement is unreachable */
# pragma diag_suppress 550 /* variable set but never used */
#endif
/* Make sure isatty is available. */
#if defined(_WIN32) && !defined(__CYGWIN__)
# include <io.h>
# if defined(_MSC_VER)
# define isatty _isatty
# endif
#else
# include <unistd.h> // IWYU pragma: export
#endif
/* Make sure malloc and free are available on QNX. */
#ifdef __QNX__
# include <malloc.h>
#endif
/* Disable features we do not need. */
#define YY_NEVER_INTERACTIVE 1
#define YY_NO_INPUT 1
#define YY_NO_UNPUT 1
#define ECHO
#include <cm3p/kwiml/int.h>
typedef KWIML_INT_int8_t flex_int8_t;
typedef KWIML_INT_uint8_t flex_uint8_t;
typedef KWIML_INT_int16_t flex_int16_t;
typedef KWIML_INT_uint16_t flex_uint16_t;
typedef KWIML_INT_int32_t flex_int32_t;
typedef KWIML_INT_uint32_t flex_uint32_t;