1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the porting application of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "preprocessorcontrol.h"
33
#include <QTemporaryFile>
34
using namespace TokenEngine;
37
IncludeFiles::IncludeFiles(const QString &basePath, const QStringList &searchPaths)
40
//prepend basePath to all relative paths in searchPaths
41
foreach (QString path, searchPaths) {
43
if (QDir::isAbsolutePath(path))
44
finalPath = QDir::cleanPath(path);
46
finalPath = QDir::cleanPath(m_basePath + "/" + path);
48
if(QFile::exists(finalPath))
49
m_searchPaths.append(finalPath);
54
Performs an #include "..." style file lookup.
55
Aboslute filenames are checked directly. Relative filenames are first
56
looked for relative to the current file path, then the includepaths
57
are searched if not found.
59
QString IncludeFiles::quoteLookup(const QString ¤tFile,
60
const QString &includeFile) const
62
//if includeFile is absolute, check if it exists
63
if(QDir::isAbsolutePath(includeFile))
64
if(QFile::exists(includeFile))
69
//If currentFile is not an absolute file path, make it one by
70
//prepending m_baspath
71
QString currentFilePath;
72
if(QDir::isAbsolutePath(currentFile))
73
currentFilePath = currentFile;
75
currentFilePath = QDir::cleanPath(m_basePath + "/" + currentFile);
77
//Check if it includeFile exists in the same dir as currentFilePath
78
const QString currentPath = QFileInfo(currentFilePath).path();
79
QString localFile = QDir::cleanPath(currentPath + "/" + includeFile);
80
if(QFile::exists(localFile))
83
return searchIncludePaths(includeFile);
87
Performs an #include <...> style file lookup.
88
Aboslute filenames are checked directly.
89
Relative paths are searched for in the includepaths.
91
QString IncludeFiles::angleBracketLookup(const QString &includeFile) const
93
//if includeFile is absolute, check if it exists
94
if(QDir::isAbsolutePath(includeFile))
95
if(QFile::exists(includeFile))
100
return searchIncludePaths(includeFile);
103
QString IncludeFiles::resolve(const QString &filename) const
105
if(QDir::isAbsolutePath(filename))
108
QString prepended = QDir::cleanPath(m_basePath + "/" + filename);
109
if(QFile::exists(prepended))
117
Searches for includeFile paths by appending it to all includePaths
118
and checking if the file exists. Returns QString() if the file is not
121
QString IncludeFiles::searchIncludePaths(const QString &includeFile) const
124
foreach(QString includePath, m_searchPaths) {
125
QString testFile = includePath + "/" + includeFile;
126
if(QFile::exists(testFile)){
127
foundFile = testFile;
134
QByteArray PreprocessorCache::readFile(const QString &filename) const
136
// If anybody is connected to the readFile signal we tell them to
137
// read the file for us.
138
if (receivers(SIGNAL(readFile(QByteArray &, QString))) > 0) {
140
// Workaround for "not beeing able to emit from const function"
141
PreprocessorCache *cache = const_cast<PreprocessorCache *>(this);
142
emit cache->readFile(array, filename);
149
f.open(QIODevice::ReadOnly);
155
PreprocessorCache::PreprocessorCache()
157
connect(&m_preprocessor, SIGNAL(error(QString,QString)),
158
this, SIGNAL(error(QString,QString)));
163
Return a TokenSequence with the contents of filname.
164
Assumens filename exists and is readable, returns a empty
165
TokenSequence if not.
167
The result is cached.
169
TokenContainer PreprocessorCache::sourceTokens(const QString &filename)
171
// Check if the source tokens are already in the cache.
172
if(m_sourceTokens.contains(filename))
173
return m_sourceTokens.value(filename);
175
// Read and tokenize file.
176
QByteArray fileContents = readFile(filename);
177
if(fileContents == QByteArray())
178
return TokenContainer();
180
QVector<TokenEngine::Token> tokenList = m_tokenizer.tokenize(fileContents);
182
// Create a FileInfo object that holds the filename for this container.
183
FileInfo *containterFileInfo = new FileInfo;
184
containterFileInfo->filename = filename;
187
TokenContainer tokenContainer(fileContents, tokenList, containterFileInfo);
189
// Insert into cache.
190
m_sourceTokens.insert(filename, tokenContainer);
191
return tokenContainer;
195
Return a Source* tree representing the contents of filename.
196
Assumens filename exists and is readable, returns a empty
197
Source object if not.
199
The result is cached.
201
Source *PreprocessorCache::sourceTree(const QString &filename)
203
// Check if the Rpp tree for this file is already in the cache.
204
if(m_sourceTrees.contains(filename))
205
return m_sourceTrees.value(filename);
207
// Get the tokens for the contents of this file.
208
TokenContainer tokenContainer = sourceTokens(filename);
210
// Run lexer and the preprocessor-parser.
211
QVector<Type> tokenTypes = m_lexer.lex(tokenContainer);
212
Source *source = m_preprocessor.parse(tokenContainer, tokenTypes, &m_memoryPool);
213
source->setFileName(filename);
215
// Insert into cache.
216
if(tokenContainer.count() > 0) //don't cache empty files.
217
m_sourceTrees.insert(filename, source);
224
Returns whether the cache contains a TokenContainer for the given filename.
226
bool PreprocessorCache::containsSourceTokens(const QString &filename)
228
return m_sourceTokens.contains(filename);
232
Returns whether the cache contains a Preprocessor tree for the given filename.
234
bool PreprocessorCache::containsSourceTree(const QString &filename)
236
return m_sourceTrees.contains(filename);
239
PreprocessorController::PreprocessorController(IncludeFiles includeFiles,
240
PreprocessorCache &preprocessorCache,
241
QStringList preLoadFilesFilenames)
242
:m_includeFiles(includeFiles),
243
m_preprocessorCache(preprocessorCache)
245
// Load qt3 headers from resources. The headers are stored as
246
// QHash<QString, QByteArray>, serialized using QDataStream. The hash
247
// maps filename -> contents.
248
if (preLoadFilesFilenames != QStringList()) {
249
foreach (QString filename, preLoadFilesFilenames) {
251
if (f.open(QIODevice::ReadOnly)) {
252
QByteArray buffer = f.readAll();
254
QDataStream stream(buffer);
255
QHash<QString, QByteArray> files;
257
m_preLoadFiles.unite(files);
262
//connect include callback
263
connect(&m_rppTreeEvaluator,
264
SIGNAL(includeCallback(Source *&, const Source *,
265
const QString &, RppTreeEvaluator::IncludeType)),
266
SLOT(includeSlot(Source *&, const Source *,
267
const QString &, RppTreeEvaluator::IncludeType)));
269
// connect readFile callback
270
connect(&m_preprocessorCache, SIGNAL(readFile(QByteArray &, QString)),
271
SLOT(readFile(QByteArray &, QString)));
273
//connect error handlers
274
connect(&m_preprocessorCache , SIGNAL(error(QString,QString)),
275
this, SIGNAL(error(QString,QString)));
279
Callback from RppTreeEvaluator, called when we evaluate an #include
280
directive. We do a filename lookup based on the type of include, and then ask
281
the cache to give us the source tree for that file.
283
void PreprocessorController::includeSlot(Source *&includee,
284
const Source *includer,
285
const QString &filename,
286
RppTreeEvaluator::IncludeType includeType)
289
if(includeType == RppTreeEvaluator::QuoteInclude)
290
newFilename = m_includeFiles.quoteLookup(includer->fileName(), filename);
291
else //AngleBracketInclude
292
newFilename = m_includeFiles.angleBracketLookup(filename);
294
if (QFile::exists(newFilename)) {
295
includee = m_preprocessorCache.sourceTree(newFilename);
299
if (m_preLoadFiles.contains(filename)) {
300
includee = m_preprocessorCache.sourceTree(filename);
304
includee = m_preprocessorCache.sourceTree(newFilename);
305
emit error("Error", "Could not find file " + filename);
309
Callback connected to preprocessorCache. Tries to load a file from
310
m_preLoadFiles before going to disk.
312
void PreprocessorController::readFile(QByteArray &contents, QString filename)
314
if (m_preLoadFiles.contains(filename)) {
315
contents = m_preLoadFiles.value(filename);
322
f.open(QIODevice::ReadOnly);
325
contents = f.readAll();
329
Preprocess file give by filename. Filename is resloved agains the basepath
332
TokenSectionSequence PreprocessorController::evaluate(const QString &filename, Rpp::DefineMap *activedefinitions)
334
QString resolvedFilename = m_includeFiles.resolve(filename);
335
if(!QFile::exists(resolvedFilename))
336
emit error("Error", "Could not find file: " + filename);
337
Source *source = m_preprocessorCache.sourceTree(resolvedFilename);
339
return m_rppTreeEvaluator.evaluate(source, activedefinitions);
342
QByteArray defaultDefines =
343
"#define __attribute__(a...) \n \
344
#define __attribute__ \n \
345
#define __extension \n \
346
#define __extension__ \n \
347
#define __restrict \n \
348
#define __restrict__ \n \
349
#define __volatile volatile\n \
350
#define __volatile__ volatile\n \
351
#define __inline inline\n \
352
#define __inline__ inline\n \
353
#define __const const\n \
354
#define __const__ const\n \
355
#define __asm asm\n \
356
#define __asm__ asm\n \
357
#define __GNUC__ 2\n \
358
#define __GNUC_MINOR__ 95\n \
359
#define __cplusplus \n \
360
#define __linux__ \n";
364
Returns a DefineMap containing the above macro definitions. The DefineMap
365
will contain pointers to data stored in the provided cache object.
367
Rpp::DefineMap *defaultMacros(PreprocessorCache &cache)
369
DefineMap *defineMap = new DefineMap();
370
//write out defualt macros to a temp file
371
QTemporaryFile tempfile;
373
tempfile.write(defaultDefines);
375
IncludeFiles *includeFiles = new IncludeFiles(QString(), QStringList());
376
PreprocessorController preprocessorController(*includeFiles, cache);
377
//evaluate default macro file.
378
preprocessorController.evaluate(tempfile.fileName(), defineMap);
383
void StandardOutErrorHandler::error(QString type, QString text)
386
cout << qPrintable(text) << endl;
390
RppPreprocessor is a convenience class that contains all the components
391
needed to preprocess files. Error messages are printed to standard out.
393
RppPreprocessor::RppPreprocessor(QString basePath, QStringList includePaths, QStringList preLoadFilesFilenames)
394
:m_includeFiles(basePath, includePaths)
395
,m_activeDefinitions(defaultMacros(m_cache))
396
,m_controller(m_includeFiles, m_cache, preLoadFilesFilenames)
398
QObject::connect(&m_controller, SIGNAL(error(QString, QString)), &m_errorHandler, SLOT(error(QString, QString)));
401
RppPreprocessor::~RppPreprocessor()
403
delete m_activeDefinitions;
406
TokenEngine::TokenSectionSequence RppPreprocessor::evaluate(const QString &filename)
408
DefineMap defMap = *m_activeDefinitions;
409
return m_controller.evaluate(filename, &defMap);