source: trunk/tools/qdoc3/location.cpp@ 814

Last change on this file since 814 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 10.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtDebug>
43#include "config.h"
44#include "location.h"
45
46#include <qregexp.h>
47#include <qtranslator.h>
48#include <stdlib.h>
49#include <limits.h>
50
51#include <stdio.h>
52
53QT_BEGIN_NAMESPACE
54
55QT_STATIC_CONST_IMPL Location Location::null;
56
57int Location::tabSize;
58QString Location::programName;
59QRegExp *Location::spuriousRegExp = 0;
60
61/*!
62 \class Location
63
64 \brief The Location class keeps track of where we are in a file.
65
66 It maintains a stack of file positions. A file position
67 consists of the file path, line number, and column number.
68 The location is used for printing error messages that are
69 tied to a location in a file.
70 */
71
72/*!
73 Constructs an empty location.
74 */
75Location::Location()
76 : stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)
77{
78 // nothing.
79}
80
81/*!
82 Constructs a location with (fileName, 1, 1) on its file
83 position stack.
84 */
85Location::Location(const QString& fileName)
86 : stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)
87{
88 push(fileName);
89}
90
91/*!
92 The copy constructor copies the contents of \a other into
93 this Location using the assignment operator.
94 */
95Location::Location(const Location& other)
96 : stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)
97{
98 *this = other;
99}
100
101/*!
102 The assignment operator does a deep copy of the entire
103 state of \a other into this Location.
104 */
105Location& Location::operator=(const Location& other)
106{
107 QStack<StackEntry> *oldStk = stk;
108
109 stkBottom = other.stkBottom;
110 if (other.stk == 0) {
111 stk = 0;
112 stkTop = &stkBottom;
113 }
114 else {
115 stk = new QStack<StackEntry>(*other.stk);
116 stkTop = &stk->top();
117 }
118 stkDepth = other.stkDepth;
119 etcetera = other.etcetera;
120 delete oldStk;
121 return *this;
122}
123
124/*!
125 If the file position on top of the stack has a line number
126 less than 1, set its line number to 1 and its column number
127 to 1. Otherwise, do nothing.
128 */
129void Location::start()
130{
131 if (stkTop->lineNo < 1) {
132 stkTop->lineNo = 1;
133 stkTop->columnNo = 1;
134 }
135}
136
137/*!
138 Advance the current file position, using \a ch to decide how to do
139 that. If \a ch is a \c{'\\n'}, increment the current line number and
140 set the column number to 1. If \ch is a \c{'\\t'}, increment to the
141 next tab column. Otherwise, increment the column number by 1.
142
143 The current file position is the one on top of the position stack.
144 */
145void Location::advance(QChar ch)
146{
147 if (ch == QLatin1Char('\n')) {
148 stkTop->lineNo++;
149 stkTop->columnNo = 1;
150 }
151 else if (ch == QLatin1Char('\t')) {
152 stkTop->columnNo =
153 1 + tabSize * (stkTop->columnNo + tabSize-1) / tabSize;
154 }
155 else {
156 stkTop->columnNo++;
157 }
158}
159
160/*!
161 Pushes \a filePath onto the file position stack. The current
162 file position becomes (\a filePath, 1, 1).
163
164 \sa pop()
165*/
166void Location::push(const QString& filePath)
167{
168 if (stkDepth++ >= 1) {
169 if (stk == 0)
170 stk = new QStack<StackEntry>;
171 stk->push(StackEntry());
172 stkTop = &stk->top();
173 }
174
175 stkTop->filePath = filePath;
176 stkTop->lineNo = INT_MIN;
177 stkTop->columnNo = 1;
178}
179
180/*!
181 Pops the top of the internal stack. The current file position
182 becomes the next one in the new top of stack.
183
184 \sa push()
185*/
186void Location::pop()
187{
188 if (--stkDepth == 0) {
189 stkBottom = StackEntry();
190 }
191 else {
192 stk->pop();
193 if (stk->isEmpty()) {
194 delete stk;
195 stk = 0;
196 stkTop = &stkBottom;
197 }
198 else {
199 stkTop = &stk->top();
200 }
201 }
202}
203
204/*! \fn bool Location::isEmpty() const
205
206 Returns true if there is no file name set yet; returns false
207 otherwise. The functions filePath(), lineNo() and columnNo()
208 must not be called on an empty Location object.
209 */
210
211/*! \fn const QString& Location::filePath() const
212 Returns the current path and file name.
213 Must not be called on an empty Location object.
214
215 \sa lineNo(), columnNo()
216 */
217
218/*!
219 Returns the file name part of the file path, ie the
220 current file. Must not be called on an empty Location
221 object.
222 */
223QString Location::fileName() const
224{
225 QString fp = filePath();
226 return fp.mid(fp.lastIndexOf('/') + 1);
227}
228
229/*! \fn int Location::lineNo() const
230 Returns the current line number.
231 Must not be called on an empty Location object.
232
233 \sa filePath(), columnNo()
234*/
235
236/*! \fn int Location::columnNo() const
237 Returns the current column number.
238 Must not be called on an empty Location object.
239
240 \sa filePath(), lineNo()
241*/
242
243/*!
244 Writes \a message and \a detals to stderr as a formatted
245 warning message.
246 */
247void Location::warning(const QString& message, const QString& details) const
248{
249 emitMessage(Warning, message, details);
250}
251
252/*!
253 Writes \a message and \a detals to stderr as a formatted
254 error message.
255 */
256void Location::error(const QString& message, const QString& details) const
257{
258 emitMessage(Error, message, details);
259}
260
261/*!
262 Writes \a message and \a detals to stderr as a formatted
263 error message and then exits the program.
264 */
265void Location::fatal(const QString& message, const QString& details) const
266{
267 emitMessage(Error, message, details);
268 information("Aborting");
269 exit(EXIT_FAILURE);
270}
271
272/*!
273 Gets several parameters from the \a config, including
274 tab size, program name, and a regular expression that
275 appears to be used for matching certain error messages
276 so that emitMessage() can avoid printing them.
277 */
278void Location::initialize(const Config& config)
279{
280 tabSize = config.getInt(CONFIG_TABSIZE);
281 programName = config.programName();
282
283 QRegExp regExp = config.getRegExp(CONFIG_SPURIOUS);
284 if (regExp.isValid()) {
285 spuriousRegExp = new QRegExp(regExp);
286 }
287 else {
288 config.lastLocation().warning(tr("Invalid regular expression '%1'")
289 .arg(regExp.pattern()));
290 }
291}
292
293/*!
294 Apparently, all this does is delete the regular expression
295 used for intercepting certain error messages that should
296 not be emitted by emitMessage().
297 */
298void Location::terminate()
299{
300 delete spuriousRegExp;
301 spuriousRegExp = 0;
302}
303
304/*!
305 Prints \a message to \c stdout followed by a \c{'\n'}.
306 */
307void Location::information(const QString& message)
308{
309 printf("%s\n", message.toLatin1().data());
310 fflush(stdout);
311}
312
313/*!
314 Report a program bug, including the \a hint.
315 */
316void Location::internalError(const QString& hint)
317{
318 Location::null.fatal(tr("Internal error (%1)").arg(hint),
319 tr("There is a bug in %1. Seek advice from your local"
320 " %2 guru.")
321 .arg(programName).arg(programName));
322}
323
324/*!
325 Formats \a message and \a details into a single string
326 and outputs that string to \c stderr. \a type specifies
327 whether the \a message is an error or a warning.
328 */
329void Location::emitMessage(MessageType type,
330 const QString& message,
331 const QString& details) const
332{
333 if (type == Warning &&
334 spuriousRegExp != 0 &&
335 spuriousRegExp->exactMatch(message))
336 return;
337
338 QString result = message;
339 if (!details.isEmpty())
340 result += "\n[" + details + "]";
341 result.replace("\n", "\n ");
342 if (type == Error)
343 result.prepend(tr("error: "));
344 result.prepend(toString());
345 fprintf(stderr, "%s\n", result.toLatin1().data());
346 fflush(stderr);
347}
348
349/*!
350 Converts the location to a string to be prepended to error
351 messages.
352 */
353QString Location::toString() const
354{
355 QString str;
356
357 if (isEmpty()) {
358 str = programName;
359 }
360 else {
361 Location loc2 = *this;
362 loc2.setEtc(false);
363 loc2.pop();
364 if (!loc2.isEmpty()) {
365 QString blah = tr("In file included from ");
366 for (;;) {
367 str += blah;
368 str += loc2.top();
369 loc2.pop();
370 if (loc2.isEmpty())
371 break;
372 str += tr(",");
373 str += QLatin1Char('\n');
374 blah.fill(' ');
375 }
376 str += tr(":");
377 str += QLatin1Char('\n');
378 }
379 str += top();
380 }
381 str += QLatin1String(": ");
382 return str;
383}
384
385QString Location::top() const
386{
387 QString str = filePath();
388 if (lineNo() >= 1) {
389 str += QLatin1Char(':');
390 str += QString::number(lineNo());
391#if 0
392 if (columnNo() >= 1)
393 str += ":" + QString::number(columnNo());
394#endif
395 }
396 if (etc())
397 str += QLatin1String(" (etc.)");
398 return str;
399}
400
401QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.