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