2 * FileInfo.cpp - TaskJuggler
4 * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
5 * Chris Schlaeger <cs@kde.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
19 #include <QTextStream>
21 #include "TjMessageHandler.h"
22 #include "tjlib-internal.h"
23 #include "ProjectFile.h"
26 FileInfo::FileInfo(ProjectFile* p, const QString& file, const QString& tp) :
36 if (m_file.right(2) == "/.")
38 m_f.reset(new QTextStream(stdin, QIODevice::ReadOnly));
43 if ((m_fh = fopen(m_file, "r")) == 0)
45 m_f.reset(new QTextStream(m_fh, QIODevice::ReadOnly));
49 tjWarning(i18n("Processing file \'%1\'").arg(m_file));
51 m_lineBuf = oldLineBuf = QString::null;
52 m_currLine = oldLine = 1;
62 if (fclose(m_fh) == EOF)
69 FileInfo::getC(bool expandMacros)
73 if (m_ungetBuf.isEmpty())
84 // Test for CR/LF Windows line breaks.
87 if (cb != QChar('\n'))
89 // Probably a MacOS LF only line break
90 m_ungetBuf.append(cb);
99 c = m_ungetBuf.last();
100 m_ungetBuf.pop_back();
101 if (c.unicode() == EOMacro)
103 m_macroStack.removeLast();
107 oldLineBuf = m_lineBuf;
115 if ((d = getC(false)) == '{')
117 // remove ${ from m_lineBuf;
118 oldLineBuf = m_lineBuf;
119 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 2);
125 // remove $( from m_lineBuf;
126 oldLineBuf = m_lineBuf;
127 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 2);
134 if ((e = getC(false)) == '{')
136 // Convert "$${" into "%{"
139 // $$ escapes $, so discard 2nd $
151 FileInfo::ungetC(QChar c)
153 oldLineBuf = m_lineBuf;
154 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 1);
155 m_ungetBuf.append(c);
159 FileInfo::nextToken(QString& token)
161 if (m_tokenTypeBuf != INVALID)
164 TokenType tt = m_tokenTypeBuf;
165 m_tokenTypeBuf = INVALID;
171 // skip blanks and comments
175 if (c.unicode() == EOFile)
183 /* This code skips c-style comments like the one you are just
185 if ((c = getC(false)) == '*')
191 oldLine = m_currLine;
194 while ((c = getC(false)) != '*')
198 oldLine = m_currLine;
201 else if (c.unicode() == EOFile)
203 errorMessage(i18n("Unterminated comment"));
207 } while ((c = getC(false)) != '/');
210 // This code skips C++-style comments like the one you are
218 // break missing on purpose
219 case '#': // Comments start with '#' and reach towards end of line
220 while ((c = getC(false)) != '\n' && c.unicode() != EOFile)
222 if (c.unicode() == EOFile)
224 // break missing on purpose
226 // Increase line counter only when not replaying a macro.
227 if (m_macroStack.isEmpty())
229 oldLine = m_currLine;
232 oldLineBuf = m_lineBuf;
242 // analyse non blank characters
246 if (c.unicode() == EOFile)
248 errorMessage(i18n("Unexpected end of file"));
251 else if (c.isLetter() || (c == '_') || (c == '!'))
254 while ((c = getC()).unicode() != EOFile &&
255 (c.isLetterOrNumber() || (c == '_') || (c == '.') || (c == '!')))
260 if (token.contains('.'))
265 else if (c.isDigit())
267 // read first number (maybe a year)
269 while ((c = getC()).unicode() != EOFile && c.isDigit())
273 // this must be a ISO date yyyy-mm-dd[[-hh:mm:[ss]]-TZ]
274 getDateFragment(token, c);
277 errorMessage(i18n("Corrupted date"));
280 getDateFragment(token, c);
283 getDateFragment(token, c);
286 errorMessage(i18n("Corrupted date"));
289 getDateFragment(token, c);
291 getDateFragment(token, c);
296 /* Timezone can either be a name (ref.
297 * Utility::timezone2tz) or GMT[+-]hh:mm */
299 while ((c = getC()).unicode() != EOFile &&
300 (c.isLetterOrNumber() || c == '+' || c == '-' || c == ':')
309 // must be a real number
311 while ((c = getC()).unicode() != EOFile && c.isDigit())
318 // must be a time (HH:MM)
320 for (int i = 0; i < 2; i++)
322 if ((c = getC()).unicode() != EOFile && c.isDigit())
326 errorMessage(i18n("2 digits minutes expected"));
338 else if (c == '\'' || c == '\"')
340 // single or double quoted string
343 while ((c = getC()).unicode() != EOFile &&
344 (escape || (c != delimiter)))
346 if ((c == '\n') && m_macroStack.isEmpty())
348 oldLine = m_currLine;
351 if (c == '\\' && !escape)
359 if (c.unicode() == EOFile)
361 errorMessage(i18n("Non terminated string"));
370 while ((c = getC(false)).unicode() != EOFile &&
371 (c != ']' || nesting > 0))
379 oldLine = m_currLine;
380 m_currLine++; // m_macroStack.isEmpty ??
384 if (c.unicode() == EOFile)
386 errorMessage(i18n("Non terminated macro definition"));
424 if ((c = getC()) == '=')
427 return GREATEROREQUAL;
434 if ((c = getC()) == '=')
437 return SMALLEROREQUAL;
447 errorMessage(i18n("Illegal character '%1'").arg(c));
455 FileInfo::errorMessage(const QString& msg)
457 if (m_macroStack.isEmpty())
459 if (m_tokenTypeBuf == INVALID)
460 TJMH.errorMessage(QString("%1\n%2").arg(msg)
461 .arg(cleanupLine(m_lineBuf)),
464 TJMH.errorMessage(QString("%1\n%2").arg(msg)
465 .arg(cleanupLine(oldLineBuf)),
474 for (Q3PtrListIterator<Macro> mli(m_macroStack); *mli; ++mli, ++i)
476 stackDump += "\n ${" + (*mli)->getName() + " ... }";
478 file = (*mli)->getFile();
479 line = (*mli)->getLine();
481 TJMH.errorMessage(i18n("Error in expanded macro\n%1\n%2"
482 "\nThis is the macro call stack:%3").
483 arg(msg).arg(cleanupLine(m_lineBuf)).arg(stackDump),
489 FileInfo::warningMessage(const QString& msg)
491 if (m_macroStack.isEmpty())
493 if (m_tokenTypeBuf == INVALID)
494 TJMH.warningMessage(QString("%1\n%2").arg(msg)
495 .arg(cleanupLine(m_lineBuf)),
498 TJMH.warningMessage(QString("%1\n%2").arg(msg)
499 .arg(cleanupLine(oldLineBuf)),
508 for (Q3PtrListIterator<Macro> mli(m_macroStack); *mli; ++mli, ++i)
510 stackDump += "\n ${" + (*mli)->getName() + " ... }";
512 file = (*mli)->getFile();
513 line = (*mli)->getLine();
515 TJMH.warningMessage(i18n("Warning in expanded macro\n%1\n%2"
516 "\nThis is the macro call stack:%3").
517 arg(msg).arg(cleanupLine(m_lineBuf)).arg(stackDump),
522 void FileInfo::setLocation(const QString& df, int dl)
524 pf->getMacros().setLocation(df, dl);
527 QString FileInfo::resolve(const QStringList* argList)
529 return pf->getMacros().resolve(argList);
532 Macro* FileInfo::getMacro(const QString& name) const
534 return pf->getMacros().getMacro(name);