/****************************************************************************+ −
**+ −
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (qt-info@nokia.com)+ −
**+ −
** This file is part of the tools applications of the Qt Toolkit.+ −
**+ −
** $QT_BEGIN_LICENSE:LGPL$+ −
** No Commercial Usage+ −
** This file contains pre-release code and may not be distributed.+ −
** You may use this file in accordance with the terms and conditions+ −
** contained in the Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** GNU Lesser General Public License Usage+ −
** Alternatively, this file may be used under the terms of the GNU Lesser+ −
** General Public License version 2.1 as published by the Free Software+ −
** Foundation and appearing in the file LICENSE.LGPL included in the+ −
** packaging of this file. Please review the following information to+ −
** ensure the GNU Lesser General Public License version 2.1 requirements+ −
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.+ −
**+ −
** In addition, as a special exception, Nokia gives you certain additional+ −
** rights. These rights are described in the Nokia Qt LGPL Exception+ −
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.+ −
**+ −
** If you have questions regarding the use of this file, please contact+ −
** Nokia at qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $QT_END_LICENSE$+ −
**+ −
****************************************************************************/+ −
+ −
#include <QtDebug>+ −
#include "config.h"+ −
#include "location.h"+ −
+ −
#include <qregexp.h>+ −
#include <qtranslator.h>+ −
#include <stdlib.h>+ −
#include <limits.h>+ −
+ −
#include <stdio.h>+ −
+ −
QT_BEGIN_NAMESPACE+ −
+ −
QT_STATIC_CONST_IMPL Location Location::null;+ −
+ −
int Location::tabSize;+ −
QString Location::programName;+ −
QRegExp *Location::spuriousRegExp = 0;+ −
+ −
/*!+ −
\class Location+ −
+ −
\brief The Location class keeps track of where we are in a file.+ −
+ −
It maintains a stack of file positions. A file position + −
consists of the file path, line number, and column number.+ −
The location is used for printing error messages that are+ −
tied to a location in a file.+ −
*/+ −
+ −
/*!+ −
Constructs an empty location.+ −
*/+ −
Location::Location()+ −
: stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)+ −
{+ −
// nothing.+ −
}+ −
+ −
/*!+ −
Constructs a location with (fileName, 1, 1) on its file+ −
position stack.+ −
*/+ −
Location::Location(const QString& fileName)+ −
: stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)+ −
{+ −
push(fileName);+ −
}+ −
+ −
/*!+ −
The copy constructor copies the contents of \a other into+ −
this Location using the assignment operator.+ −
*/+ −
Location::Location(const Location& other)+ −
: stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)+ −
{+ −
*this = other;+ −
}+ −
+ −
/*!+ −
The assignment operator does a deep copy of the entire+ −
state of \a other into this Location.+ −
*/+ −
Location& Location::operator=(const Location& other)+ −
{+ −
QStack<StackEntry> *oldStk = stk;+ −
+ −
stkBottom = other.stkBottom;+ −
if (other.stk == 0) {+ −
stk = 0;+ −
stkTop = &stkBottom;+ −
}+ −
else {+ −
stk = new QStack<StackEntry>(*other.stk);+ −
stkTop = &stk->top();+ −
}+ −
stkDepth = other.stkDepth;+ −
etcetera = other.etcetera;+ −
delete oldStk;+ −
return *this;+ −
}+ −
+ −
/*!+ −
If the file position on top of the stack has a line number+ −
less than 1, set its line number to 1 and its column number+ −
to 1. Otherwise, do nothing.+ −
*/+ −
void Location::start()+ −
{+ −
if (stkTop->lineNo < 1) {+ −
stkTop->lineNo = 1;+ −
stkTop->columnNo = 1;+ −
}+ −
}+ −
+ −
/*!+ −
Advance the current file position, using \a ch to decide how to do+ −
that. If \a ch is a \c{'\\n'}, increment the current line number and+ −
set the column number to 1. If \ch is a \c{'\\t'}, increment to the+ −
next tab column. Otherwise, increment the column number by 1.+ −
+ −
The current file position is the one on top of the position stack.+ −
*/+ −
void Location::advance(QChar ch)+ −
{+ −
if (ch == QLatin1Char('\n')) {+ −
stkTop->lineNo++;+ −
stkTop->columnNo = 1;+ −
}+ −
else if (ch == QLatin1Char('\t')) {+ −
stkTop->columnNo =+ −
1 + tabSize * (stkTop->columnNo + tabSize-1) / tabSize;+ −
}+ −
else {+ −
stkTop->columnNo++;+ −
}+ −
}+ −
+ −
/*!+ −
Pushes \a filePath onto the file position stack. The current+ −
file position becomes (\a filePath, 1, 1).+ −
+ −
\sa pop()+ −
*/+ −
void Location::push(const QString& filePath)+ −
{+ −
if (stkDepth++ >= 1) {+ −
if (stk == 0)+ −
stk = new QStack<StackEntry>;+ −
stk->push(StackEntry());+ −
stkTop = &stk->top();+ −
}+ −
+ −
stkTop->filePath = filePath;+ −
stkTop->lineNo = INT_MIN;+ −
stkTop->columnNo = 1;+ −
}+ −
+ −
/*!+ −
Pops the top of the internal stack. The current file position+ −
becomes the next one in the new top of stack.+ −
+ −
\sa push()+ −
*/+ −
void Location::pop()+ −
{+ −
if (--stkDepth == 0) {+ −
stkBottom = StackEntry();+ −
}+ −
else {+ −
stk->pop();+ −
if (stk->isEmpty()) {+ −
delete stk;+ −
stk = 0;+ −
stkTop = &stkBottom;+ −
}+ −
else {+ −
stkTop = &stk->top();+ −
}+ −
}+ −
}+ −
+ −
/*! \fn bool Location::isEmpty() const+ −
+ −
Returns true if there is no file name set yet; returns false+ −
otherwise. The functions filePath(), lineNo() and columnNo()+ −
must not be called on an empty Location object.+ −
*/+ −
+ −
/*! \fn const QString& Location::filePath() const+ −
Returns the current path and file name.+ −
Must not be called on an empty Location object.+ −
+ −
\sa lineNo(), columnNo()+ −
*/+ −
+ −
/*!+ −
Returns the file name part of the file path, ie the+ −
current file. Must not be called on an empty Location+ −
object.+ −
*/+ −
QString Location::fileName() const+ −
{+ −
QString fp = filePath();+ −
return fp.mid(fp.lastIndexOf('/') + 1);+ −
}+ −
+ −
/*! \fn int Location::lineNo() const+ −
Returns the current line number.+ −
Must not be called on an empty Location object.+ −
+ −
\sa filePath(), columnNo()+ −
*/+ −
+ −
/*! \fn int Location::columnNo() const+ −
Returns the current column number.+ −
Must not be called on an empty Location object.+ −
+ −
\sa filePath(), lineNo()+ −
*/+ −
+ −
/*!+ −
Writes \a message and \a detals to stderr as a formatted+ −
warning message.+ −
*/+ −
void Location::warning(const QString& message, const QString& details) const+ −
{+ −
emitMessage(Warning, message, details);+ −
}+ −
+ −
/*!+ −
Writes \a message and \a detals to stderr as a formatted+ −
error message.+ −
*/+ −
void Location::error(const QString& message, const QString& details) const+ −
{+ −
emitMessage(Error, message, details);+ −
}+ −
+ −
/*!+ −
Writes \a message and \a detals to stderr as a formatted+ −
error message and then exits the program.+ −
*/+ −
void Location::fatal(const QString& message, const QString& details) const+ −
{+ −
emitMessage(Error, message, details);+ −
information(message);+ −
information(details);+ −
information("Aborting");+ −
exit(EXIT_FAILURE);+ −
}+ −
+ −
/*!+ −
Gets several parameters from the \a config, including+ −
tab size, program name, and a regular expression that+ −
appears to be used for matching certain error messages+ −
so that emitMessage() can avoid printing them.+ −
*/+ −
void Location::initialize(const Config& config)+ −
{+ −
tabSize = config.getInt(CONFIG_TABSIZE);+ −
programName = config.programName();+ −
+ −
QRegExp regExp = config.getRegExp(CONFIG_SPURIOUS);+ −
if (regExp.isValid()) {+ −
spuriousRegExp = new QRegExp(regExp);+ −
}+ −
else {+ −
config.lastLocation().warning(tr("Invalid regular expression '%1'")+ −
.arg(regExp.pattern()));+ −
}+ −
}+ −
+ −
/*!+ −
Apparently, all this does is delete the regular expression+ −
used for intercepting certain error messages that should+ −
not be emitted by emitMessage().+ −
*/+ −
void Location::terminate()+ −
{+ −
delete spuriousRegExp;+ −
spuriousRegExp = 0;+ −
}+ −
+ −
/*!+ −
Prints \a message to \c stdout followed by a \c{'\n'}.+ −
*/+ −
void Location::information(const QString& message)+ −
{+ −
printf("%s\n", message.toLatin1().data());+ −
fflush(stdout);+ −
}+ −
+ −
/*!+ −
Report a program bug, including the \a hint. + −
*/+ −
void Location::internalError(const QString& hint)+ −
{+ −
Location::null.fatal(tr("Internal error (%1)").arg(hint),+ −
tr("There is a bug in %1. Seek advice from your local"+ −
" %2 guru.")+ −
.arg(programName).arg(programName));+ −
}+ −
+ −
/*!+ −
Formats \a message and \a details into a single string+ −
and outputs that string to \c stderr. \a type specifies+ −
whether the \a message is an error or a warning.+ −
*/+ −
void Location::emitMessage(MessageType type,+ −
const QString& message,+ −
const QString& details) const+ −
{+ −
if (type == Warning &&+ −
spuriousRegExp != 0 &&+ −
spuriousRegExp->exactMatch(message))+ −
return;+ −
+ −
QString result = message;+ −
if (!details.isEmpty())+ −
result += "\n[" + details + "]";+ −
result.replace("\n", "\n ");+ −
if (type == Error)+ −
result.prepend(tr("error: "));+ −
result.prepend(toString());+ −
fprintf(stderr, "%s\n", result.toLatin1().data());+ −
fflush(stderr);+ −
}+ −
+ −
/*!+ −
Converts the location to a string to be prepended to error+ −
messages. + −
*/+ −
QString Location::toString() const+ −
{+ −
QString str;+ −
+ −
if (isEmpty()) {+ −
str = programName;+ −
}+ −
else {+ −
Location loc2 = *this;+ −
loc2.setEtc(false);+ −
loc2.pop();+ −
if (!loc2.isEmpty()) {+ −
QString blah = tr("In file included from ");+ −
for (;;) {+ −
str += blah;+ −
str += loc2.top();+ −
loc2.pop();+ −
if (loc2.isEmpty())+ −
break;+ −
str += tr(",");+ −
str += QLatin1Char('\n');+ −
blah.fill(' ');+ −
}+ −
str += tr(":");+ −
str += QLatin1Char('\n');+ −
}+ −
str += top();+ −
}+ −
str += QLatin1String(": ");+ −
return str;+ −
}+ −
+ −
QString Location::top() const+ −
{+ −
QString str = filePath();+ −
if (lineNo() >= 1) {+ −
str += QLatin1Char(':'); + −
str += QString::number(lineNo());+ −
#if 0+ −
if (columnNo() >= 1)+ −
str += ":" + QString::number(columnNo());+ −
#endif+ −
}+ −
if (etc())+ −
str += QLatin1String(" (etc.)");+ −
return str;+ −
}+ −
+ −
QT_END_NAMESPACE+ −