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