Fix for UBSan build
[platform/upstream/doxygen.git] / src / pre.l
1 /******************************************************************************
2  *
3  * 
4  *
5  * Copyright (C) 1997-2012 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby 
9  * granted. No representations are made about the suitability of this software 
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 %{
19
20 /*
21  *      includes
22  */
23
24 #include <stdio.h>
25 #include <assert.h>
26 #include <ctype.h>
27 #include <errno.h>
28
29 #include "qtbc.h"
30 #include <qarray.h>
31 #include <qstack.h>
32 #include <qfile.h>
33 #include <qstrlist.h>
34 #include <qdict.h>
35 #include <qregexp.h>
36 #include <qfileinfo.h>
37 #include <qdir.h>
38   
39 #include "pre.h"
40 #include "constexp.h"
41 #include "define.h"
42 #include "doxygen.h"
43 #include "message.h"
44 #include "util.h"
45 #include "defargs.h"
46 #include "debug.h"
47 #include "bufstr.h"
48 #include "portable.h"
49 #include "bufstr.h"
50 #include "arguments.h"
51 #include "entry.h"
52
53 #define YY_NEVER_INTERACTIVE 1
54   
55
56 struct FileState
57 {
58   FileState(int size) : fileBuf(size), 
59                         oldFileBuf(0), oldFileBufPos(0) {}
60   int lineNr;
61   BufStr fileBuf;
62   BufStr *oldFileBuf;
63   int oldFileBufPos;
64   YY_BUFFER_STATE bufState;
65   QCString fileName;
66 };  
67
68 /** @brief Singleton that manages the defines available while 
69  *  proprocessing files. 
70  */
71 class DefineManager
72 {
73   /** Local class used to hold the defines for a single file */
74   class DefinesPerFile
75   {
76     public:
77       /** Creates an empty container for defines */
78       DefinesPerFile() : m_defines(257), m_includedFiles(17)
79       {
80         m_defines.setAutoDelete(TRUE);
81       }
82       /** Destroys the object */
83       virtual ~DefinesPerFile()
84       {
85       }
86       /** Adds a define in the context of a file. Will replace 
87        *  an existing define with the same name (redefinition)
88        *  @param def The Define object to add.
89        */
90       void addDefine(Define *def)
91       {
92         Define *d = m_defines.find(def->name);
93         if (d!=0) // redefine
94         {
95           m_defines.remove(d->name);
96         }
97         m_defines.insert(def->name,def);
98       }
99       /** Adds an include file for this file 
100        *  @param fileName The name of the include file
101        */
102       void addInclude(const char *fileName)
103       {
104         m_includedFiles.insert(fileName,(void*)0x8);
105       }
106       void collectDefines(DefineDict *dict,QDict<void> &includeStack);
107     private:
108       DefineDict m_defines;
109       QDict<void> m_includedFiles;
110   };
111
112   public:
113     friend class DefinesPerFile;
114     /** Returns a reference to the singleton */
115     static DefineManager &instance()
116     {
117       if (theInstance==0) theInstance = new DefineManager;
118       return *theInstance;
119     }
120     /** Deletes the singleton */
121     static void deleteInstance()
122     {
123       delete theInstance;
124       theInstance = 0;
125     }
126     /** Starts a context in which defines are collected. 
127      *  Called at the start of a new file that is preprocessed.
128      *  @param fileName the name of the file to process.
129      */
130     void startContext(const char *fileName)
131     {
132       //printf("DefineManager::startContext()\n");
133       m_contextDefines.clear();
134       if (fileName==0) return;
135       DefinesPerFile *dpf = m_fileMap.find(fileName);
136       if (dpf==0)
137       {
138         //printf("New file!\n");
139         dpf = new DefinesPerFile;
140         m_fileMap.insert(fileName,dpf);
141       }
142     }
143     /** Ends the context started with startContext() freeing any
144      *  defines collected within in this context.
145      */
146     void endContext()
147     {
148       //printf("DefineManager::endContext()\n");
149       m_contextDefines.clear();
150     }
151     /** Add an included file to the current context.
152      *  If the file has been pre-processed already, all defines are added
153      *  to the context.
154      *  @param fileName The name of the include file to add to the context.
155      */
156     void addFileToContext(const char *fileName)
157     {
158       if (fileName==0) return;
159       //printf("DefineManager::addFileToContext(%s)\n",fileName);
160       DefinesPerFile *dpf = m_fileMap.find(fileName);
161       if (dpf==0)
162       {
163         //printf("New file!\n");
164         dpf = new DefinesPerFile;
165         m_fileMap.insert(fileName,dpf);
166       }
167       else
168       {
169         //printf("existing file!\n");
170         QDict<void> includeStack(17);
171         dpf->collectDefines(&m_contextDefines,includeStack);
172       }
173     }
174
175     /** Add a define to the manager object.
176      *  @param fileName The file in which the define was found
177      *  @param def The Define object to add.
178      */
179     void addDefine(const char *fileName,Define *def)
180     {
181       if (fileName==0) return;
182       //printf("DefineManager::addDefine(%s,%s)\n",fileName,def->name.data());
183       Define *d = m_contextDefines.find(def->name);
184       if (d!=0) // redefine
185       {
186         m_contextDefines.remove(d->name);
187       }
188       m_contextDefines.insert(def->name,def);
189
190       DefinesPerFile *dpf = m_fileMap.find(fileName);
191       if (dpf==0)
192       {
193         dpf = new DefinesPerFile;
194       }
195       dpf->addDefine(def);
196     }
197
198     /** Add an include relation to the manager object.
199      *  @param fromFileName file name in which the include was found.
200      *  @param toFileName file name that is included.
201      */
202     void addInclude(const char *fromFileName,const char *toFileName)
203     {
204       //printf("DefineManager::addInclude(%s,%s)\n",fromFileName,toFileName);
205       if (fromFileName==0 || toFileName==0) return;
206       DefinesPerFile *dpf = m_fileMap.find(fromFileName);
207       if (dpf==0)
208       {
209         dpf = new DefinesPerFile;
210       }
211       dpf->addInclude(toFileName);
212     }
213     /** Returns a Define object given its name or 0 if the Define does
214      *  not exist.
215      */
216     Define *isDefined(const char *name) const
217     {
218       return m_contextDefines.find(name);
219     }
220     /** Returns a reference to the defines found in the current context. */
221     const DefineDict &defineContext() const
222     {
223       return m_contextDefines;
224     }
225   private:
226     static DefineManager *theInstance;
227
228     /** Helper function to collect all define for a given file */
229     void collectDefinesForFile(const char *fileName,DefineDict *dict)
230     {
231       if (fileName==0) return;
232       DefinesPerFile *dpf = m_fileMap.find(fileName);
233       if (dpf)
234       {
235         QDict<void> includeStack(17);
236         dpf->collectDefines(dict,includeStack);
237       }
238     }
239
240     /** Helper function to return the DefinesPerFile object for a given file name. */
241     DefinesPerFile *find(const char *fileName) const
242     {
243       if (fileName==0) return 0;
244       return m_fileMap.find(fileName);
245     }
246
247     /** Creates a new DefineManager object */
248     DefineManager() : m_fileMap(1009), m_contextDefines(1009)
249     {
250       m_fileMap.setAutoDelete(TRUE);
251     }
252
253     /** Destroys the object */
254     virtual ~DefineManager() 
255     {
256     }
257
258     QDict<DefinesPerFile> m_fileMap;
259     DefineDict m_contextDefines;
260 };
261
262 /** Singleton instance */
263 DefineManager *DefineManager::theInstance = 0;
264
265 /** Collects all defines for a file and all files that the file includes.
266  *  This function will recursively call itself for each file.
267  *  @param dict The dictionary to fill with the defines. A redefine will
268  *         replace a previous definition.
269  *  @param includeStack The stack of includes, used to stop recursion in
270  *         case there is a cyclic include dependency.
271  */
272 void DefineManager::DefinesPerFile::collectDefines(
273                      DefineDict *dict,QDict<void> &includeStack)
274 {
275   //printf("DefinesPerFile::collectDefines #defines=%d\n",m_defines.count());
276   {
277     QDictIterator<void> di(m_includedFiles);
278     for (di.toFirst();(di.current());++di)
279     {
280       QCString incFile = di.currentKey();
281       DefinesPerFile *dpf = DefineManager::instance().find(incFile);
282       if (dpf && includeStack.find(incFile)==0) 
283       {
284         //printf("  processing include %s\n",incFile.data());
285         includeStack.insert(incFile,(void*)0x8);
286         dpf->collectDefines(dict,includeStack);
287       }
288     }
289   }
290   {
291     QDictIterator<Define> di(m_defines);
292     Define *def;
293     for (di.toFirst();(def=di.current());++di)
294     {
295       Define *d = dict->find(def->name);
296       if (d!=0) // redefine
297       {
298         dict->remove(d->name);
299       }
300       dict->insert(def->name,def);
301       //printf("  adding define %s\n",def->name.data());
302     }
303   }
304 }
305
306 /* -----------------------------------------------------------------
307  *
308  *      scanner's state
309  */
310
311 static int                g_yyLineNr   = 1;
312 static QCString           g_yyFileName;
313 static FileDef           *g_yyFileDef;
314 static FileDef           *g_inputFileDef;
315 static int                g_ifcount    = 0;
316 static QStrList          *g_pathList = 0;  
317 static QStack<FileState>  g_includeStack;
318 static QDict<int>        *g_argDict;
319 static int                g_defArgs = -1;
320 static QCString           g_defName;
321 static QCString           g_defText;
322 static QCString           g_defLitText;
323 static QCString           g_defArgsStr;
324 static QCString           g_defExtraSpacing;
325 static bool               g_defVarArgs;
326 static int                g_level;
327 static int                g_lastCContext;
328 static int                g_lastCPPContext;
329 static QArray<int>        g_levelGuard;
330 static BufStr            *g_inputBuf;
331 static int                g_inputBufPos;
332 static BufStr            *g_outputBuf;
333 static int                g_roundCount;
334 static bool               g_quoteArg;
335 static DefineDict        *g_expandedDict;
336 static int                g_findDefArgContext;
337 static bool               g_expectGuard;
338 static QCString           g_guardName;
339 static QCString           g_lastGuardName;
340 static QCString           g_incName;
341 static QCString           g_guardExpr;
342 static int                g_curlyCount;
343 static bool               g_nospaces; // add extra spaces during macro expansion
344
345 static bool               g_macroExpansion; // from the configuration
346 static bool               g_expandOnlyPredef; // from the configuration
347 static int                g_commentCount;
348 static bool               g_insideComment;
349 static bool               g_isImported;
350 static QCString           g_blockName;
351 static int                g_condCtx;
352 static bool               g_skip;
353 static QStack<bool>       g_condStack;
354 static bool               g_insideCS; // C# has simpler preprocessor
355 static bool               g_isSource;
356
357 static bool               g_lexInit = FALSE;
358
359 //DefineDict* getGlobalDefineDict() 
360 //{
361 //  return g_globalDefineDict;
362 //}
363
364 static void setFileName(const char *name)
365 {
366   bool ambig;
367   QFileInfo fi(name);
368   g_yyFileName=convertToQCString(fi.absFilePath());
369   g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig);
370   if (g_yyFileDef==0) // if this is not an input file check if it is an
371                       // include file
372   {
373     g_yyFileDef=findFileDef(Doxygen::includeNameDict,g_yyFileName,ambig);
374   }
375   //printf("setFileName(%s) g_yyFileName=%s g_yyFileDef=%p\n",
376   //    name,g_yyFileName.data(),g_yyFileDef);
377   if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0;
378   g_insideCS = getLanguageFromFileName(g_yyFileName)==SrcLangExt_CSharp;
379   g_isSource = guessSection(g_yyFileName);
380 }
381
382 static void incrLevel()
383 {
384   g_level++;
385   g_levelGuard.resize(g_level);
386   g_levelGuard[g_level-1]=FALSE;
387   //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
388 }
389
390 static void decrLevel()
391 {
392   //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
393   if (g_level > 0)
394   {
395     g_level--;
396     g_levelGuard.resize(g_level);
397   }
398   else
399   {
400     warn(g_yyFileName,g_yyLineNr,"warning: More #endif's than #if's found.\n");
401   }
402 }
403
404 static bool otherCaseDone()
405 {
406   if (g_level==0)
407   {
408     warn(g_yyFileName,g_yyLineNr,"warning: Found an #else without a preceding #if.\n");
409     return TRUE;
410   }
411   else
412   {
413     return g_levelGuard[g_level-1];
414   }
415 }
416
417 static void setCaseDone(bool value)
418 {
419   g_levelGuard[g_level-1]=value;
420 }
421
422 #if 0
423 static bool macroIsAccessible(Define *def)
424 {
425   //printf("macroIsAccessible(%s) input=%s def=%s\n",
426   //    def->name.data(),g_inputFileDef?g_inputFileDef->name().data():"<none>",
427   //    def->fileDef ? def->fileDef->name().data() : "<none>");
428   if (def && def->isPredefined) // predefined macro -> globally accessible
429   {
430     //printf("%s: predefined macro %s\n",g_inputFileDef->name().data(),def->name.data());
431     return TRUE;
432   }
433   if (def && def->fileDef==g_inputFileDef)
434   {
435     //printf("%s: macro %s defined in this file at line %d now at %d\n",
436     //  g_inputFileDef->name().data(),def->name.data(),def->lineNr,g_yyLineNr);
437     return def->lineNr<=g_yyLineNr;
438   }
439   if (g_inputFileDef && def && def->fileDef) // check if g_inputFileDef actually includes def->fileDef
440   {
441     QDict<FileDef> includedFiles(257);
442     bool b = g_inputFileDef->includes(def->fileDef,&includedFiles);
443     //printf("%s: Checking for accessibility of define '%s' (defined in %s): result=%d\n",
444     //       g_inputFileDef->name().data(),def->name.data(),def->fileDef->name().data(),b);
445     return b;
446   }
447   if (g_inputFileDef && def && !def->fileName.isEmpty())
448   {
449     bool b = g_inputFileDef->includesByName(def->fileName);
450     //printf("%s: Checking for accessibility of define '%s' (defined in %s): result=%d\n",
451     //       g_inputFileDef->name().data(),def->name.data(),def->fileName.data(),b);
452     return b;
453   }
454   //printf("not accessible!\n");
455   return FALSE;
456 }
457
458 static Define *isDefined(const char *name)
459 {
460   Define *def=0;
461   if (name)
462   {
463     def=g_globalDefineDict->find(name);
464     if (def && def->undef) def=0;
465     if (def && !macroIsAccessible(def)) def=0;
466   }
467   //printf("isDefined(%s)=%p\n",name,def);
468   return def;
469 }
470 #endif
471
472
473 static QDict<void> g_allIncludes(10009);
474
475 static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded)
476 {
477   alreadyIncluded = FALSE;
478   FileState *fs = 0;
479   //printf("checkAndOpenFile(%s)\n",fileName.data());
480   QFileInfo fi(fileName);
481   if (fi.exists() && fi.isFile())
482   {
483     static QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
484     if (patternMatch(fi,&exclPatterns)) return 0;
485
486     QCString absName = convertToQCString(fi.absFilePath());
487
488     // global guard
489     if (g_curlyCount==0) // not #include inside { ... }
490     {
491       if (g_allIncludes.find(absName)!=0)
492       {
493         alreadyIncluded = TRUE;
494         //printf("  already included 1\n");
495         return 0; // already done
496       }
497       g_allIncludes.insert(absName,(void *)0x8);
498     }
499     // check include stack for absName
500
501     QStack<FileState> tmpStack;
502     g_includeStack.setAutoDelete(FALSE);
503     while ((fs=g_includeStack.pop()))
504     {
505       if (fs->fileName==absName) alreadyIncluded=TRUE;
506       tmpStack.push(fs);
507     }
508     while ((fs=tmpStack.pop()))
509     {
510       g_includeStack.push(fs);
511     }
512     g_includeStack.setAutoDelete(TRUE);
513
514     if (alreadyIncluded)
515     {
516       //printf("  already included 2\n");
517       return 0;
518     }
519     //printf("#include %s\n",absName.data());
520
521     fs = new FileState(fi.size()+4096);
522     alreadyIncluded = FALSE;
523     if (!readInputFile(absName,fs->fileBuf))
524     { // error
525       //printf("  error reading\n");
526       delete fs;
527       fs=0;
528     }
529     else
530     {
531       fs->oldFileBuf    = g_inputBuf;
532       fs->oldFileBufPos = g_inputBufPos;
533     }
534   }
535   return fs;
536 }
537
538 static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded)
539 {
540   //printf("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data());
541   if (localInclude && !g_yyFileName.isEmpty())
542   {
543     QFileInfo fi(g_yyFileName);
544     if (fi.exists())
545     {
546       QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName;
547       FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
548       if (fs)
549       {
550         setFileName(absName);
551         g_yyLineNr=1;
552         return fs;
553       }
554       else if (alreadyIncluded)
555       {
556         return 0;
557       }
558     }
559   }
560   if (g_pathList==0) 
561   {
562     return 0;
563   }
564   char *s=g_pathList->first();
565   while (s)
566   {
567     QCString absName = (QCString)s+"/"+fileName;
568     //printf("  Looking for %s in %s\n",fileName,s);
569     FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
570     if (fs)
571     {
572       setFileName(absName);
573       g_yyLineNr=1;
574       //printf("  -> found it\n");
575       return fs;
576     }
577     else if (alreadyIncluded)
578     {
579       return 0;
580     }
581
582     s=g_pathList->next();
583   } 
584   return 0;
585 }
586
587 static QCString extractTrailingComment(const char *s)
588 {
589   if (s==0) return "";
590   int i=strlen(s)-1;
591   while (i>=0)
592   {
593     char c=s[i];
594     switch (c)
595     {
596       case '/':
597         {
598           i--;
599           if (i>=0 && s[i]=='*') // end of a comment block
600           {
601             i--;
602             while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
603             if (i==0) 
604             {
605               i++;
606             }
607             // only /*!< or /**< are treated as a comment for the macro name,
608             // otherwise the comment is treated as part of the macro definition
609             return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : ""; 
610           }
611           else
612           {
613             return "";
614           }
615         } 
616         break;
617         // whitespace or line-continuation
618       case ' ':
619       case '\t': 
620       case '\r':
621       case '\n':
622       case '\\':
623         break;
624       default:
625         return "";
626     }
627     i--;
628   }
629   return "";
630 }
631
632 static int getNextChar(const QCString &expr,QCString *rest,uint &pos);
633 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos);
634 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c);
635 static void expandExpression(QCString &expr,QCString *rest,int pos);
636
637 static QCString stringize(const QCString &s)
638 {
639   QCString result;
640   uint i=0;
641   bool inString=FALSE;
642   bool inChar=FALSE;
643   char c,pc;
644   while (i<s.length())
645   {
646     if (!inString && !inChar)
647     {
648       while (i<s.length() && !inString && !inChar)
649       {
650         c=s.at(i++);
651         if (c=='"')
652         {
653           result+="\\\"";
654           inString=TRUE;
655         }
656         else if (c=='\'')
657         {
658           result+=c;
659           inChar=TRUE;
660         }
661         else
662         {
663           result+=c;
664         }
665       }
666     }
667     else if (inChar)
668     {
669       while (i<s.length() && inChar)
670       {
671         c=s.at(i++);
672         if (c=='\'')
673         {
674           result+='\'';
675           inChar=FALSE;
676         }
677         else if (c=='\\')
678         {
679           result+="\\\\";
680         }
681         else
682         {
683           result+=c;
684         }
685       }
686     }
687     else
688     {
689       pc=0;
690       while (i<s.length() && inString)
691       {
692         char c=s.at(i++);
693         if (c=='"') 
694         {
695           result+="\\\"";
696           inString= pc=='\\';
697         }
698         else if (c=='\\')
699           result+="\\\\";
700         else
701           result+=c;
702         pc=c;
703       }
704     }
705   }
706   //printf("stringize `%s'->`%s'\n",s.data(),result.data());
707   return result;
708 }
709
710 /*! Execute all ## operators in expr. 
711  * If the macro name before or after the operator contains a no-rescan 
712  * marker (@-) then this is removed (before the concatenated macro name
713  * may be expanded again.
714  */
715 static void processConcatOperators(QCString &expr)
716 {
717   //printf("processConcatOperators: in=`%s'\n",expr.data());
718   QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); 
719   int l,n,i=0;
720   if (expr.isEmpty()) return;
721   while ((n=r.match(expr,i,&l))!=-1)
722   {
723     //printf("Match: `%s'\n",expr.data()+i);
724     if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
725     {
726       // remove no-rescan marker after ID
727       l+=2;
728     }
729     //printf("found `%s'\n",expr.mid(n,l).data());
730     // remove the ## operator and the surrounding whitespace
731     expr=expr.left(n)+expr.right(expr.length()-n-l);
732     int k=n-1;
733     while (k>=0 && isId(expr.at(k))) k--; 
734     if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@')
735     {
736       // remove no-rescan marker before ID
737       expr=expr.left(k-1)+expr.right(expr.length()-k-1);
738       n-=2;
739     }
740     i=n;
741   }
742   //printf("processConcatOperators: out=`%s'\n",expr.data());
743 }
744
745 static void yyunput (int c,char *buf_ptr  );
746 static void returnCharToStream(char c)
747 {
748   unput(c);
749 }
750
751 static inline void addTillEndOfString(const QCString &expr,QCString *rest,
752                                        uint &pos,char term,QCString &arg)
753 {
754   int cc;
755   while ((cc=getNextChar(expr,rest,pos))!=EOF)
756   {
757     if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos);
758     else if (cc==term) return;
759     arg+=(char)cc;
760   }
761 }
762
763 /*! replaces the function macro \a def whose argument list starts at
764  * \a pos in expression \a expr. 
765  * Notice that this routine may scan beyond the \a expr string if needed.
766  * In that case the characters will be read from the input file.
767  * The replacement string will be returned in \a result and the 
768  * length of the (unexpanded) argument list is stored in \a len.
769  */ 
770 static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result)
771 {
772   //printf("replaceFunctionMacro(expr=%s,rest=%s,pos=%d,def=%s) level=%d\n",expr.data(),rest ? rest->data() : 0,pos,def->name.data(),g_level);
773   uint j=pos;
774   len=0;
775   result.resize(0);
776   int cc;
777   while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc)) 
778   { 
779     len++; 
780     getNextChar(expr,rest,j); 
781   }
782   if (cc!='(') 
783   { 
784     unputChar(expr,rest,j,' '); 
785     return FALSE; 
786   }
787   getNextChar(expr,rest,j); // eat the `(' character
788
789   QDict<QCString> argTable;  // list of arguments
790   argTable.setAutoDelete(TRUE);
791   QCString arg;
792   int argCount=0;
793   bool done=FALSE;
794   
795   // PHASE 1: read the macro arguments
796   if (def->nargs==0)
797   {
798     while ((cc=getNextChar(expr,rest,j))!=EOF)
799     {
800       char c = (char)cc;
801       if (c==')') break;
802     }
803   }
804   else
805   {
806     while (!done && (argCount<def->nargs || def->varArgs) && 
807         ((cc=getNextChar(expr,rest,j))!=EOF)
808           )
809     {
810       char c=(char)cc;
811       if (c=='(') // argument is a function => search for matching )
812       {
813         int level=1;
814         arg+=c;
815         //char term='\0';
816         while ((cc=getNextChar(expr,rest,j))!=EOF)
817         {
818           char c=(char)cc;
819           //printf("processing %c: term=%c (%d)\n",c,term,term);
820           if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
821           {
822             arg+=c;
823             addTillEndOfString(expr,rest,j,c,arg);
824           }
825           if (c==')')
826           {
827             level--;
828             arg+=c;
829             if (level==0) break;
830           }
831           else if (c=='(')
832           {
833             level++;
834             arg+=c;
835           }
836           else
837             arg+=c;
838         }
839       }
840       else if (c==')' || c==',') // last or next argument found
841       {
842         if (c==',' && argCount==def->nargs-1 && def->varArgs)
843         {
844           arg=arg.stripWhiteSpace();
845           arg+=',';
846         }
847         else
848         {
849           QCString argKey;
850           argKey.sprintf("@%d",argCount++); // key name
851           arg=arg.stripWhiteSpace();
852           // add argument to the lookup table
853           argTable.insert(argKey, new QCString(arg));
854           arg.resize(0);
855           if (c==')') // end of the argument list
856           {
857             done=TRUE;
858           }
859         }
860       } 
861       else if (c=='\"') // append literal strings
862       {
863         arg+=c; 
864         bool found=FALSE;
865         while (!found && (cc=getNextChar(expr,rest,j))!=EOF)
866         {
867           found = cc=='"';
868           if (cc=='\\')
869           {
870             c=(char)cc;   
871             arg+=c;
872             if ((cc=getNextChar(expr,rest,j))==EOF) break;
873           }
874           c=(char)cc;     
875           arg+=c;
876         }
877       }
878       else if (c=='\'') // append literal characters
879       {
880         arg+=c;
881         bool found=FALSE;
882         while (!found && (cc=getNextChar(expr,rest,j))!=EOF)
883         {
884           found = cc=='\'';
885           if (cc=='\\')
886           {
887             c=(char)cc;   
888             arg+=c;
889             if ((cc=getNextChar(expr,rest,j))==EOF) break;
890           }
891           c=(char)cc;
892           arg+=c;
893         }
894       }     
895       else // append other characters
896       {
897         arg+=c;
898       }
899     }
900   }
901
902   // PHASE 2: apply the macro function
903   if (argCount==def->nargs || 
904       (argCount>def->nargs && def->varArgs)) // matching parameters lists
905   {
906     uint k=0;
907     // substitution of all formal arguments
908     QCString resExpr;
909     const QCString d=def->definition.stripWhiteSpace();
910     //printf("Macro definition: %s\n",d.data());
911     bool inString=FALSE;
912     while (k<d.length())
913     {
914       if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
915       {
916         if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
917         {
918           k+=2;
919           resExpr+="@@"; // we unescape these later
920         }
921         else if (d.at(k+1)=='-') // no-rescan marker
922         {
923           k+=2;
924           resExpr+="@-";
925         }
926         else // argument marker => read the argument number
927         {
928           QCString key="@";
929           QCString *subst=0;
930           bool hash=FALSE;
931           int l=k-1;
932           // search for ## backward
933           if (l>=0 && d.at(l)=='"') l--;
934           while (l>=0 && d.at(l)==' ') l--;
935           if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
936           k++;
937           // scan the number
938           while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
939           if (!hash) 
940           {
941             // search for ## forward
942             l=k;
943             if (l<(int)d.length() && d.at(l)=='"') l++;
944             while (l<(int)d.length() && d.at(l)==' ') l++;
945             if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
946           }
947           //printf("request key %s result %s\n",key.data(),argTable[key]->data());
948           if (key.length()>1 && (subst=argTable[key])) 
949           {
950             QCString substArg=*subst;
951             //printf("substArg=`%s'\n",substArg.data());
952             // only if no ## operator is before or after the argument
953             // marker we do macro expansion.
954             if (!hash) expandExpression(substArg,0,0);
955             if (inString)
956             {
957               //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
958
959               // if the marker is inside a string (because a # was put 
960               // before the macro name) we must escape " and \ characters
961               resExpr+=stringize(substArg);
962             }
963             else
964             {
965               if (hash && substArg.isEmpty())
966               {
967                 resExpr+="@E"; // empty argument will be remove later on
968               }
969               else if (g_nospaces)
970               {
971                 resExpr+=substArg;
972               }
973               else
974               {
975                 resExpr+=" "+substArg+" ";
976               }
977             }
978           }
979         }
980       }
981       else // no marker, just copy
982       {
983         if (!inString && d.at(k)=='\"') 
984         {
985           inString=TRUE; // entering a literal string
986         }
987         else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
988         {
989           inString=FALSE; // leaving a literal string
990         }
991         resExpr+=d.at(k++);
992       }
993     }
994     len=j-pos;
995     result=resExpr;
996     //printf("result after substitution `%s' expr=`%s'\n",
997     //       result.data(),expr.mid(pos,len).data());
998     return TRUE;
999   }
1000   return FALSE;
1001 }
1002
1003
1004 /*! returns the next identifier in string \a expr by starting at position \a p.
1005  * The position of the identifier is returned (or -1 if nothing is found)
1006  * and \a l is its length. Any quoted strings are skipping during the search.
1007  */
1008 static int getNextId(const QCString &expr,int p,int *l)
1009 {
1010   int n;
1011   while (p<(int)expr.length())
1012   {
1013     char c=expr.at(p++);
1014     if (isdigit(c)) // skip number
1015     {
1016       while (p<(int)expr.length() && isId(expr.at(p))) p++;
1017     }
1018     else if (isalpha(c) || c=='_') // read id
1019     {
1020       n=p-1;
1021       while (p<(int)expr.length() && isId(expr.at(p))) p++;
1022       *l=p-n;
1023       return n; 
1024     }
1025     else if (c=='"') // skip string
1026     {
1027       char ppc=0,pc=c;
1028       if (p<(int)expr.length()) c=expr.at(p);
1029       while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) 
1030         // continue as long as no " is found, but ignoring \", but not \\"
1031       {
1032         ppc=pc;
1033         pc=c;
1034         c=expr.at(p);
1035         p++;
1036       }
1037       if (p<(int)expr.length()) ++p; // skip closing quote
1038     }
1039     else if (c=='/') // skip C Comment
1040     {
1041       //printf("Found C comment at p=%d\n",p);
1042       char pc=c;
1043       if (p<(int)expr.length()) 
1044       {
1045         c=expr.at(p);
1046         if (c=='*')  // Start of C comment
1047         { 
1048           p++;
1049           while (p<(int)expr.length() && !(pc=='*' && c=='/'))
1050           {
1051             pc=c;
1052             c=expr.at(p++);
1053           }
1054         }
1055       }
1056       //printf("Found end of C comment at p=%d\n",p);
1057     }
1058   }
1059   return -1;
1060 }
1061
1062 /*! preforms recursive macro expansion on the string \a expr
1063  *  starting at position \a pos.
1064  *  May read additional characters from the input while re-scanning!
1065  *  If \a expandAll is \c TRUE then all macros in the expression are
1066  *  expanded, otherwise only the first is expanded.
1067  */
1068 static void expandExpression(QCString &expr,QCString *rest,int pos)
1069 {
1070   //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
1071   QCString macroName;
1072   QCString expMacro;
1073   bool definedTest=FALSE;
1074   int i=pos,l,p,len;
1075   while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
1076   {
1077     bool replaced=FALSE;
1078     macroName=expr.mid(p,l);
1079     //printf("macroName=%s\n",macroName.data());
1080     if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
1081     {
1082       if (g_expandedDict->find(macroName)==0) // expand macro
1083       {
1084         Define *def=DefineManager::instance().isDefined(macroName);
1085         if (definedTest) // macro name was found after defined 
1086         {
1087           if (def) expMacro = " 1 "; else expMacro = " 0 ";
1088           replaced=TRUE;
1089           len=l;
1090           definedTest=FALSE;
1091         }
1092         else if (def && def->nargs==-1) // simple macro
1093         {
1094           // substitute the definition of the macro
1095           //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
1096           if (g_nospaces)
1097           {
1098             expMacro=def->definition.stripWhiteSpace();
1099           }
1100           else
1101           {
1102             expMacro=" "+def->definition.stripWhiteSpace()+" ";
1103           }
1104           //expMacro=def->definition.stripWhiteSpace();
1105           replaced=TRUE;
1106           len=l;
1107           //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
1108         }
1109         else if (def && def->nargs>=0) // function macro
1110         {
1111           replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
1112           len+=l;
1113         }
1114         else if (macroName=="defined")
1115         {
1116           //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
1117           definedTest=TRUE;
1118         }
1119
1120         if (replaced) // expand the macro and rescan the expression
1121         {
1122             
1123           //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
1124           QCString resultExpr=expMacro;
1125           QCString restExpr=expr.right(expr.length()-len-p);
1126           processConcatOperators(resultExpr);
1127           if (def && !def->nonRecursive)
1128           {
1129             g_expandedDict->insert(macroName,def);
1130             expandExpression(resultExpr,&restExpr,0);
1131             g_expandedDict->remove(macroName);
1132           }
1133           expr=expr.left(p)+resultExpr+restExpr;
1134           i=p;
1135           //printf("new expression: %s\n",expr.data());
1136         }
1137         else // move to the next macro name
1138         {
1139           //printf("moving to the next macro old=%d new=%d\n",i,p+l);
1140           i=p+l;
1141         }
1142       }
1143       else // move to the next macro name
1144       {
1145         expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
1146         //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
1147         i=p+l+2;
1148         //i=p+l;
1149       }
1150     }
1151     else // no re-scan marker found, skip the macro name
1152     {
1153       //printf("skipping marked macro\n");
1154       i=p+l;
1155     }
1156   }
1157 }
1158
1159 /*! replaces all occurrences of @@@@ in \a s by @@
1160  *  and removes all occurrences of @@E.
1161  *  All identifiers found are replaced by 0L
1162  */
1163 QCString removeIdsAndMarkers(const char *s)
1164 {
1165   //printf("removeIdsAndMarkers(%s)\n",s);
1166   const char *p=s;
1167   char c;
1168   bool inNum=FALSE;
1169   QCString result;
1170   if (p)
1171   {
1172     while ((c=*p))
1173     {
1174       if (c=='@') // replace @@ with @ and remove @E
1175       {
1176         if (*(p+1)=='@')
1177         {
1178           result+=c; 
1179         }
1180         else if (*(p+1)=='E')
1181         {
1182           // skip
1183         }
1184         p+=2;
1185       }
1186       else if (isdigit(c)) // number
1187       {
1188         result+=c;
1189         p++;
1190         inNum=TRUE;     
1191       }
1192       else if (c=='d' && !inNum) // identifier starting with a `d'
1193       {
1194         if (strncmp(p,"defined ",8)==0 || strncmp(p,"defined(",8)==0) 
1195                    // defined keyword
1196         {
1197           p+=7; // skip defined
1198         }
1199         else
1200         {
1201           result+="0L";
1202           p++;
1203           while ((c=*p) && isId(c)) p++;
1204         }
1205       }
1206       else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
1207       {
1208         result+="0L";
1209         p++;
1210         while ((c=*p) && isId(c)) p++;
1211         if (*p=='(') // undefined function macro
1212         {
1213           p++;
1214           int count=1;
1215           while ((c=*p++))
1216           {
1217             if (c=='(') count++;
1218             else if (c==')')
1219             {
1220               count--;
1221               if (count==0) break;
1222             }
1223             else if (c=='/')
1224             {
1225               char pc=c;
1226               c=*++p;
1227               if (c=='*') // start of C comment
1228               {
1229                 while (*p && !(pc=='*' && c=='/')) // search end of comment
1230                 {
1231                   pc=c;
1232                   c=*++p;
1233                 }
1234                 p++;
1235               }
1236             }
1237           }
1238         }
1239       }
1240       else if (c=='/') // skip C comments
1241       {
1242         char pc=c;
1243         c=*++p;
1244         if (c=='*') // start of C comment
1245         { 
1246           while (*p && !(pc=='*' && c=='/')) // search end of comment
1247           {
1248             pc=c;
1249             c=*++p;
1250           }
1251           p++;
1252         }
1253         else // oops, not comment but division
1254         {
1255           result+=pc;
1256           goto nextChar;
1257         }
1258       }
1259       else 
1260       {
1261 nextChar:
1262         result+=c;
1263         char lc=tolower(c);
1264         if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
1265         p++;
1266       }
1267     }
1268   }
1269   //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
1270   return result;
1271 }
1272
1273 /*! replaces all occurrences of @@ in \a s by @
1274  *  \par assumption: 
1275  *   \a s only contains pairs of @@'s
1276  */
1277 QCString removeMarkers(const char *s)
1278 {
1279   const char *p=s;
1280   char c;
1281   QCString result;
1282   if (p)
1283   {
1284     while ((c=*p))
1285     {
1286       switch(c)
1287       {
1288         case '@': // replace @@ with @
1289           {
1290             if (*(p+1)=='@')
1291             {
1292               result+=c; 
1293             }
1294             p+=2;
1295           }
1296           break;
1297         case '/': // skip C comments
1298           {
1299             result+=c;
1300             char pc=c;
1301             c=*++p;
1302             if (c=='*') // start of C comment
1303             { 
1304               while (*p && !(pc=='*' && c=='/')) // search end of comment
1305               {
1306                 if (*p=='@' && *(p+1)=='@') 
1307                   result+=c,p++;
1308                 else 
1309                   result+=c;
1310                 pc=c;
1311                 c=*++p;
1312               }
1313               if (*p) result+=c,p++;
1314             }
1315           }
1316           break;
1317         case '"': // skip string literals
1318           {
1319             result+=c;
1320             char pc=c;
1321             c=*++p;
1322             while (*p && (c!='"' || pc=='\\')) // no end quote
1323             {
1324               result+=c;
1325               c=*++p;
1326             }
1327             if (*p) result+=c,p++; 
1328           }
1329           break;
1330         case '\'': // skip char literals
1331           {
1332             result+=c;
1333             char pc=c;
1334             c=*++p;
1335             while (*p && (c!='\'' || pc=='\\')) // no end quote
1336             {
1337               result+=c;
1338               c=*++p;
1339             }
1340             if (*p) result+=c,p++; 
1341           }
1342           break;
1343         default:
1344           {
1345             result+=c;
1346             p++;
1347           }
1348           break;
1349       }
1350     }
1351   }
1352   //printf("RemoveMarkers(%s)=%s\n",s,result.data());
1353   return result;
1354 }
1355
1356 /*! compute the value of the expression in string \a expr.
1357  *  If needed the function may read additional characters from the input.
1358  */
1359
1360 bool computeExpression(const QCString &expr)
1361 {
1362   QCString e=expr;
1363   expandExpression(e,0,0);
1364   //printf("after expansion `%s'\n",e.data());
1365   e = removeIdsAndMarkers(e);
1366   if (e.isEmpty()) return FALSE;
1367   //printf("parsing `%s'\n",e.data());
1368   return parseCppExpression(g_yyFileName,g_yyLineNr,e);
1369 }
1370
1371 /*! expands the macro definition in \a name
1372  *  If needed the function may read additional characters from the input
1373  */
1374
1375 QCString expandMacro(const QCString &name)
1376 {
1377   QCString n=name;
1378   expandExpression(n,0,0);
1379   n=removeMarkers(n);
1380   //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
1381   return n;
1382 }
1383
1384 Define *newDefine()
1385 {
1386   Define *def=new Define;
1387   def->name       = g_defName;
1388   def->definition = g_defText.stripWhiteSpace();
1389   def->nargs      = g_defArgs;
1390   def->fileName   = g_yyFileName; 
1391   def->fileDef    = g_yyFileDef;
1392   def->lineNr     = g_yyLineNr;
1393   def->varArgs    = g_defVarArgs;
1394   //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
1395   //    def->fileDef ? def->fileDef->name().data() : def->fileName.data());
1396   //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
1397   if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
1398   {
1399     def->isPredefined=TRUE;
1400   }
1401   return def;
1402 }
1403
1404 void addDefine()
1405 {
1406   if (g_skip) return; // do not add this define as it is inside a 
1407                       // conditional section (cond command) that is disabled.
1408   if (!Doxygen::gatherDefines) return;
1409
1410   //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
1411   //ArgumentList *al = new ArgumentList;
1412   //stringToArgumentList(g_defArgsStr,al);
1413   MemberDef *md=new MemberDef(
1414       g_yyFileName,g_yyLineNr,
1415       "#define",g_defName,g_defArgsStr,0,
1416       Public,Normal,FALSE,Member,MemberDef::Define,0,0);
1417   if (!g_defArgsStr.isEmpty())
1418   {
1419     ArgumentList *argList = new ArgumentList;
1420     //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
1421     stringToArgumentList(g_defArgsStr,argList);
1422     md->setArgumentList(argList);
1423   }
1424   //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
1425   int l=g_defLitText.find('\n');
1426   if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
1427   {
1428     // strip first line if it only contains a slash
1429     g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
1430   }
1431   else if (l>0)
1432   {
1433     // align the items on the first line with the items on the second line
1434     int k=l+1;
1435     const char *p=g_defLitText.data()+k;
1436     char c;
1437     while ((c=*p++) && (c==' ' || c=='\t')) k++;
1438     g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
1439   }
1440   md->setInitializer(g_defLitText.stripWhiteSpace());
1441
1442   //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef);
1443   md->setFileDef(g_inputFileDef);
1444   md->setDefinition("#define "+g_defName);
1445
1446   MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
1447   if (mn==0)
1448   {
1449     mn = new MemberName(g_defName);
1450     Doxygen::functionNameSDict->append(g_defName,mn);
1451   }
1452   mn->append(md);
1453   if (g_yyFileDef) 
1454   {
1455     g_yyFileDef->insertMember(md);
1456   }
1457
1458   //Define *d;
1459   //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); 
1460 }
1461
1462 static inline void outputChar(char c)
1463 {
1464   if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c);
1465 }
1466
1467 static inline void outputArray(const char *a,int len)
1468 {
1469   if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len);
1470 }
1471
1472 static void readIncludeFile(const QCString &inc)
1473 {
1474   static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1475   if (!searchIncludes) return; // do not read include files
1476   uint i=0;
1477
1478   // find the start of the include file name
1479   while (i<inc.length() &&
1480          (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
1481         ) i++;
1482   uint s=i;
1483
1484   // was it a local include?
1485   bool localInclude = s>0 && inc.at(s-1)=='"';
1486
1487   // find the end of the include file name
1488   while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
1489
1490   if (s<inc.length() && i>s) // valid include file name found
1491   {
1492     // extract include path+name
1493     QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
1494
1495     QCString dosExt = incFileName.right(4);
1496     if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
1497     {
1498       // skip imported binary files (e.g. M$ type libraries)
1499       return;
1500     }
1501
1502     QCString oldFileName = g_yyFileName;
1503     FileDef *oldFileDef  = g_yyFileDef;
1504     int oldLineNr        = g_yyLineNr;
1505     //printf("Searching for `%s'\n",incFileName.data());
1506
1507     // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
1508     QCString absIncFileName = incFileName;
1509     {
1510       static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1511       QFileInfo fi(g_yyFileName);
1512       if (fi.exists())
1513       {
1514         QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName;
1515         QFileInfo fi2(absName);
1516         if (fi2.exists())
1517         {
1518           absIncFileName=fi2.absFilePath().utf8();
1519         }
1520         else if (searchIncludes) // search in INCLUDE_PATH as well
1521         {
1522           QStrList &includePath = Config_getList("INCLUDE_PATH");
1523           char *s=includePath.first();
1524           while (s)
1525           {
1526             QFileInfo fi(s);
1527             if (fi.exists() && fi.isDir())
1528             {
1529               QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName;
1530               //printf("trying absName=%s\n",absName.data());
1531               QFileInfo fi2(absName);
1532               if (fi2.exists())
1533               {
1534                 absIncFileName=fi2.absFilePath().utf8();
1535                 break;
1536               }
1537               //printf( "absIncFileName = %s\n", absIncFileName.data() );
1538             }
1539             s=includePath.next();
1540           }
1541         }
1542         //printf( "absIncFileName = %s\n", absIncFileName.data() );
1543       }
1544     }
1545     DefineManager::instance().addInclude(g_yyFileName,absIncFileName);
1546     DefineManager::instance().addFileToContext(absIncFileName);
1547
1548     // findFile will overwrite g_yyFileDef if found
1549     FileState *fs;
1550     bool alreadyIncluded = FALSE;
1551     //printf("calling findFile(%s)\n",incFileName.data());
1552     if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
1553     {
1554       //printf("Found include file!\n");
1555       if (Debug::isFlagSet(Debug::Preprocessor))
1556       {
1557         for (i=0;i<g_includeStack.count();i++) 
1558         {
1559           Debug::print(Debug::Preprocessor,0,"  ");
1560         }
1561         //msg("#include %s: parsing...\n",incFileName.data());
1562       }
1563       if (oldFileDef)
1564       {
1565         // add include dependency to the file in which the #include was found
1566         bool ambig;
1567         // change to absolute name for bug 641336 
1568         FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1569         oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE);
1570         // add included by dependency
1571         if (g_yyFileDef)
1572         {
1573           //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
1574           g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1575         }
1576       }
1577       else if (g_inputFileDef)
1578       {
1579         g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1580       }
1581       fs->bufState = YY_CURRENT_BUFFER;
1582       fs->lineNr   = oldLineNr;
1583       fs->fileName = oldFileName;
1584       // push the state on the stack
1585       g_includeStack.push(fs);
1586       // set the scanner to the include file
1587
1588       // Deal with file changes due to 
1589       // #include's within { .. } blocks
1590       QCString lineStr(g_yyFileName.length()+20);
1591       lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
1592       outputArray(lineStr.data(),lineStr.length());
1593
1594       //fprintf(stderr,"Switching to include file %s\n",incFileName.data());
1595       g_expectGuard=TRUE;
1596       g_inputBuf   = &fs->fileBuf;
1597       g_inputBufPos=0;
1598       yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
1599     }
1600     else
1601     {
1602       //printf("  calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
1603       if (oldFileDef)
1604       {
1605         bool ambig;
1606         //QCString absPath = incFileName;
1607         //if (QDir::isRelativePath(incFileName))
1608         //{
1609         //  absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName);
1610         //  //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data());
1611         //}
1612
1613         // change to absolute name for bug 641336 
1614         FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1615         //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd);
1616         // add include dependency to the file in which the #include was found
1617         oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE);
1618         // add included by dependency
1619         if (fd)
1620         {
1621           //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
1622           fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1623         }
1624       }
1625       else if (g_inputFileDef)
1626       {
1627         g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1628       }
1629       if (Debug::isFlagSet(Debug::Preprocessor))
1630       {
1631         if (alreadyIncluded)
1632         {
1633           Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",incFileName.data());
1634         }
1635         else
1636         {
1637           Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",incFileName.data());
1638         }
1639         //printf("error: include file %s not found\n",yytext);
1640       }
1641       if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
1642       {
1643         warn(g_yyFileName,g_yyLineNr,"Warning: include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
1644       }
1645     }
1646   }
1647 }
1648
1649 /* ----------------------------------------------------------------- */
1650
1651 static void startCondSection(const char *sectId)
1652 {
1653   g_condStack.push(new bool(g_skip));
1654   if (Config_getList("ENABLED_SECTIONS").find(sectId)==-1)
1655   {
1656     g_skip=TRUE;
1657   }
1658 }
1659
1660 static void endCondSection()
1661 {
1662   if (g_condStack.isEmpty())
1663   {
1664     g_skip=FALSE;
1665   }
1666   else
1667   {
1668     bool *ctx = g_condStack.pop();
1669     g_skip=*ctx;
1670   }
1671 }
1672
1673 static void forceEndCondSection()
1674 {
1675   while (!g_condStack.isEmpty())
1676   {
1677     g_condStack.pop();
1678   }
1679   g_skip=FALSE;
1680 }
1681
1682 static QCString escapeAt(const char *text)
1683 {
1684   QCString result;
1685   if (text)
1686   {
1687     char c;
1688     const char *p=text;
1689     while ((c=*p++))
1690     {
1691       if (c=='@') result+="@@"; else result+=c;
1692     }
1693   }
1694   return result;
1695 }
1696
1697 static char resolveTrigraph(char c)
1698 {
1699   switch (c)
1700   {
1701     case '=': return '#';
1702     case '/': return '\\';
1703     case '\'': return '^';
1704     case '(': return '[';
1705     case ')': return ']';
1706     case '!': return '|';
1707     case '<': return '{';
1708     case '>': return '}';
1709     case '-': return '~';
1710   }
1711   return '?';
1712 }
1713
1714 /* ----------------------------------------------------------------- */
1715
1716 #undef  YY_INPUT
1717 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1718
1719 static int yyread(char *buf,int max_size)
1720 {
1721   int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
1722   int bytesToCopy = QMIN(max_size,bytesInBuf);
1723   memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
1724   g_inputBufPos+=bytesToCopy;
1725   return bytesToCopy;
1726 }
1727
1728 /* ----------------------------------------------------------------- */
1729
1730 %}
1731
1732 ID      [a-z_A-Z][a-z_A-Z0-9]*
1733 B       [ \t]
1734 BN      [ \t\r\n]
1735 CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
1736
1737 %option noyywrap
1738
1739 %x      Start
1740 %x      Command
1741 %x      SkipCommand
1742 %x      SkipLine
1743 %x      SkipString
1744 %x      CopyLine
1745 %x      CopyString
1746 %x      Include
1747 %x      IncludeID
1748 %x      EndImport
1749 %x      DefName
1750 %x      DefineArg
1751 %x      DefineText
1752 %x      SkipCPPBlock
1753 %x      Ifdef
1754 %x      Ifndef
1755 %x      SkipCComment
1756 %x      CopyCComment
1757 %x      SkipVerbatim
1758 %x      SkipCPPComment
1759 %x      RemoveCComment
1760 %x      RemoveCPPComment
1761 %x      Guard
1762 %x      DefinedExpr1
1763 %x      DefinedExpr2
1764 %x      SkipDoubleQuote
1765 %x      SkipSingleQuote
1766 %x      UndefName
1767 %x      IgnoreLine
1768 %x      FindDefineArgs
1769 %x      ReadString
1770 %x      CondLine
1771
1772 %%
1773
1774 <*>\x06                                 
1775 <*>\x00
1776 <*>\r
1777 <*>"??"[=/'()!<>-]                      { // Trigraph
1778                                           unput(resolveTrigraph(yytext[2]));
1779                                         }
1780 <Start>^{B}*"#"                         { BEGIN(Command); }
1781 <Start>^{B}*/[^#]                       {
1782                                           outputArray(yytext,yyleng); 
1783                                           BEGIN(CopyLine); 
1784                                         }
1785 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
1786                                           int i;
1787                                           for (i=yyleng-1;i>=0;i--)
1788                                           {
1789                                             unput(yytext[i]);
1790                                           }
1791                                           BEGIN(CopyLine);
1792                                         }
1793 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\(\)\n]*"("[^\)\n]*")"[^\)\n]*")"{B}*\n | // function list macro with one (...) argument, e.g. for K_GLOBAL_STATIC_WITH_ARGS
1794 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"{B}*\n { // function like macro
1795                                           static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS");
1796                                           QCString name(yytext);
1797                                           name=name.left(name.find('(')).stripWhiteSpace();
1798
1799                                           Define *def=0;
1800                                           if (skipFuncMacros && 
1801                                               name!="Q_PROPERTY" &&
1802                                               !(
1803                                                  (g_includeStack.isEmpty() || g_curlyCount>0) &&
1804                                                  g_macroExpansion &&
1805                                                  (def=DefineManager::instance().isDefined(name)) &&
1806                                                  /*macroIsAccessible(def) &&*/
1807                                                  (!g_expandOnlyPredef || def->isPredefined)
1808                                                )
1809                                              )
1810                                           {
1811                                             outputChar('\n');
1812                                             g_yyLineNr++;
1813                                           }
1814                                           else // don't skip
1815                                           {
1816                                             int i;
1817                                             for (i=yyleng-1;i>=0;i--)
1818                                             {
1819                                               unput(yytext[i]);
1820                                             }
1821                                             BEGIN(CopyLine);
1822                                           }
1823                                         }
1824 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{"       {
1825                                           QCString text=yytext;
1826                                           g_yyLineNr+=text.contains('\n');
1827                                           outputArray(yytext,yyleng);
1828                                         }
1829 <CopyLine>"{"                           { // count brackets inside the main file
1830                                           if (g_includeStack.isEmpty()) 
1831                                           {
1832                                             g_curlyCount++;
1833                                           }
1834                                           outputChar(*yytext);
1835                                         }
1836 <CopyLine>"}"                           { // count brackets inside the main file
1837                                           if (g_includeStack.isEmpty() && g_curlyCount>0) 
1838                                           {
1839                                             g_curlyCount--;
1840                                           }
1841                                           outputChar(*yytext);
1842                                         }
1843 <CopyLine>"'"\\[0-7]{1,3}"'"            { 
1844                                           outputArray(yytext,yyleng);
1845                                         }
1846 <CopyLine>"'"\\."'"                     { 
1847                                           outputArray(yytext,yyleng);
1848                                         }
1849 <CopyLine>"'"."'"                       { 
1850                                           outputArray(yytext,yyleng);
1851                                         }
1852 <CopyLine>\"                            {
1853                                           outputChar(*yytext);
1854                                           BEGIN( CopyString );
1855                                         }
1856 <CopyString>[^\"\\\r\n]+                {
1857                                           outputArray(yytext,yyleng);
1858                                         }
1859 <CopyString>\\.                         {
1860                                           outputArray(yytext,yyleng);
1861                                         }
1862 <CopyString>\"                          {
1863                                           outputChar(*yytext);
1864                                           BEGIN( CopyLine );
1865                                         }
1866 <CopyLine>{ID}/{BN}{0,80}"("            {
1867                                           g_expectGuard = FALSE;
1868                                           Define *def=0;
1869                                           //def=g_globalDefineDict->find(yytext);
1870                                           //def=DefineManager::instance().isDefined(yytext);
1871                                           //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d "
1872                                           //       "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
1873                                           //     "isPreDefined=%d\n",yytext,def ? 1 : 0,
1874                                           //     g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
1875                                           //     def ? def->isPredefined : -1
1876                                           //    );
1877                                           if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1878                                               g_macroExpansion &&
1879                                               (def=DefineManager::instance().isDefined(yytext)) &&
1880                                               /*(def->isPredefined || macroIsAccessible(def)) && */
1881                                               (!g_expandOnlyPredef || def->isPredefined)
1882                                              )
1883                                           {
1884                                             //printf("Found it! #args=%d\n",def->nargs);
1885                                             g_roundCount=0;
1886                                             g_defArgsStr=yytext;
1887                                             if (def->nargs==-1) // no function macro
1888                                             {
1889                                               QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr);
1890                                               outputArray(result,result.length());
1891                                             }
1892                                             else // zero or more arguments
1893                                             {
1894                                               g_findDefArgContext = CopyLine;
1895                                               BEGIN(FindDefineArgs);
1896                                             }
1897                                           }
1898                                           else
1899                                           {
1900                                             outputArray(yytext,yyleng);
1901                                           }
1902                                         }
1903 <CopyLine>{ID}                          {
1904                                           Define *def=0;
1905                                           if ((g_includeStack.isEmpty() || g_curlyCount>0) && 
1906                                               g_macroExpansion &&
1907                                               (def=DefineManager::instance().isDefined(yytext)) &&
1908                                               def->nargs==-1 &&
1909                                               /*(def->isPredefined || macroIsAccessible(def)) &&*/
1910                                               (!g_expandOnlyPredef || def->isPredefined)
1911                                              )
1912                                           {
1913                                             QCString result=def->isPredefined ? def->definition : expandMacro(yytext); 
1914                                             outputArray(result,result.length());
1915                                           }
1916                                           else
1917                                           {
1918                                             outputArray(yytext,yyleng);
1919                                           }
1920                                         }
1921 <CopyLine>"\\"\r?/\n                    { // strip line continuation characters
1922                                         }
1923 <CopyLine>.                             {
1924                                           outputChar(*yytext);
1925                                         }
1926 <CopyLine>\n                            {
1927                                           outputChar('\n');
1928                                           BEGIN(Start);
1929                                           g_yyLineNr++;
1930                                         }
1931 <FindDefineArgs>"("                     {
1932                                           g_defArgsStr+='(';
1933                                           g_roundCount++;
1934                                         }
1935 <FindDefineArgs>")"                     {
1936                                           g_defArgsStr+=')';
1937                                           g_roundCount--;
1938                                           if (g_roundCount==0)
1939                                           {
1940                                             QCString result=expandMacro(g_defArgsStr);
1941                                             //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
1942                                             if (g_findDefArgContext==CopyLine)
1943                                             {
1944                                               outputArray(result,result.length());
1945                                               BEGIN(g_findDefArgContext);
1946                                             }
1947                                             else // g_findDefArgContext==IncludeID
1948                                             {
1949                                               readIncludeFile(result);
1950                                               g_nospaces=FALSE;
1951                                               BEGIN(Start);
1952                                             }
1953                                           }
1954                                         }
1955   /*
1956 <FindDefineArgs>")"{B}*"("              {
1957                                           g_defArgsStr+=yytext;
1958                                         }
1959   */
1960 <FindDefineArgs>{CHARLIT}               {
1961                                           g_defArgsStr+=yytext;
1962                                         }
1963 <FindDefineArgs>\"                      {
1964                                           g_defArgsStr+=*yytext;
1965                                           BEGIN(ReadString);
1966                                         }
1967 <FindDefineArgs>\n                      {
1968                                           g_yyLineNr++;
1969                                           outputChar('\n');
1970                                         }
1971 <FindDefineArgs>"@"                     {
1972                                           g_defArgsStr+="@@";
1973                                         }
1974 <FindDefineArgs>.                       {
1975                                           g_defArgsStr+=*yytext;
1976                                         }
1977 <ReadString>"\""                        {
1978                                           g_defArgsStr+=*yytext;
1979                                           BEGIN(FindDefineArgs);
1980                                         }
1981 <ReadString>"//"|"/*"                   {
1982                                           g_defArgsStr+=yytext;
1983                                         }
1984 <ReadString>\\.                         {
1985                                           g_defArgsStr+=yytext;
1986                                         }
1987 <ReadString>.                           {
1988                                           g_defArgsStr+=*yytext;
1989                                         }
1990 <Command>("include"|"import"){B}+/{ID}  {
1991                                           g_isImported = yytext[1]=='m';
1992                                           if (g_macroExpansion) 
1993                                             BEGIN(IncludeID);
1994                                         }
1995 <Command>("include"|"import"){B}*[<"]   { 
1996                                           g_isImported = yytext[1]=='m';
1997                                           char c[2];
1998                                           c[0]=yytext[yyleng-1];c[1]='\0';
1999                                           g_incName=c;
2000                                           BEGIN(Include); 
2001                                         }
2002 <Command>("cmake")?"define"{B}+         { 
2003                                           //printf("!!!DefName\n"); 
2004                                           BEGIN(DefName); 
2005                                         }
2006 <Command>"ifdef"/{B}*"("                {
2007                                           incrLevel();
2008                                           g_guardExpr.resize(0);
2009                                           BEGIN(DefinedExpr2);
2010                                         }
2011 <Command>"ifdef"/{B}+                   {
2012                                           //printf("Pre.l: ifdef\n");
2013                                           incrLevel();
2014                                           g_guardExpr.resize(0);
2015                                           BEGIN(DefinedExpr1);
2016                                         }
2017 <Command>"ifndef"/{B}*"("               {
2018                                           incrLevel();
2019                                           g_guardExpr="! ";
2020                                           BEGIN(DefinedExpr2);
2021                                         }
2022 <Command>"ifndef"/{B}+                  {
2023                                           incrLevel();
2024                                           g_guardExpr="! ";
2025                                           BEGIN(DefinedExpr1);
2026                                         }
2027 <Command>"if"/[ \t(!]                   {
2028                                           incrLevel();
2029                                           g_guardExpr.resize(0);
2030                                           BEGIN(Guard);
2031                                         }
2032 <Command>("elif"|"else"{B}*"if")/[ \t(!]        {
2033                                           if (!otherCaseDone())
2034                                           {
2035                                             g_guardExpr.resize(0);
2036                                             BEGIN(Guard);  
2037                                           }
2038                                           else
2039                                           {
2040                                             g_ifcount=0;
2041                                             BEGIN(SkipCPPBlock);
2042                                           }
2043                                         }
2044 <Command>"else"/[^a-z_A-Z0-9]           {
2045                                           //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2046                                           if (otherCaseDone())
2047                                           {
2048                                             g_ifcount=0;
2049                                             BEGIN(SkipCPPBlock);
2050                                           }
2051                                           else
2052                                           {
2053                                             setCaseDone(TRUE);
2054                                             //g_levelGuard[g_level-1]=TRUE;
2055                                           } 
2056                                         }
2057 <Command>"undef"{B}+                    {
2058                                           BEGIN(UndefName);
2059                                         }
2060 <Command>("elif"|"else"{B}*"if")/[ \t(!]        {
2061                                           if (!otherCaseDone())
2062                                           {
2063                                             g_guardExpr.resize(0);
2064                                             BEGIN(Guard);
2065                                           }
2066                                         }
2067 <Command>"endif"/[^a-z_A-Z0-9]          {
2068                                           //printf("Pre.l: #endif\n");
2069                                           decrLevel();
2070                                         }
2071 <Command,IgnoreLine>\n                  {
2072                                           outputChar('\n');
2073                                           BEGIN(Start);
2074                                           g_yyLineNr++;
2075                                         }
2076 <Command>"pragma"{B}+"once"             {
2077                                           g_expectGuard = FALSE;
2078                                         }
2079 <Command>{ID}                           { // unknown directive
2080                                           BEGIN(IgnoreLine);
2081                                         }
2082 <IgnoreLine>\\[\r]?\n                   {
2083                                           outputChar('\n');
2084                                           g_yyLineNr++;
2085                                         }
2086 <IgnoreLine>.
2087 <Command>.
2088 <UndefName>{ID}                         {
2089                                           Define *def;
2090                                           if ((def=DefineManager::instance().isDefined(yytext)) 
2091                                               /*&& !def->isPredefined*/
2092                                               && !def->nonRecursive
2093                                              )
2094                                           {
2095                                             //printf("undefining %s\n",yytext);
2096                                             def->undef=TRUE;
2097                                           }
2098                                           BEGIN(Start);
2099                                         }
2100 <Guard>\\[\r]?\n                        {
2101                                           outputChar('\n');
2102                                           g_guardExpr+=' ';
2103                                           g_yyLineNr++;
2104                                         }
2105 <Guard>"defined"/{B}*"("                {
2106                                           BEGIN(DefinedExpr2);
2107                                         }
2108 <Guard>"defined"/{B}+                   {
2109                                           BEGIN(DefinedExpr1);
2110                                         }
2111 <Guard>{ID}                             { g_guardExpr+=yytext; }
2112 <Guard>.                                { g_guardExpr+=*yytext; }
2113 <Guard>\n                               {
2114                                           unput(*yytext);
2115                                           //printf("Guard: `%s'\n",
2116                                           //    g_guardExpr.data());
2117                                           bool guard=computeExpression(g_guardExpr);
2118                                           setCaseDone(guard);
2119                                           //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2120                                           if (guard)
2121                                           {
2122                                             BEGIN(Start);
2123                                           } 
2124                                           else
2125                                           {
2126                                             g_ifcount=0;
2127                                             BEGIN(SkipCPPBlock);
2128                                           }
2129                                         }
2130 <DefinedExpr1,DefinedExpr2>\\\n         { g_yyLineNr++; outputChar('\n'); }
2131 <DefinedExpr1>{ID}                      {
2132                                           if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2133                                             g_guardExpr+=" 1L ";
2134                                           else
2135                                             g_guardExpr+=" 0L ";
2136                                           g_lastGuardName=yytext;
2137                                           BEGIN(Guard);
2138                                         }
2139 <DefinedExpr2>{ID}                      {
2140                                           if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2141                                             g_guardExpr+=" 1L ";
2142                                           else
2143                                             g_guardExpr+=" 0L ";
2144                                           g_lastGuardName=yytext;
2145                                         }
2146 <DefinedExpr1,DefinedExpr2>\n           { // should not happen, handle anyway
2147                                           g_yyLineNr++;
2148                                           g_ifcount=0;
2149                                           BEGIN(SkipCPPBlock); 
2150                                         }
2151 <DefinedExpr2>")"                       {
2152                                           BEGIN(Guard);
2153                                         }
2154 <DefinedExpr1,DefinedExpr2>.
2155 <SkipCPPBlock>^{B}*"#"                  { BEGIN(SkipCommand); }
2156 <SkipCPPBlock>^{B}*/[^#]                { BEGIN(SkipLine); }
2157 <SkipCPPBlock>\n                        { g_yyLineNr++; outputChar('\n'); }
2158 <SkipCPPBlock>.
2159 <SkipCommand>"if"(("n")?("def"))?/[ \t(!]       { 
2160                                           incrLevel();
2161                                           g_ifcount++; 
2162                                           //printf("#if... depth=%d\n",g_ifcount);
2163                                         }
2164 <SkipCommand>"else"                     {
2165                                           //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
2166                                           if (g_ifcount==0 && !otherCaseDone())
2167                                           {
2168                                             setCaseDone(TRUE);
2169                                             //outputChar('\n');
2170                                             BEGIN(Start);
2171                                           }
2172                                         }
2173 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!]            {
2174                                           if (g_ifcount==0) 
2175                                           {
2176                                             if (!otherCaseDone())
2177                                             {
2178                                               g_guardExpr.resize(0);
2179                                               g_lastGuardName.resize(0);
2180                                               BEGIN(Guard);
2181                                             }
2182                                             else
2183                                             {
2184                                               BEGIN(SkipCPPBlock);
2185                                             }
2186                                           }
2187                                         }
2188 <SkipCommand>"endif"                    { 
2189                                           g_expectGuard = FALSE;
2190                                           decrLevel();
2191                                           if (--g_ifcount<0)
2192                                           {
2193                                             //outputChar('\n');
2194                                             BEGIN(Start);
2195                                           }
2196                                         }
2197 <SkipCommand>\n                         { 
2198                                           outputChar('\n');
2199                                           g_yyLineNr++; 
2200                                           BEGIN(SkipCPPBlock);
2201                                         }
2202 <SkipCommand>{ID}                       { // unknown directive 
2203                                           BEGIN(SkipLine); 
2204                                         }
2205 <SkipCommand>.
2206 <SkipLine>[^'"/\n]+                     
2207 <SkipLine>{CHARLIT}                     { }
2208 <SkipLine>\"                            {
2209                                           BEGIN(SkipString);
2210                                         }
2211 <SkipLine>.
2212 <SkipString>"//"/[^\n]*                 { 
2213                                         }
2214 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
2215                                           g_lastCPPContext=YY_START;
2216                                           BEGIN(RemoveCPPComment);
2217                                         }
2218 <SkipString>"/*"/[^\n]*                 { 
2219                                         }
2220 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
2221                                           g_lastCContext=YY_START;
2222                                           BEGIN(RemoveCComment);
2223                                         }
2224 <SkipLine>\n                            {
2225                                           outputChar('\n');
2226                                           g_yyLineNr++;  
2227                                           BEGIN(SkipCPPBlock);
2228                                         }
2229 <SkipString>[^"\\\n]+                   { }
2230 <SkipString>\\.                         { }
2231 <SkipString>\"                          {
2232                                           BEGIN(SkipLine);
2233                                         }
2234 <SkipString>.                           { }
2235 <IncludeID>{ID}{B}*/"("                 {
2236                                           g_nospaces=TRUE;
2237                                           g_roundCount=0;
2238                                           g_defArgsStr=yytext;
2239                                           g_findDefArgContext = IncludeID;
2240                                           BEGIN(FindDefineArgs);
2241                                         }
2242 <IncludeID>{ID}                         {
2243                                           g_nospaces=TRUE;
2244                                           readIncludeFile(expandMacro(yytext));
2245                                           BEGIN(Start);
2246                                         }
2247 <Include>[^\">\n]+[\">]                 { 
2248                                           g_incName+=yytext;
2249                                           readIncludeFile(g_incName);
2250                                           if (g_isImported)
2251                                           {
2252                                             BEGIN(EndImport);
2253                                           }
2254                                           else
2255                                           {
2256                                             BEGIN(Start);
2257                                           }
2258                                         }
2259 <EndImport>[^\\\n]*/\n                  {
2260                                           BEGIN(Start);
2261                                         }
2262 <EndImport>\\[\r]?"\n"                  { 
2263                                           outputChar('\n');
2264                                           g_yyLineNr++;
2265                                         }
2266 <EndImport>.                            {
2267                                         }
2268 <DefName>{ID}/("\\\n")*"("              { // define with argument
2269                                           //printf("Define() `%s'\n",yytext);
2270                                           g_argDict = new QDict<int>(31);
2271                                           g_argDict->setAutoDelete(TRUE);
2272                                           g_defArgs = 0; 
2273                                           g_defArgsStr.resize(0);
2274                                           g_defText.resize(0);
2275                                           g_defLitText.resize(0);
2276                                           g_defName = yytext;
2277                                           g_defVarArgs = FALSE;
2278                                           g_defExtraSpacing.resize(0);
2279                                           BEGIN(DefineArg);
2280                                         }
2281 <DefName>{ID}{B}+"1"/[ \r\t\n]          { // special case: define with 1 -> can be "guard"
2282                                           //printf("Define `%s'\n",yytext);
2283                                           g_argDict = 0;
2284                                           g_defArgs = -1;
2285                                           g_defArgsStr.resize(0);
2286                                           g_defName = yytext;
2287                                           g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace();
2288                                           g_defVarArgs = FALSE;
2289                                           //printf("Guard check: %s!=%s || %d\n",
2290                                           //    g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2291                                           if ( g_defName!=g_lastGuardName || !g_expectGuard)
2292                                           { // define may appear in the output
2293                                             QCString tmp=(QCString)"#define "+g_defName;
2294                                             outputArray(tmp.data(),tmp.length());
2295                                             g_quoteArg=FALSE;
2296                                             g_insideComment=FALSE;
2297                                             g_lastGuardName.resize(0);
2298                                             g_defText="1"; 
2299                                             g_defLitText="1"; 
2300                                             BEGIN(DefineText); 
2301                                           }
2302                                           else // define is a guard => hide
2303                                           {
2304                                             //printf("Found a guard %s\n",yytext);
2305                                             g_defText.resize(0);
2306                                             g_defLitText.resize(0);
2307                                             BEGIN(Start);
2308                                           }
2309                                           g_expectGuard=FALSE;
2310                                         }
2311 <DefName>{ID}/{B}*"\n"                  { // empty define
2312                                           g_argDict = 0;
2313                                           g_defArgs = -1;
2314                                           g_defName = yytext;
2315                                           g_defArgsStr.resize(0);
2316                                           g_defText.resize(0);
2317                                           g_defLitText.resize(0);
2318                                           g_defVarArgs = FALSE;
2319                                           //printf("Guard check: %s!=%s || %d\n",
2320                                           //    g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2321                                           if ( g_defName!=g_lastGuardName || !g_expectGuard)
2322                                           { // define may appear in the output
2323                                             QCString tmp=(QCString)"#define "+g_defName;
2324                                             outputArray(tmp.data(),tmp.length());
2325                                             g_quoteArg=FALSE;
2326                                             g_insideComment=FALSE;
2327                                             if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
2328                                             BEGIN(DefineText);
2329                                           }
2330                                           else // define is a guard => hide
2331                                           {
2332                                             //printf("Found a guard %s\n",yytext);
2333                                             g_guardName = yytext;
2334                                             g_lastGuardName.resize(0);
2335                                             BEGIN(Start);
2336                                           }
2337                                           g_expectGuard=FALSE;
2338                                         }
2339 <DefName>{ID}/{B}*                      { // define with content
2340                                           //printf("Define `%s'\n",yytext);
2341                                           g_argDict = 0;
2342                                           g_defArgs = -1;
2343                                           g_defArgsStr.resize(0);
2344                                           g_defText.resize(0);
2345                                           g_defLitText.resize(0);
2346                                           g_defName = yytext;
2347                                           g_defVarArgs = FALSE;
2348                                           QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
2349                                           outputArray(tmp.data(),tmp.length());
2350                                           g_quoteArg=FALSE;
2351                                           g_insideComment=FALSE;
2352                                           BEGIN(DefineText); 
2353                                         }
2354 <DefineArg>"\\\n"                       {
2355                                           g_defExtraSpacing+="\n";
2356                                           g_yyLineNr++;
2357                                         }
2358 <DefineArg>","{B}*                      { g_defArgsStr+=yytext; }
2359 <DefineArg>"("{B}*                      { g_defArgsStr+=yytext; }
2360 <DefineArg>{B}*")"{B}*                  {
2361                                           g_defArgsStr+=yytext; 
2362                                           QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing;
2363                                           outputArray(tmp.data(),tmp.length());
2364                                           g_quoteArg=FALSE;
2365                                           g_insideComment=FALSE;
2366                                           BEGIN(DefineText);
2367                                         }
2368 <DefineArg>"..."                        { // Variadic macro
2369                                           g_defVarArgs = TRUE;
2370                                           g_defArgsStr+=yytext;
2371                                           g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
2372                                           g_defArgs++;
2373                                         }
2374 <DefineArg>{ID}{B}*("..."?)             {
2375                                           //printf("Define addArg(%s)\n",yytext);
2376                                           QCString argName=yytext;
2377                                           g_defVarArgs = yytext[yyleng-1]=='.';
2378                                           if (g_defVarArgs) // strip ellipsis
2379                                           {
2380                                             argName=argName.left(argName.length()-3);
2381                                           }
2382                                           argName = argName.stripWhiteSpace();
2383                                           g_defArgsStr+=yytext;
2384                                           g_argDict->insert(argName,new int(g_defArgs)); 
2385                                           g_defArgs++;
2386                                         }
2387   /*
2388 <DefineText>"/ **"|"/ *!"                       {
2389                                           g_defText+=yytext;
2390                                           g_defLitText+=yytext;
2391                                           g_insideComment=TRUE;
2392                                         }
2393 <DefineText>"* /"                       {
2394                                           g_defText+=yytext;
2395                                           g_defLitText+=yytext;
2396                                           g_insideComment=FALSE;
2397                                         }
2398   */
2399 <DefineText>"/*"[!*]?                   {
2400                                           g_defText+=yytext;
2401                                           g_defLitText+=yytext;
2402                                           g_lastCContext=YY_START;
2403                                           g_commentCount=1;
2404                                           BEGIN(CopyCComment);
2405                                         }
2406 <DefineText>"//"[!/]?                   {
2407                                           outputArray(yytext,yyleng);
2408                                           g_lastCPPContext=YY_START;
2409                                           g_defLitText+=' ';
2410                                           BEGIN(SkipCPPComment);
2411                                         }
2412 <SkipCComment>[/]?"*/"                  {
2413                                           if (yytext[0]=='/') outputChar('/');
2414                                           outputChar('*');outputChar('/');
2415                                           if (--g_commentCount<=0)
2416                                           {
2417                                             if (g_lastCContext==Start) 
2418                                               // small hack to make sure that ^... rule will
2419                                               // match when going to Start... Example: "/*...*/ some stuff..."
2420                                             {
2421                                               YY_CURRENT_BUFFER->yy_at_bol=1;
2422                                             }
2423                                             BEGIN(g_lastCContext);  
2424                                           }
2425                                         }
2426 <SkipCComment>"//"("/")*                {
2427                                           outputArray(yytext,yyleng);
2428                                         }
2429 <SkipCComment>"/*"                      {
2430                                           outputChar('/');outputChar('*');
2431                                           //g_commentCount++;
2432                                         }
2433 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
2434                                           outputArray(yytext,yyleng);
2435                                         }
2436 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ {
2437                                           outputArray(yytext,yyleng);
2438                                           g_yyLineNr+=QCString(yytext).contains('\n');
2439                                         }
2440 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+  {
2441                                           outputArray(yytext,yyleng);
2442                                           g_yyLineNr+=QCString(yytext).contains('\n');
2443                                           if (yytext[1]=='f')
2444                                           {
2445                                             g_blockName="f";
2446                                           }
2447                                           else
2448                                           {
2449                                             g_blockName=QCString(&yytext[1]).stripWhiteSpace();
2450                                           }
2451                                           BEGIN(SkipVerbatim);
2452                                         }
2453 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t]+  { // conditional section
2454                                           g_condCtx = YY_START;
2455                                           outputArray(yytext,yyleng);
2456                                           BEGIN(CondLine);
2457                                         }
2458 <CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]*     {
2459                                           startCondSection(yytext);
2460                                           outputArray(yytext,yyleng);
2461                                           BEGIN(g_condCtx);
2462                                         }
2463 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*/\n {
2464                                           g_condCtx = YY_START;
2465                                           outputArray(yytext,yyleng);
2466                                         }
2467 <CondLine>.                             {
2468                                           unput(*yytext);
2469                                           startCondSection(" ");
2470                                           BEGIN(g_condCtx);
2471                                         }
2472 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9] {
2473                                           outputArray(yytext,yyleng);
2474                                           endCondSection();
2475                                         }
2476 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
2477                                           outputArray(yytext,yyleng);
2478                                           if (yytext[1]=='f' && g_blockName=="f")
2479                                           {
2480                                             BEGIN(SkipCComment);
2481                                           }
2482                                           else if (&yytext[4]==g_blockName)
2483                                           {
2484                                             BEGIN(SkipCComment);
2485                                           }
2486                                         }
2487 <SkipVerbatim>"*/"|"/*"                 {
2488                                           outputArray(yytext,yyleng);
2489                                         }
2490 <SkipCComment,SkipVerbatim>[^*\\@\x06\n\/]+ {
2491                                           outputArray(yytext,yyleng);
2492                                         }
2493 <SkipCComment,SkipVerbatim>\n           { 
2494                                           g_yyLineNr++;
2495                                           outputChar('\n');
2496                                         }
2497 <SkipCComment,SkipVerbatim>.            {
2498                                           outputChar(*yytext);
2499                                         }
2500 <CopyCComment>[^*a-z_A-Z\n]+            {
2501                                           g_defLitText+=yytext;
2502                                           g_defText+=escapeAt(yytext);
2503                                         }
2504 <CopyCComment>"*/"                      {
2505                                           g_defLitText+=yytext;
2506                                           g_defText+=yytext;
2507                                           BEGIN(g_lastCContext);
2508                                         }
2509 <CopyCComment>\n                        { 
2510                                           g_yyLineNr++;
2511                                           g_defLitText+=yytext;
2512                                           g_defText+=' ';
2513                                         }
2514 <RemoveCComment>"*/"{B}*"#"             { // see bug 594021 for a usecase for this rule
2515                                           if (g_lastCContext==SkipCPPBlock)
2516                                           {
2517                                             BEGIN(SkipCommand);
2518                                           }
2519                                           else
2520                                           {
2521                                             REJECT;
2522                                           }
2523                                         }
2524 <RemoveCComment>"*/"                    { BEGIN(g_lastCContext); }
2525 <RemoveCComment>"//"                    
2526 <RemoveCComment>"/*"
2527 <RemoveCComment>[^*\x06\n]+
2528 <RemoveCComment>\n                      { g_yyLineNr++; outputChar('\n'); }
2529 <RemoveCComment>.                       
2530 <SkipCPPComment>[^\n\/\\@]+             {
2531                                           outputArray(yytext,yyleng);
2532                                         }
2533 <SkipCPPComment,RemoveCPPComment>\n     {
2534                                           unput(*yytext);
2535                                           BEGIN(g_lastCPPContext);
2536                                         }
2537 <SkipCPPComment>"/*"                    {
2538                                           outputChar('/');outputChar('*');
2539                                         }
2540 <SkipCPPComment>"//"                    {
2541                                           outputChar('/');outputChar('/');
2542                                         }
2543 <SkipCPPComment>[^\x06\@\\\n]+          {
2544                                           outputArray(yytext,yyleng);
2545                                         }
2546 <SkipCPPComment>.                       {
2547                                           outputChar(*yytext);
2548                                         }
2549 <RemoveCPPComment>"/*"
2550 <RemoveCPPComment>"//"
2551 <RemoveCPPComment>[^\x06\n]+
2552 <RemoveCPPComment>.
2553 <DefineText>"#"                         {
2554                                           g_quoteArg=TRUE;
2555                                           g_defLitText+=yytext;
2556                                         }
2557 <DefineText,CopyCComment>{ID}           {
2558                                           g_defLitText+=yytext;
2559                                           if (g_quoteArg)
2560                                           {
2561                                             g_defText+="\"";
2562                                           }
2563                                           if (g_defArgs>0)
2564                                           {
2565                                             int *n;
2566                                             if ((n=(*g_argDict)[yytext]))
2567                                             {
2568                                               //if (!g_quoteArg) g_defText+=' ';
2569                                               g_defText+='@';
2570                                               QCString numStr;
2571                                               numStr.sprintf("%d",*n);
2572                                               g_defText+=numStr;
2573                                               //if (!g_quoteArg) g_defText+=' ';
2574                                             }
2575                                             else
2576                                             {
2577                                               g_defText+=yytext;
2578                                             }
2579                                           }
2580                                           else
2581                                           {
2582                                             g_defText+=yytext;
2583                                           }
2584                                           if (g_quoteArg)
2585                                           {
2586                                             g_defText+="\"";
2587                                           }
2588                                           g_quoteArg=FALSE;
2589                                         }
2590 <CopyCComment>.                         {
2591                                           g_defLitText+=yytext;
2592                                           g_defText+=yytext;
2593                                         }
2594 <DefineText>\\[\r]?\n                   { 
2595                                           g_defLitText+=yytext;
2596                                           outputChar('\n');
2597                                           g_defText += ' '; g_yyLineNr++; 
2598                                         }
2599 <DefineText>\n                          {
2600                                           QCString comment=extractTrailingComment(g_defLitText);
2601                                           g_defLitText+=yytext;
2602                                           if (!comment.isEmpty())
2603                                           {
2604                                             outputArray(comment,comment.length());
2605                                             g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
2606                                           }
2607                                           outputChar('\n');
2608                                           Define *def=0;
2609                                           //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
2610                                           if (g_includeStack.isEmpty() || g_curlyCount>0) 
2611                                           {
2612                                             addDefine();
2613                                           }
2614                                           def=DefineManager::instance().isDefined(g_defName);
2615                                           if (def==0) // new define
2616                                           {
2617                                             //printf("new define '%s'!\n",g_defName.data());
2618                                             Define *nd = newDefine();
2619                                             DefineManager::instance().addDefine(g_yyFileName,nd);
2620
2621                                             // also add it to the local file list if it is a source file
2622                                             //if (g_isSource && g_includeStack.isEmpty())
2623                                             //{
2624                                             //  g_fileDefineDict->insert(g_defName,nd);
2625                                             //}
2626                                           }
2627                                           else if (def /*&& macroIsAccessible(def)*/)
2628                                                // name already exists
2629                                           {
2630                                             //printf("existing define!\n");
2631                                             //printf("define found\n");
2632                                             if (def->undef) // undefined name
2633                                             {
2634                                               def->undef = FALSE;
2635                                               def->name = g_defName;
2636                                               def->definition = g_defText.stripWhiteSpace();
2637                                               def->nargs = g_defArgs;
2638                                               def->fileName = g_yyFileName.copy(); 
2639                                               def->lineNr = g_yyLineNr;
2640                                             }
2641                                             else
2642                                             {
2643                                               //printf("error: define %s is defined more than once!\n",g_defName.data());
2644                                             }
2645                                           }
2646                                           delete g_argDict; g_argDict=0;
2647                                           g_yyLineNr++;
2648                                           g_lastGuardName.resize(0);
2649                                           BEGIN(Start);
2650                                         }
2651 <DefineText>{B}*                        { g_defText += ' '; g_defLitText+=yytext; }
2652 <DefineText>{B}*"##"{B}*                { g_defText += "##"; g_defLitText+=yytext; }
2653 <DefineText>"@"                         { g_defText += "@@"; g_defLitText+=yytext; }
2654 <DefineText>\"                          { 
2655                                           g_defText += *yytext; 
2656                                           g_defLitText+=yytext; 
2657                                           if (!g_insideComment)
2658                                           {
2659                                             BEGIN(SkipDoubleQuote);
2660                                           }
2661                                         }
2662 <DefineText>\'                          { g_defText += *yytext;
2663                                           g_defLitText+=yytext; 
2664                                           if (!g_insideComment)
2665                                           {
2666                                             BEGIN(SkipSingleQuote);
2667                                           }
2668                                         }
2669 <SkipDoubleQuote>"//"[/]?               { g_defText += yytext; g_defLitText+=yytext; }
2670 <SkipDoubleQuote>"/*"                   { g_defText += yytext; g_defLitText+=yytext; }
2671 <SkipDoubleQuote>\"                     {
2672                                           g_defText += *yytext; g_defLitText+=yytext; 
2673                                           BEGIN(DefineText);
2674                                         }
2675 <SkipSingleQuote,SkipDoubleQuote>\\.    {
2676                                           g_defText += yytext; g_defLitText+=yytext;
2677                                         }
2678 <SkipSingleQuote>\'                     {
2679                                           g_defText += *yytext; g_defLitText+=yytext;
2680                                           BEGIN(DefineText);
2681                                         }
2682 <SkipDoubleQuote>.                      { g_defText += *yytext; g_defLitText+=yytext; }
2683 <SkipSingleQuote>.                      { g_defText += *yytext; g_defLitText+=yytext; }
2684 <DefineText>.                           { g_defText += *yytext; g_defLitText+=yytext; }
2685 <<EOF>>                                 {
2686                                           //fprintf(stderr,"End of include file\n");
2687                                           //printf("Include stack depth=%d\n",g_includeStack.count());
2688                                           if (g_includeStack.isEmpty())
2689                                           {
2690                                             //fprintf(stderr,"Terminating scanner!\n");
2691                                             yyterminate();
2692                                           }
2693                                           else
2694                                           {
2695                                             FileState *fs=g_includeStack.pop();
2696                                             //fileDefineCache->merge(g_yyFileName,fs->fileName);
2697                                             YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2698                                             yy_switch_to_buffer( fs->bufState );
2699                                             yy_delete_buffer( oldBuf );
2700                                             g_yyLineNr    = fs->lineNr;
2701                                             //preYYin = fs->oldYYin;
2702                                             g_inputBuf    = fs->oldFileBuf;
2703                                             g_inputBufPos = fs->oldFileBufPos;
2704                                             setFileName(fs->fileName);
2705                                             //fprintf(stderr,"######## FileName %s\n",g_yyFileName.data());
2706                                             
2707                                             // Deal with file changes due to 
2708                                             // #include's within { .. } blocks
2709                                             QCString lineStr(15+g_yyFileName.length());
2710                                             lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
2711                                             outputArray(lineStr.data(),lineStr.length());
2712                                             
2713                                             delete fs; fs=0;
2714                                           }
2715                                         }
2716 <*>"/*"/"*/"                            |
2717 <*>"/*"[*]?                             {
2718                                           outputArray(yytext,yyleng);
2719                                           g_lastCContext=YY_START;
2720                                           g_commentCount=1;
2721                                           if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2722                                           BEGIN(SkipCComment);
2723                                         }
2724 <*>"//"[/]?                             {
2725                                           outputArray(yytext,yyleng);
2726                                           g_lastCPPContext=YY_START;
2727                                           if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2728                                           BEGIN(SkipCPPComment);
2729                                         }
2730 <*>\n                                   { 
2731                                           outputChar('\n');
2732                                           g_yyLineNr++; 
2733                                         }
2734 <*>.                                    {
2735                                           g_expectGuard = FALSE;
2736                                           outputChar(*yytext);
2737                                         }
2738
2739 %%
2740
2741 /*@ ----------------------------------------------------------------------------
2742  */
2743
2744 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
2745 {
2746   //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2747   if (pos<expr.length())
2748   {
2749     //printf("%c=expr()\n",expr.at(pos));
2750     return expr.at(pos++);
2751   }
2752   else if (rest && !rest->isEmpty())
2753   {
2754     int cc=rest->at(0);
2755     *rest=rest->right(rest->length()-1);
2756     //printf("%c=rest\n",cc);
2757     return cc;
2758   }
2759   else
2760   {
2761     int cc=yyinput();
2762     //printf("%c=yyinput()\n",cc);
2763     return cc;
2764   }
2765 }
2766  
2767 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
2768 {
2769   //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2770   if (pos<expr.length())
2771   {
2772     //printf("%c=expr()\n",expr.at(pos));
2773     return expr.at(pos);
2774   }
2775   else if (rest && !rest->isEmpty())
2776   {
2777     int cc=rest->at(0);
2778     //printf("%c=rest\n",cc);
2779     return cc;
2780   }
2781   else
2782   {
2783     int cc=yyinput();
2784     returnCharToStream(cc);
2785     //unput((char)cc);
2786     //printf("%c=yyinput()\n",cc);
2787     return cc;
2788   }
2789 }
2790
2791 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
2792 {
2793   //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2794   if (pos<expr.length())
2795   {
2796     pos++;
2797   }
2798   else if (rest)
2799   {
2800     //printf("Prepending to rest!\n");
2801     char cs[2];cs[0]=c;cs[1]='\0';
2802     rest->prepend(cs);
2803   }
2804   else
2805   {
2806     //unput(c);
2807     returnCharToStream(c);
2808   }
2809   //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2810 }
2811
2812 void addSearchDir(const char *dir)
2813 {
2814   QFileInfo fi(dir);
2815   if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8());
2816
2817
2818 void initPreprocessor()
2819 {
2820   g_pathList = new QStrList;
2821   addSearchDir(".");
2822   g_expandedDict = new DefineDict(17);
2823 }
2824
2825 void cleanUpPreprocessor()
2826 {
2827   delete g_expandedDict; g_expandedDict=0;
2828   delete g_pathList; g_pathList=0;
2829   DefineManager::deleteInstance();
2830 }
2831
2832
2833 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
2834 {
2835   uint orgOffset=output.curPos();
2836   //printf("##########################\n%s\n####################\n",
2837   //    input.data());
2838
2839   g_macroExpansion = Config_getBool("MACRO_EXPANSION");
2840   g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF");
2841   g_curlyCount=0;
2842   g_nospaces=FALSE;
2843   g_inputBuf=&input;
2844   g_inputBufPos=0;
2845   g_outputBuf=&output;
2846   g_includeStack.setAutoDelete(TRUE);
2847   g_includeStack.clear();
2848   g_expandedDict->setAutoDelete(FALSE);
2849   g_expandedDict->clear();
2850   g_condStack.clear();
2851   g_condStack.setAutoDelete(TRUE);
2852   //g_fileDefineDict->clear();
2853
2854   setFileName(fileName);
2855   g_inputFileDef = g_yyFileDef;
2856   DefineManager::instance().startContext(g_yyFileName);
2857   
2858   static bool firstTime=TRUE;
2859   if (firstTime)
2860   {
2861     // add predefined macros
2862     char *defStr;
2863     QStrList &predefList = Config_getList("PREDEFINED");
2864     QStrListIterator sli(predefList);
2865     for (sli.toFirst();(defStr=sli.current());++sli)
2866     {
2867       QCString ds = defStr;
2868       int i_equals=ds.find('=');
2869       int i_obrace=ds.find('(');
2870       int i_cbrace=ds.find(')');
2871       bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
2872
2873       if (i_obrace==0) continue; // no define name
2874
2875       if (i_obrace<i_equals && i_cbrace<i_equals && 
2876           i_obrace!=-1      && i_cbrace!=-1      && 
2877           i_obrace<i_cbrace
2878          ) // predefined function macro definition
2879       {
2880         //printf("predefined function macro '%s'\n",defStr);
2881         QRegExp reId("[a-z_A-Z][a-z_A-Z0-9]*"); // regexp matching an id
2882         QDict<int> argDict(17);
2883         argDict.setAutoDelete(TRUE);
2884         int i=i_obrace+1,p,l,count=0;
2885         // gather the formal arguments in a dictionary 
2886         while (i<i_cbrace && (p=reId.match(ds,i,&l)))
2887         {
2888           argDict.insert(ds.mid(p,l),new int(count++));
2889           i=p+l;
2890         }
2891         // strip definition part
2892         QCString tmp=ds.right(ds.length()-i_equals-1);
2893         QCString definition;
2894         i=0;
2895         // substitute all occurrences of formal arguments by their 
2896         // corresponding markers
2897         while ((p=reId.match(tmp,i,&l))!=-1)
2898         {
2899           if (p>i) definition+=tmp.mid(i,p-i);
2900           int *argIndex;
2901           if ((argIndex=argDict[tmp.mid(p,l)])!=0)
2902           {
2903             QCString marker;
2904             marker.sprintf(" @%d ",*argIndex);
2905             definition+=marker;
2906           }
2907           else
2908           {
2909             definition+=tmp.mid(p,l);
2910           }
2911           i=p+l;
2912         }
2913         if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
2914
2915         // add define definition to the dictionary of defines for this file
2916         QCString dname = ds.left(i_obrace);
2917         if (!dname.isEmpty())
2918         {
2919           Define *def = new Define;
2920           def->name         = dname;
2921           def->definition   = definition; 
2922           def->nargs        = count;
2923           def->isPredefined = TRUE;
2924           def->nonRecursive = nonRecursive;
2925           def->fileDef      = g_yyFileDef;
2926           def->fileName     = fileName;
2927           DefineManager::instance().addDefine(g_yyFileName,def);
2928         }
2929
2930         //printf("#define `%s' `%s' #nargs=%d\n",
2931         //  def->name.data(),def->definition.data(),def->nargs);
2932       }
2933       else if ((i_obrace==-1 || i_obrace>i_equals) &&
2934           (i_cbrace==-1 || i_cbrace>i_equals) &&
2935           !ds.isEmpty() && (int)ds.length()>i_equals
2936           ) // predefined non-function macro definition
2937       {
2938         //printf("predefined normal macro '%s'\n",defStr);
2939         Define *def = new Define;
2940         if (i_equals==-1) // simple define without argument
2941         {
2942           def->name = ds;
2943           def->definition = "1"; // substitute occurrences by 1 (true)
2944         }
2945         else // simple define with argument
2946         {
2947           int ine=i_equals - (nonRecursive ? 1 : 0);
2948           def->name = ds.left(ine);
2949           def->definition = ds.right(ds.length()-i_equals-1);
2950         }
2951         if (!def->name.isEmpty())
2952         {
2953           def->nargs = -1;
2954           def->isPredefined = TRUE;
2955           def->nonRecursive = nonRecursive;
2956           def->fileDef      = g_yyFileDef;
2957           def->fileName     = fileName;
2958           DefineManager::instance().addDefine(g_yyFileName,def);
2959         }
2960         else
2961         {
2962           delete def;
2963         }
2964
2965         //printf("#define `%s' `%s' #nargs=%d\n",
2966         //  def->name.data(),def->definition.data(),def->nargs);
2967       }
2968     }
2969     //firstTime=FALSE;
2970   }
2971  
2972   g_yyLineNr = 1;
2973   g_level    = 0;
2974   g_ifcount  = 0;
2975
2976   BEGIN( Start );
2977   
2978   g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
2979   g_guardName.resize(0);
2980   g_lastGuardName.resize(0);
2981   g_guardExpr.resize(0);
2982   
2983   preYYlex();
2984   g_lexInit=TRUE;
2985
2986   // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
2987   forceEndCondSection();
2988
2989   // remove locally defined macros so they can be redefined in another source file
2990   //if (g_fileDefineDict->count()>0)
2991   //{
2992   //  QDictIterator<Define> di(*g_fileDefineDict);
2993   //  Define *d;
2994   //  for (di.toFirst();(d=di.current());++di)
2995   //  {
2996   //    g_globalDefineDict->remove(di.currentKey());
2997   //  }
2998   //  g_fileDefineDict->clear();
2999   //}
3000
3001   if (Debug::isFlagSet(Debug::Preprocessor))
3002   {
3003     char *orgPos=output.data()+orgOffset;
3004     char *newPos=output.data()+output.curPos();
3005     Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos);
3006     int line=1;
3007     Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
3008     while (orgPos<newPos) 
3009     {
3010       putchar(*orgPos);
3011       if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3012       orgPos++;
3013     }
3014     Debug::print(Debug::Preprocessor,0,"\n---------\n");
3015     if (DefineManager::instance().defineContext().count()>0)
3016     {
3017       Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n");
3018       Debug::print(Debug::Preprocessor,0,"---------\n");
3019       QDictIterator<Define> di(DefineManager::instance().defineContext());
3020       Define *def;
3021       for (di.toFirst();(def=di.current());++di)
3022       {
3023         Debug::print(Debug::Preprocessor,0,"%s ",def->name.data());
3024       }
3025       Debug::print(Debug::Preprocessor,0,"\n---------\n");
3026     }
3027     else
3028     {
3029       Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n");
3030     }
3031   }
3032   DefineManager::instance().endContext();
3033 }
3034
3035 void preFreeScanner()
3036 {
3037 #if defined(YY_FLEX_SUBMINOR_VERSION) 
3038   if (g_lexInit)
3039   {
3040     preYYlex_destroy();
3041   }
3042 #endif
3043 }
3044
3045 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
3046 extern "C" { // some bogus code to keep the compiler happy
3047 //  int  preYYwrap() { return 1 ; }
3048   void preYYdummy() { yy_flex_realloc(0,0); } 
3049 }
3050 #endif
3051