OSDN Git Service

Removing redundant error checking related to booking declaration.
[tjqt4port/tj2qt4.git] / taskjuggler / FileInfo.cpp
1 /*
2  * FileInfo.cpp - TaskJuggler
3  *
4  * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
5  * Chris Schlaeger <cs@kde.org>
6  *
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.
10  *
11  * $Id$
12  */
13
14 #include "FileInfo.h"
15
16 #include <ctype.h>
17 #include <stdlib.h>
18
19 #include "TjMessageHandler.h"
20 #include "tjlib-internal.h"
21 #include "ProjectFile.h"
22 #include "debug.h"
23
24 FileInfo::FileInfo(ProjectFile* p, const QString& file, const QString& tp) :
25     FileToken(file, tp),
26     pf(p),
27     oldLineBuf(),
28     oldLine(0)
29 { }
30
31 bool
32 FileInfo::open()
33 {
34     if (m_file.right(2) == "/.")
35     {
36         m_f.reset(new QTextStream(stdin, IO_ReadOnly));
37         m_fh = stdin;
38     }
39     else
40     {
41         if ((m_fh = fopen(m_file, "r")) == 0)
42             return false;
43         m_f.reset(new QTextStream(m_fh, IO_ReadOnly));
44     }
45
46     if (DEBUGLEVEL > 0)
47         tjWarning(i18n("Processing file \'%1\'").arg(m_file));
48
49     m_lineBuf = oldLineBuf = QString::null;
50     m_currLine = oldLine = 1;
51     return true;
52 }
53
54 bool
55 FileInfo::close()
56 {
57     if (m_fh == stdin)
58         return true;
59
60     if (fclose(m_fh) == EOF)
61         return false;
62
63     return true;
64 }
65
66 QChar
67 FileInfo::getC(bool expandMacros)
68 {
69  BEGIN:
70     QChar c;
71     if (m_ungetBuf.isEmpty())
72     {
73         if (feof(m_fh))
74             c = QChar(EOFile);
75         else
76         {
77             *m_f >> c;
78             if (c == QChar('\r'))
79             {
80                 if (!feof(m_fh))
81                 {
82                     // Test for CR/LF Windows line breaks.
83                     QChar cb;
84                     *m_f >> cb;
85                     if (cb != QChar('\n'))
86                     {
87                         // Probably a MacOS LF only line break
88                         m_ungetBuf.append(cb);
89                     }
90                 }
91                 c = QChar('\n');
92             }
93         }
94     }
95     else
96     {
97         c = m_ungetBuf.last();
98         m_ungetBuf.pop_back();
99         if (c.unicode() == EOMacro)
100         {
101             m_macroStack.removeLast();
102             goto BEGIN;
103         }
104     }
105     oldLineBuf = m_lineBuf;
106     m_lineBuf += c;
107
108     if (expandMacros)
109     {
110         if (c == '$')
111         {
112             QChar d;
113             if ((d = getC(false)) == '{')
114             {
115                 // remove ${ from m_lineBuf;
116                 oldLineBuf = m_lineBuf;
117                 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 2);
118                 readMacroCall();
119                 goto BEGIN;
120             }
121             else if (d == '(')
122             {
123                 // remove $( from m_lineBuf;
124                 oldLineBuf = m_lineBuf;
125                 m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 2);
126                 readEnvironment();
127                 goto BEGIN;
128             }
129             else if (d == '$')
130             {
131                 QChar e;
132                 if ((e = getC(false)) == '{')
133                 {
134                     // Convert "$${" into "%{"
135                     c = '%';
136                 }
137                 // $$ escapes $, so discard 2nd $
138                 ungetC(e);
139             }
140             else
141                 ungetC(d);
142         }
143     }
144
145     return c;
146 }
147
148 void
149 FileInfo::ungetC(QChar c)
150 {
151     oldLineBuf = m_lineBuf;
152     m_lineBuf = m_lineBuf.left(m_lineBuf.length() - 1);
153     m_ungetBuf.append(c);
154 }
155
156 TokenType
157 FileInfo::nextToken(QString& token)
158 {
159     if (m_tokenTypeBuf != INVALID)
160     {
161         token = m_tokenBuf;
162         TokenType tt = m_tokenTypeBuf;
163         m_tokenTypeBuf = INVALID;
164         return tt;
165     }
166
167     token = "";
168
169     // skip blanks and comments
170     for ( ; ; )
171     {
172         QChar c = getC();
173         if (c.unicode() == EOFile)
174             return EndOfFile;
175         switch (c)
176         {
177         case ' ':
178         case '\t':
179             break;
180         case '/':
181             /* This code skips c-style comments like the one you are just
182              * reading. */
183             if ((c = getC(false)) == '*')
184             {
185                 do
186                 {
187                     if (c == '\n')
188                     {
189                         oldLine = m_currLine;
190                         m_currLine++;
191                     }
192                     while ((c = getC(false)) != '*')
193                     {
194                         if (c == '\n')
195                         {
196                             oldLine = m_currLine;
197                             m_currLine++;
198                         }
199                         else if (c.unicode() == EOFile)
200                         {
201                             errorMessage(i18n("Unterminated comment"));
202                             return EndOfFile;
203                         }
204                     }
205                 } while ((c = getC(false)) != '/');
206                 break;
207             }
208             // This code skips C++-style comments like the one you are
209             // reading here.
210             else if (c != '/')
211             {
212                 ungetC(c);
213                 ungetC('/');
214                 goto BLANKS_DONE;
215             }
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)
219                 ;
220             if (c.unicode() == EOFile)
221                 return EndOfFile;
222             // break missing on purpose
223         case '\n':
224             // Increase line counter only when not replaying a macro.
225             if (m_macroStack.isEmpty())
226             {
227                 oldLine = m_currLine;
228                 m_currLine++;
229             }
230             oldLineBuf = m_lineBuf;
231             m_lineBuf = "";
232             break;
233         default:
234             ungetC(c);
235             goto BLANKS_DONE;
236         }
237     }
238  BLANKS_DONE:
239
240     // analyse non blank characters
241     for ( ; ; )
242     {
243         QChar c = getC();
244         if (c.unicode() == EOFile)
245         {
246             errorMessage(i18n("Unexpected end of file"));
247             return EndOfFile;
248         }
249         else if (isalpha(c) || (c == '_') || (c == '!'))
250         {
251             token += c;
252             while ((c = getC()).unicode() != EOFile &&
253                    (isalnum(c) || (c == '_') || (c == '.') || (c == '!')))
254                 token += c;
255             ungetC(c);
256             if (token[0] == '!')
257                 return RELATIVE_ID;
258             if (token.contains('.'))
259                 return ABSOLUTE_ID;
260             else
261                 return ID;
262         }
263         else if (c.isDigit())
264         {
265             // read first number (maybe a year)
266             token += c;
267             while ((c = getC()).unicode() != EOFile && c.isDigit())
268                 token += c;
269             if (c == '-')
270             {
271                 // this must be a ISO date yyyy-mm-dd[[-hh:mm:[ss]]-TZ]
272                 getDateFragment(token, c);
273                 if (c != '-')
274                 {
275                     errorMessage(i18n("Corrupted date"));
276                     return EndOfFile;
277                 }
278                 getDateFragment(token, c);
279                 if (c == '-')
280                 {
281                     getDateFragment(token, c);
282                     if (c != ':')
283                     {
284                         errorMessage(i18n("Corrupted date"));
285                         return EndOfFile;
286                     }
287                     getDateFragment(token, c);
288                     if (c == ':')
289                         getDateFragment(token, c);
290                 }
291                 int i = 0;
292                 if (c == '-')
293                 {
294                     /* Timezone can either be a name (ref.
295                      * Utility::timezone2tz) or GMT[+-]hh:mm */
296                     token += c;
297                     while ((c = getC()).unicode() != EOFile &&
298                            (isalnum(c) || c == '+' || c == '-' || c == ':')
299                            && i++ < 9)
300                         token += c;
301                 }
302                 ungetC(c);
303                 return DATE;
304             }
305             else if (c == '.')
306             {
307                 // must be a real number
308                 token += c;
309                 while ((c = getC()).unicode() != EOFile && c.isDigit())
310                     token += c;
311                 ungetC(c);
312                 return REAL;
313             }
314             else if (c == ':')
315             {
316                 // must be a time (HH:MM)
317                 token += c;
318                 for (int i = 0; i < 2; i++)
319                 {
320                     if ((c = getC()).unicode() != EOFile && c.isDigit())
321                         token += c;
322                     else
323                     {
324                         errorMessage(i18n("2 digits minutes expected"));
325                         return EndOfFile;
326                     }
327                 }
328                 return HOUR;
329             }
330             else
331             {
332                 ungetC(c);
333                 return INTEGER;
334             }
335         }
336         else if (c == '\'' || c == '\"')
337         {
338             // single or double quoted string
339             QChar delimiter = c;
340             bool escape = false;
341             while ((c = getC()).unicode() != EOFile &&
342                    (escape || (c != delimiter)))
343             {
344                 if ((c == '\n') && m_macroStack.isEmpty())
345                 {
346                     oldLine = m_currLine;
347                     m_currLine++;
348                 }
349                 if (c == '\\' && !escape)
350                     escape = true;
351                 else
352                 {
353                     escape = false;
354                     token += c;
355                 }
356             }
357             if (c.unicode() == EOFile)
358             {
359                 errorMessage(i18n("Non terminated string"));
360                 return EndOfFile;
361             }
362             return STRING;
363         }
364         else if (c == '[')
365         {
366             token = "";
367             int nesting = 0;
368             while ((c = getC(false)).unicode() != EOFile &&
369                    (c != ']' || nesting > 0))
370             {
371                 if (c == '[')
372                     nesting++;
373                 else if (c == ']')
374                     nesting--;
375                 if (c == '\n')
376                 {
377                     oldLine = m_currLine;
378                     m_currLine++; // m_macroStack.isEmpty ??
379                 }
380                 token += c;
381             }
382             if (c.unicode() == EOFile)
383             {
384                 errorMessage(i18n("Non terminated macro definition"));
385                 return EndOfFile;
386             }
387             return MacroBody;
388         }
389         else
390         {
391             token += c;
392             switch (c)
393             {
394             case '{':
395                 return LBRACE;
396             case '}':
397                 return RBRACE;
398             case '(':
399                 return LBRACKET;
400             case ')':
401                 return RBRACKET;
402             case ',':
403                 return COMMA;
404             case '%':
405                 return PERCENT;
406             case '~':
407                 return TILDE;
408             case ':':
409                 return COLON;
410             case '?':
411                 return QUESTIONMARK;
412             case '+':
413                 return PLUS;
414             case '-':
415                 return MINUS;
416             case '&':
417                 return AND;
418             case '|':
419                 return OR;
420             case '>':
421             {
422                 if ((c = getC()) == '=')
423                 {
424                     token += c;
425                     return GREATEROREQUAL;
426                 }
427                 ungetC(c);
428                 return GREATER;
429             }
430             case '<':
431             {
432                 if ((c = getC()) == '=')
433                 {
434                     token += c;
435                     return SMALLEROREQUAL;
436                 }
437                 ungetC(c);
438                 return SMALLER;
439             }
440             case '=':
441                 return EQUAL;
442             case '*':
443                 return STAR;
444             default:
445                 errorMessage(i18n("Illegal character '%1'").arg(c));
446                 return INVALID;
447             }
448         }
449     }
450 }
451
452 void
453 FileInfo::errorMessage(const QString& msg)
454 {
455     if (m_macroStack.isEmpty())
456     {
457         if (m_tokenTypeBuf == INVALID)
458             TJMH.errorMessage(QString("%1\n%2").arg(msg)
459                               .arg(cleanupLine(m_lineBuf)),
460                               m_file, m_currLine);
461         else
462             TJMH.errorMessage(QString("%1\n%2").arg(msg)
463                               .arg(cleanupLine(oldLineBuf)),
464                               m_file, oldLine);
465     }
466     else
467     {
468         QString stackDump;
469         int i = 0;
470         QString file;
471         int line = 0;
472         for (QPtrListIterator<Macro> mli(m_macroStack); *mli; ++mli, ++i)
473         {
474             stackDump += "\n  ${" + (*mli)->getName() + " ... }";
475
476             file = (*mli)->getFile();
477             line = (*mli)->getLine();
478         }
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),
482                           file, line);
483     }
484 }
485
486 void
487 FileInfo::warningMessage(const QString& msg)
488 {
489     if (m_macroStack.isEmpty())
490     {
491         if (m_tokenTypeBuf == INVALID)
492             TJMH.warningMessage(QString("%1\n%2").arg(msg)
493                                 .arg(cleanupLine(m_lineBuf)),
494                                 m_file, m_currLine);
495         else
496             TJMH.warningMessage(QString("%1\n%2").arg(msg)
497                                 .arg(cleanupLine(oldLineBuf)),
498                                 m_file, oldLine);
499     }
500     else
501     {
502         QString stackDump;
503         int i = 0;
504         QString file;
505         int line = 0;
506         for (QPtrListIterator<Macro> mli(m_macroStack); *mli; ++mli, ++i)
507         {
508             stackDump += "\n  ${" + (*mli)->getName() + " ... }";
509
510             file = (*mli)->getFile();
511             line = (*mli)->getLine();
512         }
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),
516                             file, line);
517     }
518 }
519
520 void FileInfo::setLocation(const QString& df, int dl)
521 {
522     pf->getMacros().setLocation(df, dl);
523 }
524
525 QString FileInfo::resolve(const QStringList* argList)
526 {
527     return pf->getMacros().resolve(argList);
528 }
529
530 Macro* FileInfo::getMacro(const QString& name) const
531 {
532     return pf->getMacros().getMacro(name);
533 }