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 "TjMessageHandler.h"
20 #include "tjlib-internal.h"
21 #include "ProjectFile.h"
24 FileInfo::FileInfo(ProjectFile* p, const QString& file, const QString& tp) :
34 if (m_file.right(2) == "/.")
36 m_f.reset(new QTextStream(stdin, IO_ReadOnly));
41 if ((m_fh = fopen(m_file, "r")) == 0)
43 m_f.reset(new QTextStream(m_fh, IO_ReadOnly));
47 tjWarning(i18n("Processing file \'%1\'").arg(m_file));
49 m_lineBuf = oldLineBuf = QString::null;
50 m_currLine = oldLine = 1;
60 if (fclose(m_fh) == EOF)
67 FileInfo::getC(bool expandMacros)
71 if (m_ungetBuf.isEmpty())
82 // Test for CR/LF Windows line breaks.
85 if (cb != QChar('\n'))
87 // Probably a MacOS LF only line break
88 m_ungetBuf.append(cb);
97 c = m_ungetBuf.last();
98 m_ungetBuf.pop_back();
99 if (c.unicode() == EOMacro)
101 m_macroStack.removeLast();
105 oldLineBuf = m_lineBuf;
113 if ((d = getC(false)) == '{')
115 // remove ${ from m_lineBuf;
116 oldLineBuf = m_lineBuf;
117 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 2);
123 // remove $( from m_lineBuf;
124 oldLineBuf = m_lineBuf;
125 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 2);
132 if ((e = getC(false)) == '{')
134 // Convert "$${" into "%{"
137 // $$ escapes $, so discard 2nd $
149 FileInfo::ungetC(QChar c)
151 oldLineBuf = m_lineBuf;
152 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 1);
153 m_ungetBuf.append(c);
157 FileInfo::nextToken(QString& token)
159 if (m_tokenTypeBuf != INVALID)
162 TokenType tt = m_tokenTypeBuf;
163 m_tokenTypeBuf = INVALID;
169 // skip blanks and comments
173 if (c.unicode() == EOFile)
181 /* This code skips c-style comments like the one you are just
183 if ((c = getC(false)) == '*')
189 oldLine = m_currLine;
192 while ((c = getC(false)) != '*')
196 oldLine = m_currLine;
199 else if (c.unicode() == EOFile)
201 errorMessage(i18n("Unterminated comment"));
205 } while ((c = getC(false)) != '/');
208 // This code skips C++-style comments like the one you are
216 // break missing on purpose
217 case '#': // Comments start with '#' and reach towards end of line
218 while ((c = getC(false)) != '\n' && c.unicode() != EOFile)
220 if (c.unicode() == EOFile)
222 // break missing on purpose
224 // Increase line counter only when not replaying a macro.
225 if (m_macroStack.isEmpty())
227 oldLine = m_currLine;
230 oldLineBuf = m_lineBuf;
240 // analyse non blank characters
244 if (c.unicode() == EOFile)
246 errorMessage(i18n("Unexpected end of file"));
249 else if (isalpha(c) || (c == '_') || (c == '!'))
252 while ((c = getC()).unicode() != EOFile &&
253 (isalnum(c) || (c == '_') || (c == '.') || (c == '!')))
258 if (token.contains('.'))
263 else if (c.isDigit())
265 // read first number (maybe a year)
267 while ((c = getC()).unicode() != EOFile && c.isDigit())
271 // this must be a ISO date yyyy-mm-dd[[-hh:mm:[ss]]-TZ]
272 getDateFragment(token, c);
275 errorMessage(i18n("Corrupted date"));
278 getDateFragment(token, c);
281 getDateFragment(token, c);
284 errorMessage(i18n("Corrupted date"));
287 getDateFragment(token, c);
289 getDateFragment(token, c);
294 /* Timezone can either be a name (ref.
295 * Utility::timezone2tz) or GMT[+-]hh:mm */
297 while ((c = getC()).unicode() != EOFile &&
298 (isalnum(c) || c == '+' || c == '-' || c == ':')
307 // must be a real number
309 while ((c = getC()).unicode() != EOFile && c.isDigit())
316 // must be a time (HH:MM)
318 for (int i = 0; i < 2; i++)
320 if ((c = getC()).unicode() != EOFile && c.isDigit())
324 errorMessage(i18n("2 digits minutes expected"));
336 else if (c == '\'' || c == '\"')
338 // single or double quoted string
341 while ((c = getC()).unicode() != EOFile &&
342 (escape || (c != delimiter)))
344 if ((c == '\n') && m_macroStack.isEmpty())
346 oldLine = m_currLine;
349 if (c == '\\' && !escape)
357 if (c.unicode() == EOFile)
359 errorMessage(i18n("Non terminated string"));
368 while ((c = getC(false)).unicode() != EOFile &&
369 (c != ']' || nesting > 0))
377 oldLine = m_currLine;
378 m_currLine++; // m_macroStack.isEmpty ??
382 if (c.unicode() == EOFile)
384 errorMessage(i18n("Non terminated macro definition"));
422 if ((c = getC()) == '=')
425 return GREATEROREQUAL;
432 if ((c = getC()) == '=')
435 return SMALLEROREQUAL;
445 errorMessage(i18n("Illegal character '%1'").arg(c));
453 FileInfo::errorMessage(const QString& msg)
455 if (m_macroStack.isEmpty())
457 if (m_tokenTypeBuf == INVALID)
458 TJMH.errorMessage(QString("%1\n%2").arg(msg)
459 .arg(cleanupLine(m_lineBuf)),
462 TJMH.errorMessage(QString("%1\n%2").arg(msg)
463 .arg(cleanupLine(oldLineBuf)),
472 for (QPtrListIterator<Macro> mli(m_macroStack); *mli; ++mli, ++i)
474 stackDump += "\n ${" + (*mli)->getName() + " ... }";
476 file = (*mli)->getFile();
477 line = (*mli)->getLine();
479 TJMH.errorMessage(i18n("Error in expanded macro\n%1\n%2"
480 "\nThis is the macro call stack:%3").
481 arg(msg).arg(cleanupLine(m_lineBuf)).arg(stackDump),
487 FileInfo::warningMessage(const QString& msg)
489 if (m_macroStack.isEmpty())
491 if (m_tokenTypeBuf == INVALID)
492 TJMH.warningMessage(QString("%1\n%2").arg(msg)
493 .arg(cleanupLine(m_lineBuf)),
496 TJMH.warningMessage(QString("%1\n%2").arg(msg)
497 .arg(cleanupLine(oldLineBuf)),
506 for (QPtrListIterator<Macro> mli(m_macroStack); *mli; ++mli, ++i)
508 stackDump += "\n ${" + (*mli)->getName() + " ... }";
510 file = (*mli)->getFile();
511 line = (*mli)->getLine();
513 TJMH.warningMessage(i18n("Warning in expanded macro\n%1\n%2"
514 "\nThis is the macro call stack:%3").
515 arg(msg).arg(cleanupLine(m_lineBuf)).arg(stackDump),
520 void FileInfo::setLocation(const QString& df, int dl)
522 pf->getMacros().setLocation(df, dl);
525 QString FileInfo::resolve(const QStringList* argList)
527 return pf->getMacros().resolve(argList);
530 Macro* FileInfo::getMacro(const QString& name) const
532 return pf->getMacros().getMacro(name);