Imported Upstream version 1.8.8
[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 || // same number of arguments
890       (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
891                                                 // params as the non-variadic part (see bug731985)
892   {
893     uint k=0;
894     // substitution of all formal arguments
895     QCString resExpr;
896     const QCString d=def->definition.stripWhiteSpace();
897     //printf("Macro definition: %s\n",d.data());
898     bool inString=FALSE;
899     while (k<d.length())
900     {
901       if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
902       {
903         if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
904         {
905           k+=2;
906           resExpr+="@@"; // we unescape these later
907         }
908         else if (d.at(k+1)=='-') // no-rescan marker
909         {
910           k+=2;
911           resExpr+="@-";
912         }
913         else // argument marker => read the argument number
914         {
915           QCString key="@";
916           QCString *subst=0;
917           bool hash=FALSE;
918           int l=k-1;
919           // search for ## backward
920           if (l>=0 && d.at(l)=='"') l--;
921           while (l>=0 && d.at(l)==' ') l--;
922           if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
923           k++;
924           // scan the number
925           while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
926           if (!hash) 
927           {
928             // search for ## forward
929             l=k;
930             if (l<(int)d.length() && d.at(l)=='"') l++;
931             while (l<(int)d.length() && d.at(l)==' ') l++;
932             if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
933           }
934           //printf("request key %s result %s\n",key.data(),argTable[key]->data());
935           if (key.length()>1 && (subst=argTable[key])) 
936           {
937             QCString substArg=*subst;
938             //printf("substArg=`%s'\n",substArg.data());
939             // only if no ## operator is before or after the argument
940             // marker we do macro expansion.
941             if (!hash) expandExpression(substArg,0,0);
942             if (inString)
943             {
944               //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
945
946               // if the marker is inside a string (because a # was put 
947               // before the macro name) we must escape " and \ characters
948               resExpr+=stringize(substArg);
949             }
950             else
951             {
952               if (hash && substArg.isEmpty())
953               {
954                 resExpr+="@E"; // empty argument will be remove later on
955               }
956               else if (g_nospaces)
957               {
958                 resExpr+=substArg;
959               }
960               else
961               {
962                 resExpr+=" "+substArg+" ";
963               }
964             }
965           }
966         }
967       }
968       else // no marker, just copy
969       {
970         if (!inString && d.at(k)=='\"') 
971         {
972           inString=TRUE; // entering a literal string
973         }
974         else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
975         {
976           inString=FALSE; // leaving a literal string
977         }
978         resExpr+=d.at(k++);
979       }
980     }
981     len=j-pos;
982     result=resExpr;
983     //printf("result after substitution `%s' expr=`%s'\n",
984     //       result.data(),expr.mid(pos,len).data());
985     return TRUE;
986   }
987   return FALSE;
988 }
989
990
991 /*! returns the next identifier in string \a expr by starting at position \a p.
992  * The position of the identifier is returned (or -1 if nothing is found)
993  * and \a l is its length. Any quoted strings are skipping during the search.
994  */
995 static int getNextId(const QCString &expr,int p,int *l)
996 {
997   int n;
998   while (p<(int)expr.length())
999   {
1000     char c=expr.at(p++);
1001     if (isdigit(c)) // skip number
1002     {
1003       while (p<(int)expr.length() && isId(expr.at(p))) p++;
1004     }
1005     else if (isalpha(c) || c=='_') // read id
1006     {
1007       n=p-1;
1008       while (p<(int)expr.length() && isId(expr.at(p))) p++;
1009       *l=p-n;
1010       return n; 
1011     }
1012     else if (c=='"') // skip string
1013     {
1014       char ppc=0,pc=c;
1015       if (p<(int)expr.length()) c=expr.at(p);
1016       while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) 
1017         // continue as long as no " is found, but ignoring \", but not \\"
1018       {
1019         ppc=pc;
1020         pc=c;
1021         c=expr.at(p);
1022         p++;
1023       }
1024       if (p<(int)expr.length()) ++p; // skip closing quote
1025     }
1026     else if (c=='/') // skip C Comment
1027     {
1028       //printf("Found C comment at p=%d\n",p);
1029       char pc=c;
1030       if (p<(int)expr.length()) 
1031       {
1032         c=expr.at(p);
1033         if (c=='*')  // Start of C comment
1034         { 
1035           p++;
1036           while (p<(int)expr.length() && !(pc=='*' && c=='/'))
1037           {
1038             pc=c;
1039             c=expr.at(p++);
1040           }
1041         }
1042       }
1043       //printf("Found end of C comment at p=%d\n",p);
1044     }
1045   }
1046   return -1;
1047 }
1048
1049 /*! preforms recursive macro expansion on the string \a expr
1050  *  starting at position \a pos.
1051  *  May read additional characters from the input while re-scanning!
1052  *  If \a expandAll is \c TRUE then all macros in the expression are
1053  *  expanded, otherwise only the first is expanded.
1054  */
1055 static void expandExpression(QCString &expr,QCString *rest,int pos)
1056 {
1057   //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
1058   QCString macroName;
1059   QCString expMacro;
1060   bool definedTest=FALSE;
1061   int i=pos,l,p,len;
1062   while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
1063   {
1064     bool replaced=FALSE;
1065     macroName=expr.mid(p,l);
1066     //printf("macroName=%s\n",macroName.data());
1067     if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
1068     {
1069       if (g_expandedDict->find(macroName)==0) // expand macro
1070       {
1071         Define *def=DefineManager::instance().isDefined(macroName);
1072         if (definedTest) // macro name was found after defined 
1073         {
1074           if (def) expMacro = " 1 "; else expMacro = " 0 ";
1075           replaced=TRUE;
1076           len=l;
1077           definedTest=FALSE;
1078         }
1079         else if (def && def->nargs==-1) // simple macro
1080         {
1081           // substitute the definition of the macro
1082           //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
1083           if (g_nospaces)
1084           {
1085             expMacro=def->definition.stripWhiteSpace();
1086           }
1087           else
1088           {
1089             expMacro=" "+def->definition.stripWhiteSpace()+" ";
1090           }
1091           //expMacro=def->definition.stripWhiteSpace();
1092           replaced=TRUE;
1093           len=l;
1094           //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
1095         }
1096         else if (def && def->nargs>=0) // function macro
1097         {
1098           replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
1099           len+=l;
1100         }
1101         else if (macroName=="defined")
1102         {
1103           //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
1104           definedTest=TRUE;
1105         }
1106
1107         if (replaced) // expand the macro and rescan the expression
1108         {
1109             
1110           //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
1111           QCString resultExpr=expMacro;
1112           QCString restExpr=expr.right(expr.length()-len-p);
1113           processConcatOperators(resultExpr);
1114           if (def && !def->nonRecursive)
1115           {
1116             g_expandedDict->insert(macroName,def);
1117             expandExpression(resultExpr,&restExpr,0);
1118             g_expandedDict->remove(macroName);
1119           }
1120           expr=expr.left(p)+resultExpr+restExpr;
1121           i=p;
1122           //printf("new expression: %s\n",expr.data());
1123         }
1124         else // move to the next macro name
1125         {
1126           //printf("moving to the next macro old=%d new=%d\n",i,p+l);
1127           i=p+l;
1128         }
1129       }
1130       else // move to the next macro name
1131       {
1132         expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
1133         //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
1134         i=p+l+2;
1135         //i=p+l;
1136       }
1137     }
1138     else // no re-scan marker found, skip the macro name
1139     {
1140       //printf("skipping marked macro\n");
1141       i=p+l;
1142     }
1143   }
1144 }
1145
1146 /*! replaces all occurrences of @@@@ in \a s by @@
1147  *  and removes all occurrences of @@E.
1148  *  All identifiers found are replaced by 0L
1149  */
1150 QCString removeIdsAndMarkers(const char *s)
1151 {
1152   //printf("removeIdsAndMarkers(%s)\n",s);
1153   const char *p=s;
1154   char c;
1155   bool inNum=FALSE;
1156   QCString result;
1157   if (p)
1158   {
1159     while ((c=*p))
1160     {
1161       if (c=='@') // replace @@ with @ and remove @E
1162       {
1163         if (*(p+1)=='@')
1164         {
1165           result+=c; 
1166         }
1167         else if (*(p+1)=='E')
1168         {
1169           // skip
1170         }
1171         p+=2;
1172       }
1173       else if (isdigit(c)) // number
1174       {
1175         result+=c;
1176         p++;
1177         inNum=TRUE;     
1178       }
1179       else if (c=='d' && !inNum) // identifier starting with a `d'
1180       {
1181         if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0) 
1182                    // defined keyword
1183         {
1184           p+=7; // skip defined
1185         }
1186         else
1187         {
1188           result+="0L";
1189           p++;
1190           while ((c=*p) && isId(c)) p++;
1191         }
1192       }
1193       else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
1194       {
1195         result+="0L";
1196         p++;
1197         while ((c=*p) && isId(c)) p++;
1198         if (*p=='(') // undefined function macro
1199         {
1200           p++;
1201           int count=1;
1202           while ((c=*p++))
1203           {
1204             if (c=='(') count++;
1205             else if (c==')')
1206             {
1207               count--;
1208               if (count==0) break;
1209             }
1210             else if (c=='/')
1211             {
1212               char pc=c;
1213               c=*++p;
1214               if (c=='*') // start of C comment
1215               {
1216                 while (*p && !(pc=='*' && c=='/')) // search end of comment
1217                 {
1218                   pc=c;
1219                   c=*++p;
1220                 }
1221                 p++;
1222               }
1223             }
1224           }
1225         }
1226       }
1227       else if (c=='/') // skip C comments
1228       {
1229         char pc=c;
1230         c=*++p;
1231         if (c=='*') // start of C comment
1232         { 
1233           while (*p && !(pc=='*' && c=='/')) // search end of comment
1234           {
1235             pc=c;
1236             c=*++p;
1237           }
1238           p++;
1239         }
1240         else // oops, not comment but division
1241         {
1242           result+=pc;
1243           goto nextChar;
1244         }
1245       }
1246       else 
1247       {
1248 nextChar:
1249         result+=c;
1250         char lc=tolower(c);
1251         if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
1252         p++;
1253       }
1254     }
1255   }
1256   //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
1257   return result;
1258 }
1259
1260 /*! replaces all occurrences of @@ in \a s by @
1261  *  \par assumption: 
1262  *   \a s only contains pairs of @@'s
1263  */
1264 QCString removeMarkers(const char *s)
1265 {
1266   const char *p=s;
1267   char c;
1268   QCString result;
1269   if (p)
1270   {
1271     while ((c=*p))
1272     {
1273       switch(c)
1274       {
1275         case '@': // replace @@ with @
1276           {
1277             if (*(p+1)=='@')
1278             {
1279               result+=c; 
1280             }
1281             p+=2;
1282           }
1283           break;
1284         case '/': // skip C comments
1285           {
1286             result+=c;
1287             char pc=c;
1288             c=*++p;
1289             if (c=='*') // start of C comment
1290             { 
1291               while (*p && !(pc=='*' && c=='/')) // search end of comment
1292               {
1293                 if (*p=='@' && *(p+1)=='@') 
1294                   result+=c,p++;
1295                 else 
1296                   result+=c;
1297                 pc=c;
1298                 c=*++p;
1299               }
1300               if (*p) result+=c,p++;
1301             }
1302           }
1303           break;
1304         case '"': // skip string literals
1305           {
1306             result+=c;
1307             char pc=c;
1308             c=*++p;
1309             while (*p && (c!='"' || pc=='\\')) // no end quote
1310             {
1311               result+=c;
1312               c=*++p;
1313             }
1314             if (*p) result+=c,p++; 
1315           }
1316           break;
1317         case '\'': // skip char literals
1318           {
1319             result+=c;
1320             char pc=c;
1321             c=*++p;
1322             while (*p && (c!='\'' || pc=='\\')) // no end quote
1323             {
1324               result+=c;
1325               c=*++p;
1326             }
1327             if (*p) result+=c,p++; 
1328           }
1329           break;
1330         default:
1331           {
1332             result+=c;
1333             p++;
1334           }
1335           break;
1336       }
1337     }
1338   }
1339   //printf("RemoveMarkers(%s)=%s\n",s,result.data());
1340   return result;
1341 }
1342
1343 /*! compute the value of the expression in string \a expr.
1344  *  If needed the function may read additional characters from the input.
1345  */
1346
1347 bool computeExpression(const QCString &expr)
1348 {
1349   QCString e=expr;
1350   expandExpression(e,0,0);
1351   //printf("after expansion `%s'\n",e.data());
1352   e = removeIdsAndMarkers(e);
1353   if (e.isEmpty()) return FALSE;
1354   //printf("parsing `%s'\n",e.data());
1355   return parseconstexp(g_yyFileName,g_yyLineNr,e);
1356 }
1357
1358 /*! expands the macro definition in \a name
1359  *  If needed the function may read additional characters from the input
1360  */
1361
1362 QCString expandMacro(const QCString &name)
1363 {
1364   QCString n=name;
1365   expandExpression(n,0,0);
1366   n=removeMarkers(n);
1367   //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
1368   return n;
1369 }
1370
1371 Define *newDefine()
1372 {
1373   Define *def=new Define;
1374   def->name       = g_defName;
1375   def->definition = g_defText.stripWhiteSpace();
1376   def->nargs      = g_defArgs;
1377   def->fileName   = g_yyFileName; 
1378   def->fileDef    = g_yyFileDef;
1379   def->lineNr     = g_yyLineNr-g_yyMLines;
1380   def->columnNr   = g_yyColNr;
1381   def->varArgs    = g_defVarArgs;
1382   //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
1383   //    def->fileDef ? def->fileDef->name().data() : def->fileName.data());
1384   //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
1385   if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
1386   {
1387     def->isPredefined=TRUE;
1388   }
1389   return def;
1390 }
1391
1392 void addDefine()
1393 {
1394   if (g_skip) return; // do not add this define as it is inside a 
1395                       // conditional section (cond command) that is disabled.
1396   if (!Doxygen::gatherDefines) return;
1397
1398   //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
1399   //ArgumentList *al = new ArgumentList;
1400   //stringToArgumentList(g_defArgsStr,al);
1401   MemberDef *md=new MemberDef(
1402       g_yyFileName,g_yyLineNr-g_yyMLines,g_yyColNr,
1403       "#define",g_defName,g_defArgsStr,0,
1404       Public,Normal,FALSE,Member,MemberType_Define,0,0);
1405   if (!g_defArgsStr.isEmpty())
1406   {
1407     ArgumentList *argList = new ArgumentList;
1408     //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
1409     stringToArgumentList(g_defArgsStr,argList);
1410     md->setArgumentList(argList);
1411   }
1412   //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
1413   int l=g_defLitText.find('\n');
1414   if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
1415   {
1416     // strip first line if it only contains a slash
1417     g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
1418   }
1419   else if (l>0)
1420   {
1421     // align the items on the first line with the items on the second line
1422     int k=l+1;
1423     const char *p=g_defLitText.data()+k;
1424     char c;
1425     while ((c=*p++) && (c==' ' || c=='\t')) k++;
1426     g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
1427   }
1428   md->setInitializer(g_defLitText.stripWhiteSpace());
1429
1430   //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef);
1431   md->setFileDef(g_inputFileDef);
1432   md->setDefinition("#define "+g_defName);
1433
1434   MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
1435   if (mn==0)
1436   {
1437     mn = new MemberName(g_defName);
1438     Doxygen::functionNameSDict->append(g_defName,mn);
1439   }
1440   mn->append(md);
1441   if (g_yyFileDef) 
1442   {
1443     g_yyFileDef->insertMember(md);
1444   }
1445
1446   //Define *d;
1447   //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); 
1448 }
1449
1450 static inline void outputChar(char c)
1451 {
1452   if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c);
1453 }
1454
1455 static inline void outputArray(const char *a,int len)
1456 {
1457   if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len);
1458 }
1459
1460 static void readIncludeFile(const QCString &inc)
1461 {
1462   static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1463   uint i=0;
1464
1465   // find the start of the include file name
1466   while (i<inc.length() &&
1467          (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
1468         ) i++;
1469   uint s=i;
1470
1471   // was it a local include?
1472   bool localInclude = s>0 && inc.at(s-1)=='"';
1473
1474   // find the end of the include file name
1475   while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
1476
1477   if (s<inc.length() && i>s) // valid include file name found
1478   {
1479     // extract include path+name
1480     QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
1481
1482     QCString dosExt = incFileName.right(4);
1483     if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
1484     {
1485       // skip imported binary files (e.g. M$ type libraries)
1486       return;
1487     }
1488
1489     QCString oldFileName = g_yyFileName;
1490     FileDef *oldFileDef  = g_yyFileDef;
1491     int oldLineNr        = g_yyLineNr;
1492     //printf("Searching for `%s'\n",incFileName.data());
1493
1494     // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
1495     QCString absIncFileName = incFileName;
1496     {
1497       QFileInfo fi(g_yyFileName);
1498       if (fi.exists())
1499       {
1500         QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName;
1501         QFileInfo fi2(absName);
1502         if (fi2.exists())
1503         {
1504           absIncFileName=fi2.absFilePath().utf8();
1505         }
1506         else if (searchIncludes) // search in INCLUDE_PATH as well
1507         {
1508           QStrList &includePath = Config_getList("INCLUDE_PATH");
1509           char *s=includePath.first();
1510           while (s)
1511           {
1512             QFileInfo fi(s);
1513             if (fi.exists() && fi.isDir())
1514             {
1515               QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName;
1516               //printf("trying absName=%s\n",absName.data());
1517               QFileInfo fi2(absName);
1518               if (fi2.exists())
1519               {
1520                 absIncFileName=fi2.absFilePath().utf8();
1521                 break;
1522               }
1523               //printf( "absIncFileName = %s\n", absIncFileName.data() );
1524             }
1525             s=includePath.next();
1526           }
1527         }
1528         //printf( "absIncFileName = %s\n", absIncFileName.data() );
1529       }
1530     }
1531     DefineManager::instance().addInclude(g_yyFileName,absIncFileName);
1532     DefineManager::instance().addFileToContext(absIncFileName);
1533
1534     // findFile will overwrite g_yyFileDef if found
1535     FileState *fs;
1536     bool alreadyIncluded = FALSE;
1537     //printf("calling findFile(%s)\n",incFileName.data());
1538     if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
1539     {
1540       //printf("Found include file!\n");
1541       if (Debug::isFlagSet(Debug::Preprocessor))
1542       {
1543         for (i=0;i<g_includeStack.count();i++) 
1544         {
1545           Debug::print(Debug::Preprocessor,0,"  ");
1546         }
1547         //msg("#include %s: parsing...\n",incFileName.data());
1548       }
1549       if (oldFileDef)
1550       {
1551         // add include dependency to the file in which the #include was found
1552         bool ambig;
1553         // change to absolute name for bug 641336 
1554         FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1555         oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE);
1556         // add included by dependency
1557         if (g_yyFileDef)
1558         {
1559           //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
1560           g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1561         }
1562       }
1563       else if (g_inputFileDef)
1564       {
1565         g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1566       }
1567       fs->bufState = YY_CURRENT_BUFFER;
1568       fs->lineNr   = oldLineNr;
1569       fs->fileName = oldFileName;
1570       // push the state on the stack
1571       g_includeStack.push(fs);
1572       // set the scanner to the include file
1573
1574       // Deal with file changes due to 
1575       // #include's within { .. } blocks
1576       QCString lineStr(g_yyFileName.length()+20);
1577       lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
1578       outputArray(lineStr.data(),lineStr.length());
1579
1580       DBG_CTX((stderr,"Switching to include file %s\n",incFileName.data()));
1581       g_expectGuard=TRUE;
1582       g_inputBuf   = &fs->fileBuf;
1583       g_inputBufPos=0;
1584       yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
1585     }
1586     else
1587     {
1588       //printf("  calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
1589       if (oldFileDef)
1590       {
1591         bool ambig;
1592         //QCString absPath = incFileName;
1593         //if (QDir::isRelativePath(incFileName))
1594         //{
1595         //  absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName);
1596         //  //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data());
1597         //}
1598
1599         // change to absolute name for bug 641336 
1600         FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1601         //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd);
1602         // add include dependency to the file in which the #include was found
1603         oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE);
1604         // add included by dependency
1605         if (fd)
1606         {
1607           //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
1608           fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1609         }
1610       }
1611       else if (g_inputFileDef)
1612       {
1613         g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1614       }
1615       if (Debug::isFlagSet(Debug::Preprocessor))
1616       {
1617         if (alreadyIncluded)
1618         {
1619           Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",incFileName.data());
1620         }
1621         else
1622         {
1623           Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",incFileName.data());
1624         }
1625         //printf("error: include file %s not found\n",yytext);
1626       }
1627       if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
1628       {
1629         warn(g_yyFileName,g_yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
1630       }
1631     }
1632   }
1633 }
1634
1635 /* ----------------------------------------------------------------- */
1636
1637 static void startCondSection(const char *sectId)
1638 {
1639   //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1640   CondParser prs;
1641   bool expResult = prs.parse(g_yyFileName,g_yyLineNr,sectId);
1642   g_condStack.push(new CondCtx(g_yyLineNr,sectId,g_skip));
1643   if (!expResult)
1644   {
1645     g_skip=TRUE;
1646   }
1647   //printf("  expResult=%d skip=%d\n",expResult,g_skip);
1648 }
1649
1650 static void endCondSection()
1651 {
1652   if (g_condStack.isEmpty())
1653   {
1654     g_skip=FALSE;
1655   }
1656   else
1657   {
1658     CondCtx *ctx = g_condStack.pop();
1659     g_skip=ctx->skip;
1660   }
1661   //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1662 }
1663
1664 static void forceEndCondSection()
1665 {
1666   while (!g_condStack.isEmpty())
1667   {
1668     g_condStack.pop();
1669   }
1670   g_skip=FALSE;
1671 }
1672
1673 static QCString escapeAt(const char *text)
1674 {
1675   QCString result;
1676   if (text)
1677   {
1678     char c;
1679     const char *p=text;
1680     while ((c=*p++))
1681     {
1682       if (c=='@') result+="@@"; else result+=c;
1683     }
1684   }
1685   return result;
1686 }
1687
1688 static char resolveTrigraph(char c)
1689 {
1690   switch (c)
1691   {
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     case '-': return '~';
1701   }
1702   return '?';
1703 }
1704
1705 /* ----------------------------------------------------------------- */
1706
1707 #undef  YY_INPUT
1708 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1709
1710 static int yyread(char *buf,int max_size)
1711 {
1712   int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
1713   int bytesToCopy = QMIN(max_size,bytesInBuf);
1714   memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
1715   g_inputBufPos+=bytesToCopy;
1716   return bytesToCopy;
1717 }
1718
1719 /* ----------------------------------------------------------------- */
1720
1721 %}
1722
1723 ID      [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
1724 B       [ \t]
1725 BN      [ \t\r\n]
1726 CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
1727
1728 %option noyywrap
1729
1730 %x      Start
1731 %x      Command
1732 %x      SkipCommand
1733 %x      SkipLine
1734 %x      SkipString
1735 %x      CopyLine
1736 %x      CopyString
1737 %x      Include
1738 %x      IncludeID
1739 %x      EndImport
1740 %x      DefName
1741 %x      DefineArg
1742 %x      DefineText
1743 %x      SkipCPPBlock
1744 %x      Ifdef
1745 %x      Ifndef
1746 %x      SkipCComment
1747 %x      ArgCopyCComment
1748 %x      CopyCComment
1749 %x      SkipVerbatim
1750 %x      SkipCPPComment
1751 %x      RemoveCComment
1752 %x      RemoveCPPComment
1753 %x      Guard
1754 %x      DefinedExpr1
1755 %x      DefinedExpr2
1756 %x      SkipDoubleQuote
1757 %x      SkipSingleQuote
1758 %x      UndefName
1759 %x      IgnoreLine
1760 %x      FindDefineArgs
1761 %x      ReadString
1762 %x      CondLineC
1763 %x      CondLineCpp
1764 %x      SkipCond
1765
1766 %%
1767
1768 <*>\x06                                 
1769 <*>\x00
1770 <*>\r
1771 <*>"??"[=/'()!<>-]                      { // Trigraph
1772                                           unput(resolveTrigraph(yytext[2]));
1773                                         }
1774 <Start>^{B}*"#"                         { BEGIN(Command); g_yyColNr+=yyleng; g_yyMLines=0;}
1775 <Start>^{B}*/[^#]                       {
1776                                           outputArray(yytext,(int)yyleng);
1777                                           BEGIN(CopyLine); 
1778                                         }
1779 <Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
1780                                           int i;
1781                                           for (i=(int)yyleng-1;i>=0;i--)
1782                                           {
1783                                             unput(yytext[i]);
1784                                           }
1785                                           BEGIN(CopyLine);
1786                                         }
1787 <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
1788 <Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro
1789                                           static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS");
1790                                           QCString name(yytext);
1791                                           name=name.left(name.find('(')).stripWhiteSpace();
1792
1793                                           Define *def=0;
1794                                           if (skipFuncMacros && 
1795                                               name!="Q_PROPERTY" &&
1796                                               !(
1797                                                  (g_includeStack.isEmpty() || g_curlyCount>0) &&
1798                                                  g_macroExpansion &&
1799                                                  (def=DefineManager::instance().isDefined(name)) &&
1800                                                  /*macroIsAccessible(def) &&*/
1801                                                  (!g_expandOnlyPredef || def->isPredefined)
1802                                                )
1803                                              )
1804                                           {
1805                                             outputChar('\n');
1806                                             g_yyLineNr++;
1807                                           }
1808                                           else // don't skip
1809                                           {
1810                                             int i;
1811                                             for (i=(int)yyleng-1;i>=0;i--)
1812                                             {
1813                                               unput(yytext[i]);
1814                                             }
1815                                             BEGIN(CopyLine);
1816                                           }
1817                                         }
1818 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{"       {
1819                                           QCString text=yytext;
1820                                           g_yyLineNr+=text.contains('\n');
1821                                           outputArray(yytext,(int)yyleng);
1822                                         }
1823 <CopyLine>"{"                           { // count brackets inside the main file
1824                                           if (g_includeStack.isEmpty()) 
1825                                           {
1826                                             g_curlyCount++;
1827                                           }
1828                                           outputChar(*yytext);
1829                                         }
1830 <CopyLine>"}"                           { // count brackets inside the main file
1831                                           if (g_includeStack.isEmpty() && g_curlyCount>0) 
1832                                           {
1833                                             g_curlyCount--;
1834                                           }
1835                                           outputChar(*yytext);
1836                                         }
1837 <CopyLine>"'"\\[0-7]{1,3}"'"            { 
1838                                           outputArray(yytext,(int)yyleng);
1839                                         }
1840 <CopyLine>"'"\\."'"                     { 
1841                                           outputArray(yytext,(int)yyleng);
1842                                         }
1843 <CopyLine>"'"."'"                       { 
1844                                           outputArray(yytext,(int)yyleng);
1845                                         }
1846 <CopyLine>\"                            {
1847                                           outputChar(*yytext);
1848                                           BEGIN( CopyString );
1849                                         }
1850 <CopyString>[^\"\\\r\n]+                {
1851                                           outputArray(yytext,(int)yyleng);
1852                                         }
1853 <CopyString>\\.                         {
1854                                           outputArray(yytext,(int)yyleng);
1855                                         }
1856 <CopyString>\"                          {
1857                                           outputChar(*yytext);
1858                                           BEGIN( CopyLine );
1859                                         }
1860 <CopyLine>{ID}/{BN}{0,80}"("            {
1861                                           g_expectGuard = FALSE;
1862                                           Define *def=0;
1863                                           //def=g_globalDefineDict->find(yytext);
1864                                           //def=DefineManager::instance().isDefined(yytext);
1865                                           //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d "
1866                                           //       "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
1867                                           //     "isPreDefined=%d\n",yytext,def ? 1 : 0,
1868                                           //     g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
1869                                           //     def ? def->isPredefined : -1
1870                                           //    );
1871                                           if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1872                                               g_macroExpansion &&
1873                                               (def=DefineManager::instance().isDefined(yytext)) &&
1874                                               /*(def->isPredefined || macroIsAccessible(def)) && */
1875                                               (!g_expandOnlyPredef || def->isPredefined)
1876                                              )
1877                                           {
1878                                             //printf("Found it! #args=%d\n",def->nargs);
1879                                             g_roundCount=0;
1880                                             g_defArgsStr=yytext;
1881                                             if (def->nargs==-1) // no function macro
1882                                             {
1883                                               QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr);
1884                                               outputArray(result,result.length());
1885                                             }
1886                                             else // zero or more arguments
1887                                             {
1888                                               g_findDefArgContext = CopyLine;
1889                                               BEGIN(FindDefineArgs);
1890                                             }
1891                                           }
1892                                           else
1893                                           {
1894                                             outputArray(yytext,(int)yyleng);
1895                                           }
1896                                         }
1897 <CopyLine>{ID}                          {
1898                                           Define *def=0;
1899                                           if ((g_includeStack.isEmpty() || g_curlyCount>0) && 
1900                                               g_macroExpansion &&
1901                                               (def=DefineManager::instance().isDefined(yytext)) &&
1902                                               def->nargs==-1 &&
1903                                               /*(def->isPredefined || macroIsAccessible(def)) &&*/
1904                                               (!g_expandOnlyPredef || def->isPredefined)
1905                                              )
1906                                           {
1907                                             QCString result=def->isPredefined ? def->definition : expandMacro(yytext); 
1908                                             outputArray(result,result.length());
1909                                           }
1910                                           else
1911                                           {
1912                                             outputArray(yytext,(int)yyleng);
1913                                           }
1914                                         }
1915 <CopyLine>"\\"\r?/\n                    { // strip line continuation characters
1916                                         }
1917 <CopyLine>.                             {
1918                                           outputChar(*yytext);
1919                                         }
1920 <CopyLine>\n                            {
1921                                           outputChar('\n');
1922                                           BEGIN(Start);
1923                                           g_yyLineNr++;
1924                                           g_yyColNr=1;
1925                                         }
1926 <FindDefineArgs>"("                     {
1927                                           g_defArgsStr+='(';
1928                                           g_roundCount++;
1929                                         }
1930 <FindDefineArgs>")"                     {
1931                                           g_defArgsStr+=')';
1932                                           g_roundCount--;
1933                                           if (g_roundCount==0)
1934                                           {
1935                                             QCString result=expandMacro(g_defArgsStr);
1936                                             //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
1937                                             if (g_findDefArgContext==CopyLine)
1938                                             {
1939                                               outputArray(result,result.length());
1940                                               BEGIN(g_findDefArgContext);
1941                                             }
1942                                             else // g_findDefArgContext==IncludeID
1943                                             {
1944                                               readIncludeFile(result);
1945                                               g_nospaces=FALSE;
1946                                               BEGIN(Start);
1947                                             }
1948                                           }
1949                                         }
1950   /*
1951 <FindDefineArgs>")"{B}*"("              {
1952                                           g_defArgsStr+=yytext;
1953                                         }
1954   */
1955 <FindDefineArgs>{CHARLIT}               {
1956                                           g_defArgsStr+=yytext;
1957                                         }
1958 <FindDefineArgs>"/*"[*]?                {
1959                                           g_defArgsStr+=yytext;
1960                                           BEGIN(ArgCopyCComment);
1961                                         }
1962 <FindDefineArgs>\"                      {
1963                                           g_defArgsStr+=*yytext;
1964                                           BEGIN(ReadString);
1965                                         }
1966 <FindDefineArgs>\n                      {
1967                                           g_defArgsStr+=' ';
1968                                           g_yyLineNr++;
1969                                           outputChar('\n');
1970                                         }
1971 <FindDefineArgs>"@"                     {
1972                                           g_defArgsStr+="@@";
1973                                         }
1974 <FindDefineArgs>.                       {
1975                                           g_defArgsStr+=*yytext;
1976                                         }
1977 <ArgCopyCComment>[^*\n]+                {
1978                                           g_defArgsStr+=yytext;
1979                                         }
1980 <ArgCopyCComment>"*/"                   {
1981                                           g_defArgsStr+=yytext;
1982                                           BEGIN(FindDefineArgs);
1983                                         }
1984 <ArgCopyCComment>\n                     { 
1985                                           g_defArgsStr+=' ';
1986                                           g_yyLineNr++;
1987                                           outputChar('\n');
1988                                         }
1989 <ArgCopyCComment>.                      { 
1990                                           g_defArgsStr+=yytext;
1991                                         }
1992 <ReadString>"\""                        {
1993                                           g_defArgsStr+=*yytext;
1994                                           BEGIN(FindDefineArgs);
1995                                         }
1996 <ReadString>"//"|"/*"                   {
1997                                           g_defArgsStr+=yytext;
1998                                         }
1999 <ReadString>\\.                         {
2000                                           g_defArgsStr+=yytext;
2001                                         }
2002 <ReadString>.                           {
2003                                           g_defArgsStr+=*yytext;
2004                                         }
2005 <Command>("include"|"import"){B}+/{ID}  {
2006                                           g_isImported = yytext[1]=='m';
2007                                           if (g_macroExpansion) 
2008                                             BEGIN(IncludeID);
2009                                         }
2010 <Command>("include"|"import"){B}*[<"]   { 
2011                                           g_isImported = yytext[1]=='m';
2012                                           char c[2];
2013                                           c[0]=yytext[yyleng-1];c[1]='\0';
2014                                           g_incName=c;
2015                                           BEGIN(Include); 
2016                                         }
2017 <Command>("cmake")?"define"{B}+         { 
2018                                           //printf("!!!DefName\n"); 
2019                                           g_yyColNr+=yyleng;
2020                                           BEGIN(DefName); 
2021                                         }
2022 <Command>"ifdef"/{B}*"("                {
2023                                           incrLevel();
2024                                           g_guardExpr.resize(0);
2025                                           BEGIN(DefinedExpr2);
2026                                         }
2027 <Command>"ifdef"/{B}+                   {
2028                                           //printf("Pre.l: ifdef\n");
2029                                           incrLevel();
2030                                           g_guardExpr.resize(0);
2031                                           BEGIN(DefinedExpr1);
2032                                         }
2033 <Command>"ifndef"/{B}*"("               {
2034                                           incrLevel();
2035                                           g_guardExpr="! ";
2036                                           BEGIN(DefinedExpr2);
2037                                         }
2038 <Command>"ifndef"/{B}+                  {
2039                                           incrLevel();
2040                                           g_guardExpr="! ";
2041                                           BEGIN(DefinedExpr1);
2042                                         }
2043 <Command>"if"/[ \t(!]                   {
2044                                           incrLevel();
2045                                           g_guardExpr.resize(0);
2046                                           BEGIN(Guard);
2047                                         }
2048 <Command>("elif"|"else"{B}*"if")/[ \t(!]        {
2049                                           if (!otherCaseDone())
2050                                           {
2051                                             g_guardExpr.resize(0);
2052                                             BEGIN(Guard);  
2053                                           }
2054                                           else
2055                                           {
2056                                             g_ifcount=0;
2057                                             BEGIN(SkipCPPBlock);
2058                                           }
2059                                         }
2060 <Command>"else"/[^a-z_A-Z0-9\x80-\xFF]          {
2061                                           //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2062                                           if (otherCaseDone())
2063                                           {
2064                                             g_ifcount=0;
2065                                             BEGIN(SkipCPPBlock);
2066                                           }
2067                                           else
2068                                           {
2069                                             setCaseDone(TRUE);
2070                                             //g_levelGuard[g_level-1]=TRUE;
2071                                           } 
2072                                         }
2073 <Command>"undef"{B}+                    {
2074                                           BEGIN(UndefName);
2075                                         }
2076 <Command>("elif"|"else"{B}*"if")/[ \t(!]        {
2077                                           if (!otherCaseDone())
2078                                           {
2079                                             g_guardExpr.resize(0);
2080                                             BEGIN(Guard);
2081                                           }
2082                                         }
2083 <Command>"endif"/[^a-z_A-Z0-9\x80-\xFF]         {
2084                                           //printf("Pre.l: #endif\n");
2085                                           decrLevel();
2086                                         }
2087 <Command,IgnoreLine>\n                  {
2088                                           outputChar('\n');
2089                                           BEGIN(Start);
2090                                           g_yyLineNr++;
2091                                         }
2092 <Command>"pragma"{B}+"once"             {
2093                                           g_expectGuard = FALSE;
2094                                         }
2095 <Command>{ID}                           { // unknown directive
2096                                           BEGIN(IgnoreLine);
2097                                         }
2098 <IgnoreLine>\\[\r]?\n                   {
2099                                           outputChar('\n');
2100                                           g_yyLineNr++;
2101                                         }
2102 <IgnoreLine>.
2103 <Command>. {g_yyColNr+=yyleng;}
2104 <UndefName>{ID}                         {
2105                                           Define *def;
2106                                           if ((def=DefineManager::instance().isDefined(yytext)) 
2107                                               /*&& !def->isPredefined*/
2108                                               && !def->nonRecursive
2109                                              )
2110                                           {
2111                                             //printf("undefining %s\n",yytext);
2112                                             def->undef=TRUE;
2113                                           }
2114                                           BEGIN(Start);
2115                                         }
2116 <Guard>\\[\r]?\n                        {
2117                                           outputChar('\n');
2118                                           g_guardExpr+=' ';
2119                                           g_yyLineNr++;
2120                                         }
2121 <Guard>"defined"/{B}*"("                {
2122                                           BEGIN(DefinedExpr2);
2123                                         }
2124 <Guard>"defined"/{B}+                   {
2125                                           BEGIN(DefinedExpr1);
2126                                         }
2127 <Guard>{ID}                             { g_guardExpr+=yytext; }
2128 <Guard>.                                { g_guardExpr+=*yytext; }
2129 <Guard>\n                               {
2130                                           unput(*yytext);
2131                                           //printf("Guard: `%s'\n",
2132                                           //    g_guardExpr.data());
2133                                           bool guard=computeExpression(g_guardExpr);
2134                                           setCaseDone(guard);
2135                                           //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2136                                           if (guard)
2137                                           {
2138                                             BEGIN(Start);
2139                                           } 
2140                                           else
2141                                           {
2142                                             g_ifcount=0;
2143                                             BEGIN(SkipCPPBlock);
2144                                           }
2145                                         }
2146 <DefinedExpr1,DefinedExpr2>\\\n         { g_yyLineNr++; outputChar('\n'); }
2147 <DefinedExpr1>{ID}                      {
2148                                           if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2149                                             g_guardExpr+=" 1L ";
2150                                           else
2151                                             g_guardExpr+=" 0L ";
2152                                           g_lastGuardName=yytext;
2153                                           BEGIN(Guard);
2154                                         }
2155 <DefinedExpr2>{ID}                      {
2156                                           if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2157                                             g_guardExpr+=" 1L ";
2158                                           else
2159                                             g_guardExpr+=" 0L ";
2160                                           g_lastGuardName=yytext;
2161                                         }
2162 <DefinedExpr1,DefinedExpr2>\n           { // should not happen, handle anyway
2163                                           g_yyLineNr++;
2164                                           g_ifcount=0;
2165                                           BEGIN(SkipCPPBlock); 
2166                                         }
2167 <DefinedExpr2>")"                       {
2168                                           BEGIN(Guard);
2169                                         }
2170 <DefinedExpr1,DefinedExpr2>.
2171 <SkipCPPBlock>^{B}*"#"                  { BEGIN(SkipCommand); }
2172 <SkipCPPBlock>^{B}*/[^#]                { BEGIN(SkipLine); }
2173 <SkipCPPBlock>\n                        { g_yyLineNr++; outputChar('\n'); }
2174 <SkipCPPBlock>.
2175 <SkipCommand>"if"(("n")?("def"))?/[ \t(!]       { 
2176                                           incrLevel();
2177                                           g_ifcount++; 
2178                                           //printf("#if... depth=%d\n",g_ifcount);
2179                                         }
2180 <SkipCommand>"else"                     {
2181                                           //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
2182                                           if (g_ifcount==0 && !otherCaseDone())
2183                                           {
2184                                             setCaseDone(TRUE);
2185                                             //outputChar('\n');
2186                                             BEGIN(Start);
2187                                           }
2188                                         }
2189 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!]            {
2190                                           if (g_ifcount==0) 
2191                                           {
2192                                             if (!otherCaseDone())
2193                                             {
2194                                               g_guardExpr.resize(0);
2195                                               g_lastGuardName.resize(0);
2196                                               BEGIN(Guard);
2197                                             }
2198                                             else
2199                                             {
2200                                               BEGIN(SkipCPPBlock);
2201                                             }
2202                                           }
2203                                         }
2204 <SkipCommand>"endif"                    { 
2205                                           g_expectGuard = FALSE;
2206                                           decrLevel();
2207                                           if (--g_ifcount<0)
2208                                           {
2209                                             //outputChar('\n');
2210                                             BEGIN(Start);
2211                                           }
2212                                         }
2213 <SkipCommand>\n                         { 
2214                                           outputChar('\n');
2215                                           g_yyLineNr++; 
2216                                           BEGIN(SkipCPPBlock);
2217                                         }
2218 <SkipCommand>{ID}                       { // unknown directive 
2219                                           BEGIN(SkipLine); 
2220                                         }
2221 <SkipCommand>.
2222 <SkipLine>[^'"/\n]+                     
2223 <SkipLine>{CHARLIT}                     { }
2224 <SkipLine>\"                            {
2225                                           BEGIN(SkipString);
2226                                         }
2227 <SkipLine>.
2228 <SkipString>"//"/[^\n]*                 { 
2229                                         }
2230 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
2231                                           g_lastCPPContext=YY_START;
2232                                           BEGIN(RemoveCPPComment);
2233                                         }
2234 <SkipString>"/*"/[^\n]*                 { 
2235                                         }
2236 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
2237                                           g_lastCContext=YY_START;
2238                                           BEGIN(RemoveCComment);
2239                                         }
2240 <SkipLine>\n                            {
2241                                           outputChar('\n');
2242                                           g_yyLineNr++;  
2243                                           BEGIN(SkipCPPBlock);
2244                                         }
2245 <SkipString>[^"\\\n]+                   { }
2246 <SkipString>\\.                         { }
2247 <SkipString>\"                          {
2248                                           BEGIN(SkipLine);
2249                                         }
2250 <SkipString>.                           { }
2251 <IncludeID>{ID}{B}*/"("                 {
2252                                           g_nospaces=TRUE;
2253                                           g_roundCount=0;
2254                                           g_defArgsStr=yytext;
2255                                           g_findDefArgContext = IncludeID;
2256                                           BEGIN(FindDefineArgs);
2257                                         }
2258 <IncludeID>{ID}                         {
2259                                           g_nospaces=TRUE;
2260                                           readIncludeFile(expandMacro(yytext));
2261                                           BEGIN(Start);
2262                                         }
2263 <Include>[^\">\n]+[\">]                 { 
2264                                           g_incName+=yytext;
2265                                           readIncludeFile(g_incName);
2266                                           if (g_isImported)
2267                                           {
2268                                             BEGIN(EndImport);
2269                                           }
2270                                           else
2271                                           {
2272                                             BEGIN(Start);
2273                                           }
2274                                         }
2275 <EndImport>[^\\\n]*/\n                  {
2276                                           BEGIN(Start);
2277                                         }
2278 <EndImport>\\[\r]?"\n"                  { 
2279                                           outputChar('\n');
2280                                           g_yyLineNr++;
2281                                         }
2282 <EndImport>.                            {
2283                                         }
2284 <DefName>{ID}/("\\\n")*"("              { // define with argument
2285                                           //printf("Define() `%s'\n",yytext);
2286                                           g_argDict = new QDict<int>(31);
2287                                           g_argDict->setAutoDelete(TRUE);
2288                                           g_defArgs = 0; 
2289                                           g_defArgsStr.resize(0);
2290                                           g_defText.resize(0);
2291                                           g_defLitText.resize(0);
2292                                           g_defName = yytext;
2293                                           g_defVarArgs = FALSE;
2294                                           g_defExtraSpacing.resize(0);
2295                                           BEGIN(DefineArg);
2296                                         }
2297 <DefName>{ID}{B}+"1"/[ \r\t\n]          { // special case: define with 1 -> can be "guard"
2298                                           //printf("Define `%s'\n",yytext);
2299                                           g_argDict = 0;
2300                                           g_defArgs = -1;
2301                                           g_defArgsStr.resize(0);
2302                                           g_defName = yytext;
2303                                           g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace();
2304                                           g_defVarArgs = FALSE;
2305                                           //printf("Guard check: %s!=%s || %d\n",
2306                                           //    g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2307                                           if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2308                                           { // define may appear in the output
2309                                             QCString tmp=(QCString)"#define "+g_defName;
2310                                             outputArray(tmp.data(),tmp.length());
2311                                             g_quoteArg=FALSE;
2312                                             g_insideComment=FALSE;
2313                                             g_lastGuardName.resize(0);
2314                                             g_defText="1"; 
2315                                             g_defLitText="1"; 
2316                                             BEGIN(DefineText); 
2317                                           }
2318                                           else // define is a guard => hide
2319                                           {
2320                                             //printf("Found a guard %s\n",yytext);
2321                                             g_defText.resize(0);
2322                                             g_defLitText.resize(0);
2323                                             BEGIN(Start);
2324                                           }
2325                                           g_expectGuard=FALSE;
2326                                         }
2327 <DefName>{ID}/{B}*"\n"                  { // empty define
2328                                           g_argDict = 0;
2329                                           g_defArgs = -1;
2330                                           g_defName = yytext;
2331                                           g_defArgsStr.resize(0);
2332                                           g_defText.resize(0);
2333                                           g_defLitText.resize(0);
2334                                           g_defVarArgs = FALSE;
2335                                           //printf("Guard check: %s!=%s || %d\n",
2336                                           //    g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2337                                           if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2338                                           { // define may appear in the output
2339                                             QCString tmp=(QCString)"#define "+g_defName;
2340                                             outputArray(tmp.data(),tmp.length());
2341                                             g_quoteArg=FALSE;
2342                                             g_insideComment=FALSE;
2343                                             if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
2344                                             BEGIN(DefineText);
2345                                           }
2346                                           else // define is a guard => hide
2347                                           {
2348                                             //printf("Found a guard %s\n",yytext);
2349                                             g_guardName = yytext;
2350                                             g_lastGuardName.resize(0);
2351                                             BEGIN(Start);
2352                                           }
2353                                           g_expectGuard=FALSE;
2354                                         }
2355 <DefName>{ID}/{B}*                      { // define with content
2356                                           //printf("Define `%s'\n",yytext);
2357                                           g_argDict = 0;
2358                                           g_defArgs = -1;
2359                                           g_defArgsStr.resize(0);
2360                                           g_defText.resize(0);
2361                                           g_defLitText.resize(0);
2362                                           g_defName = yytext;
2363                                           g_defVarArgs = FALSE;
2364                                           QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
2365                                           outputArray(tmp.data(),tmp.length());
2366                                           g_quoteArg=FALSE;
2367                                           g_insideComment=FALSE;
2368                                           BEGIN(DefineText); 
2369                                         }
2370 <DefineArg>"\\\n"                       {
2371                                           g_defExtraSpacing+="\n";
2372                                           g_yyLineNr++;
2373                                         }
2374 <DefineArg>","{B}*                      { g_defArgsStr+=yytext; }
2375 <DefineArg>"("{B}*                      { g_defArgsStr+=yytext; }
2376 <DefineArg>{B}*")"{B}*                  {
2377                                           g_defArgsStr+=yytext; 
2378                                           QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing;
2379                                           outputArray(tmp.data(),tmp.length());
2380                                           g_quoteArg=FALSE;
2381                                           g_insideComment=FALSE;
2382                                           BEGIN(DefineText);
2383                                         }
2384 <DefineArg>"..."                        { // Variadic macro
2385                                           g_defVarArgs = TRUE;
2386                                           g_defArgsStr+=yytext;
2387                                           g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
2388                                           g_defArgs++;
2389                                         }
2390 <DefineArg>{ID}{B}*("..."?)             {
2391                                           //printf("Define addArg(%s)\n",yytext);
2392                                           QCString argName=yytext;
2393                                           g_defVarArgs = yytext[yyleng-1]=='.';
2394                                           if (g_defVarArgs) // strip ellipsis
2395                                           {
2396                                             argName=argName.left(argName.length()-3);
2397                                           }
2398                                           argName = argName.stripWhiteSpace();
2399                                           g_defArgsStr+=yytext;
2400                                           g_argDict->insert(argName,new int(g_defArgs)); 
2401                                           g_defArgs++;
2402                                         }
2403   /*
2404 <DefineText>"/ **"|"/ *!"                       {
2405                                           g_defText+=yytext;
2406                                           g_defLitText+=yytext;
2407                                           g_insideComment=TRUE;
2408                                         }
2409 <DefineText>"* /"                       {
2410                                           g_defText+=yytext;
2411                                           g_defLitText+=yytext;
2412                                           g_insideComment=FALSE;
2413                                         }
2414   */
2415 <DefineText>"/*"[!*]?                   {
2416                                           g_defText+=yytext;
2417                                           g_defLitText+=yytext;
2418                                           g_lastCContext=YY_START;
2419                                           g_commentCount=1;
2420                                           BEGIN(CopyCComment);
2421                                         }
2422 <DefineText>"//"[!/]?                   {
2423                                           outputArray(yytext,(int)yyleng);
2424                                           g_lastCPPContext=YY_START;
2425                                           g_defLitText+=' ';
2426                                           BEGIN(SkipCPPComment);
2427                                         }
2428 <SkipCComment>[/]?"*/"                  {
2429                                           if (yytext[0]=='/') outputChar('/');
2430                                           outputChar('*');outputChar('/');
2431                                           if (--g_commentCount<=0)
2432                                           {
2433                                             if (g_lastCContext==Start) 
2434                                               // small hack to make sure that ^... rule will
2435                                               // match when going to Start... Example: "/*...*/ some stuff..."
2436                                             {
2437                                               YY_CURRENT_BUFFER->yy_at_bol=1;
2438                                             }
2439                                             BEGIN(g_lastCContext);  
2440                                           }
2441                                         }
2442 <SkipCComment>"//"("/")*                {
2443                                           outputArray(yytext,(int)yyleng);
2444                                         }
2445 <SkipCComment>"/*"                      {
2446                                           outputChar('/');outputChar('*');
2447                                           //g_commentCount++;
2448                                         }
2449 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
2450                                           outputArray(yytext,(int)yyleng);
2451                                         }
2452 <SkipCComment>"~~~"[~]*                 {
2453                                           static bool markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
2454                                           if (!markdownSupport)
2455                                           {
2456                                             REJECT;
2457                                           }
2458                                           else
2459                                           {
2460                                             outputArray(yytext,(int)yyleng);
2461                                             g_fenceSize=yyleng;
2462                                             BEGIN(SkipVerbatim);
2463                                           }
2464                                         }
2465 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2466                                           outputArray(yytext,(int)yyleng);
2467                                           g_yyLineNr+=QCString(yytext).contains('\n');
2468                                         }
2469 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+      {
2470                                           outputArray(yytext,(int)yyleng);
2471                                           g_yyLineNr+=QCString(yytext).contains('\n');
2472                                           g_fenceSize=0;
2473                                           if (yytext[1]=='f')
2474                                           {
2475                                             g_blockName="f";
2476                                           }
2477                                           else
2478                                           {
2479                                             QCString bn=&yytext[1];
2480                                             int i = bn.find('{'); // for \code{.c}
2481                                             if (i!=-1) bn=bn.left(i);
2482                                             g_blockName=bn.stripWhiteSpace();
2483                                           }
2484                                           BEGIN(SkipVerbatim);
2485                                         }
2486 <SkipCComment,SkipCPPComment>[\\@][\\@]"cond"[ \t]+ { // escaped @cond
2487                                           outputArray(yytext,(int)yyleng);
2488                                         }
2489 <SkipCPPComment>[\\@]"cond"[ \t]+       { // conditional section
2490                                           g_ccomment=TRUE;  
2491                                           g_condCtx=YY_START;
2492                                           BEGIN(CondLineCpp);
2493                                         }
2494 <SkipCComment>[\\@]"cond"[ \t]+ { // conditional section
2495                                           g_ccomment=FALSE;  
2496                                           g_condCtx=YY_START;
2497                                           BEGIN(CondLineC);
2498                                         }
2499 <CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+      {
2500                                           startCondSection(yytext);
2501                                           if (g_skip)
2502                                           {
2503                                             if (YY_START==CondLineC)
2504                                             {
2505                                               // end C comment
2506                                               outputArray("*/",2);
2507                                               g_ccomment=TRUE;
2508                                             }
2509                                             else
2510                                             {
2511                                               g_ccomment=FALSE;
2512                                             }
2513                                             BEGIN(SkipCond);
2514                                           }
2515                                           else
2516                                           {
2517                                             BEGIN(g_condCtx);
2518                                           }
2519                                         }
2520 <CondLineC,CondLineCpp>.                { // non-guard character
2521                                           unput(*yytext);
2522                                           startCondSection(" ");
2523                                           if (g_skip)
2524                                           {
2525                                             if (YY_START==CondLineC)
2526                                             {
2527                                               // end C comment
2528                                               outputArray("*/",2);
2529                                               g_ccomment=TRUE;
2530                                             }
2531                                             else
2532                                             {
2533                                               g_ccomment=FALSE;
2534                                             }
2535                                             BEGIN(SkipCond);
2536                                           }
2537                                           else
2538                                           {
2539                                             BEGIN(g_condCtx);
2540                                           }
2541                                         }
2542 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*/\n { // no guard
2543                                           if (YY_START==SkipCComment)
2544                                           {
2545                                             g_ccomment=TRUE;
2546                                             // end C comment
2547                                             outputArray("*/",2);
2548                                           }
2549                                           else
2550                                           {
2551                                             g_ccomment=FALSE;
2552                                           }
2553                                           g_condCtx=YY_START;
2554                                           startCondSection(" ");
2555                                           BEGIN(SkipCond);
2556                                         }
2557 <SkipCond>\n                            { g_yyLineNr++; outputChar('\n'); }
2558 <SkipCond>.                             { }
2559 <SkipCond>[^\/\!*\\@\n]+                { }
2560 <SkipCond>"//"[/!]                      { g_ccomment=FALSE; }
2561 <SkipCond>"/*"[*!]                      { g_ccomment=TRUE; }
2562 <SkipCond,SkipCComment,SkipCPPComment>[\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2563                                           if (!g_skip)
2564                                           {
2565                                             outputArray(yytext,(int)yyleng);
2566                                           }
2567                                         }
2568 <SkipCond>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF]  { 
2569                                           bool oldSkip = g_skip;
2570                                           endCondSection(); 
2571                                           if (oldSkip && !g_skip)
2572                                           {
2573                                             if (g_ccomment)
2574                                             {
2575                                               outputArray("/** ",4);
2576                                             }
2577                                             BEGIN(g_condCtx);
2578                                           }
2579                                         }
2580 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2581                                           bool oldSkip = g_skip;
2582                                           endCondSection();
2583                                           if (oldSkip && !g_skip) 
2584                                           {
2585                                             BEGIN(g_condCtx);
2586                                           }
2587                                         }
2588 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
2589                                           outputArray(yytext,(int)yyleng);
2590                                           if (yytext[1]=='f' && g_blockName=="f")
2591                                           {
2592                                             BEGIN(SkipCComment);
2593                                           }
2594                                           else if (&yytext[4]==g_blockName)
2595                                           {
2596                                             BEGIN(SkipCComment);
2597                                           }
2598                                         }
2599 <SkipVerbatim>"~~~"[~]*                 {
2600                                           outputArray(yytext,(int)yyleng);
2601                                           if (g_fenceSize==yyleng)
2602                                           {
2603                                             BEGIN(SkipCComment);
2604                                           }
2605                                         }
2606 <SkipVerbatim>"*/"|"/*"                 {
2607                                           outputArray(yytext,(int)yyleng);
2608                                         }
2609 <SkipCComment,SkipVerbatim>[^*\\@\x06~\n\/]+ {
2610                                           outputArray(yytext,(int)yyleng);
2611                                         }
2612 <SkipCComment,SkipVerbatim>\n           { 
2613                                           g_yyLineNr++;
2614                                           outputChar('\n');
2615                                         }
2616 <SkipCComment,SkipVerbatim>.            {
2617                                           outputChar(*yytext);
2618                                         }
2619 <CopyCComment>[^*a-z_A-Z\x80-\xFF\n]+           {
2620                                           g_defLitText+=yytext;
2621                                           g_defText+=escapeAt(yytext);
2622                                         }
2623 <CopyCComment>"*/"                      {
2624                                           g_defLitText+=yytext;
2625                                           g_defText+=yytext;
2626                                           BEGIN(g_lastCContext);
2627                                         }
2628 <CopyCComment>\n                        { 
2629                                           g_yyLineNr++;
2630                                           outputChar('\n');
2631                                           g_defLitText+=yytext;
2632                                           g_defText+=' ';
2633                                         }
2634 <RemoveCComment>"*/"{B}*"#"             { // see bug 594021 for a usecase for this rule
2635                                           if (g_lastCContext==SkipCPPBlock)
2636                                           {
2637                                             BEGIN(SkipCommand);
2638                                           }
2639                                           else
2640                                           {
2641                                             REJECT;
2642                                           }
2643                                         }
2644 <RemoveCComment>"*/"                    { BEGIN(g_lastCContext); }
2645 <RemoveCComment>"//"                    
2646 <RemoveCComment>"/*"
2647 <RemoveCComment>[^*\x06\n]+
2648 <RemoveCComment>\n                      { g_yyLineNr++; outputChar('\n'); }
2649 <RemoveCComment>.                       
2650 <SkipCPPComment>[^\n\/\\@]+             {
2651                                           outputArray(yytext,(int)yyleng);
2652                                         }
2653 <SkipCPPComment,RemoveCPPComment>\n     {
2654                                           unput(*yytext);
2655                                           BEGIN(g_lastCPPContext);
2656                                         }
2657 <SkipCPPComment>"/*"                    {
2658                                           outputChar('/');outputChar('*');
2659                                         }
2660 <SkipCPPComment>"//"                    {
2661                                           outputChar('/');outputChar('/');
2662                                         }
2663 <SkipCPPComment>[^\x06\@\\\n]+          {
2664                                           outputArray(yytext,(int)yyleng);
2665                                         }
2666 <SkipCPPComment>.                       {
2667                                           outputChar(*yytext);
2668                                         }
2669 <RemoveCPPComment>"/*"
2670 <RemoveCPPComment>"//"
2671 <RemoveCPPComment>[^\x06\n]+
2672 <RemoveCPPComment>.
2673 <DefineText>"#"                         {
2674                                           g_quoteArg=TRUE;
2675                                           g_defLitText+=yytext;
2676                                         }
2677 <DefineText,CopyCComment>{ID}           {
2678                                           g_defLitText+=yytext;
2679                                           if (g_quoteArg)
2680                                           {
2681                                             g_defText+="\"";
2682                                           }
2683                                           if (g_defArgs>0)
2684                                           {
2685                                             int *n;
2686                                             if ((n=(*g_argDict)[yytext]))
2687                                             {
2688                                               //if (!g_quoteArg) g_defText+=' ';
2689                                               g_defText+='@';
2690                                               QCString numStr;
2691                                               numStr.sprintf("%d",*n);
2692                                               g_defText+=numStr;
2693                                               //if (!g_quoteArg) g_defText+=' ';
2694                                             }
2695                                             else
2696                                             {
2697                                               g_defText+=yytext;
2698                                             }
2699                                           }
2700                                           else
2701                                           {
2702                                             g_defText+=yytext;
2703                                           }
2704                                           if (g_quoteArg)
2705                                           {
2706                                             g_defText+="\"";
2707                                           }
2708                                           g_quoteArg=FALSE;
2709                                         }
2710 <CopyCComment>.                         {
2711                                           g_defLitText+=yytext;
2712                                           g_defText+=yytext;
2713                                         }
2714 <DefineText>\\[\r]?\n                   { 
2715                                           g_defLitText+=yytext;
2716                                           outputChar('\n');
2717                                           g_defText += ' ';
2718                                           g_yyLineNr++;
2719                                           g_yyMLines++;
2720                                         }
2721 <DefineText>\n                          {
2722                                           QCString comment=extractTrailingComment(g_defLitText);
2723                                           g_defLitText+=yytext;
2724                                           if (!comment.isEmpty())
2725                                           {
2726                                             outputArray(comment,comment.length());
2727                                             g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
2728                                           }
2729                                           outputChar('\n');
2730                                           Define *def=0;
2731                                           //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
2732                                           if (g_includeStack.isEmpty() || g_curlyCount>0) 
2733                                           {
2734                                             addDefine();
2735                                           }
2736                                           def=DefineManager::instance().isDefined(g_defName);
2737                                           if (def==0) // new define
2738                                           {
2739                                             //printf("new define '%s'!\n",g_defName.data());
2740                                             Define *nd = newDefine();
2741                                             DefineManager::instance().addDefine(g_yyFileName,nd);
2742
2743                                             // also add it to the local file list if it is a source file
2744                                             //if (g_isSource && g_includeStack.isEmpty())
2745                                             //{
2746                                             //  g_fileDefineDict->insert(g_defName,nd);
2747                                             //}
2748                                           }
2749                                           else if (def /*&& macroIsAccessible(def)*/)
2750                                                // name already exists
2751                                           {
2752                                             //printf("existing define!\n");
2753                                             //printf("define found\n");
2754                                             if (def->undef) // undefined name
2755                                             {
2756                                               def->undef = FALSE;
2757                                               def->name = g_defName;
2758                                               def->definition = g_defText.stripWhiteSpace();
2759                                               def->nargs = g_defArgs;
2760                                               def->fileName = g_yyFileName.copy(); 
2761                                               def->lineNr = g_yyLineNr-g_yyMLines;
2762                                               def->columnNr = g_yyColNr;
2763                                             }
2764                                             else
2765                                             {
2766                                               //printf("error: define %s is defined more than once!\n",g_defName.data());
2767                                             }
2768                                           }
2769                                           delete g_argDict; g_argDict=0;
2770                                           g_yyLineNr++;
2771                                           g_yyColNr=1;
2772                                           g_lastGuardName.resize(0);
2773                                           BEGIN(Start);
2774                                         }
2775 <DefineText>{B}*                        { g_defText += ' '; g_defLitText+=yytext; }
2776 <DefineText>{B}*"##"{B}*                { g_defText += "##"; g_defLitText+=yytext; }
2777 <DefineText>"@"                         { g_defText += "@@"; g_defLitText+=yytext; }
2778 <DefineText>\"                          { 
2779                                           g_defText += *yytext; 
2780                                           g_defLitText+=yytext; 
2781                                           if (!g_insideComment)
2782                                           {
2783                                             BEGIN(SkipDoubleQuote);
2784                                           }
2785                                         }
2786 <DefineText>\'                          { g_defText += *yytext;
2787                                           g_defLitText+=yytext; 
2788                                           if (!g_insideComment)
2789                                           {
2790                                             BEGIN(SkipSingleQuote);
2791                                           }
2792                                         }
2793 <SkipDoubleQuote>"//"[/]?               { g_defText += yytext; g_defLitText+=yytext; }
2794 <SkipDoubleQuote>"/*"                   { g_defText += yytext; g_defLitText+=yytext; }
2795 <SkipDoubleQuote>\"                     {
2796                                           g_defText += *yytext; g_defLitText+=yytext; 
2797                                           BEGIN(DefineText);
2798                                         }
2799 <SkipSingleQuote,SkipDoubleQuote>\\.    {
2800                                           g_defText += yytext; g_defLitText+=yytext;
2801                                         }
2802 <SkipSingleQuote>\'                     {
2803                                           g_defText += *yytext; g_defLitText+=yytext;
2804                                           BEGIN(DefineText);
2805                                         }
2806 <SkipDoubleQuote>.                      { g_defText += *yytext; g_defLitText+=yytext; }
2807 <SkipSingleQuote>.                      { g_defText += *yytext; g_defLitText+=yytext; }
2808 <DefineText>.                           { g_defText += *yytext; g_defLitText+=yytext; }
2809 <<EOF>>                                 {
2810                                           DBG_CTX((stderr,"End of include file\n"));
2811                                           //printf("Include stack depth=%d\n",g_includeStack.count());
2812                                           if (g_includeStack.isEmpty())
2813                                           {
2814                                             DBG_CTX((stderr,"Terminating scanner!\n"));
2815                                             yyterminate();
2816                                           }
2817                                           else
2818                                           {
2819                                             FileState *fs=g_includeStack.pop();
2820                                             //fileDefineCache->merge(g_yyFileName,fs->fileName);
2821                                             YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2822                                             yy_switch_to_buffer( fs->bufState );
2823                                             yy_delete_buffer( oldBuf );
2824                                             g_yyLineNr    = fs->lineNr;
2825                                             //preYYin = fs->oldYYin;
2826                                             g_inputBuf    = fs->oldFileBuf;
2827                                             g_inputBufPos = fs->oldFileBufPos;
2828                                             setFileName(fs->fileName);
2829                                             DBG_CTX((stderr,"######## FileName %s\n",g_yyFileName.data()));
2830                                             
2831                                             // Deal with file changes due to 
2832                                             // #include's within { .. } blocks
2833                                             QCString lineStr(15+g_yyFileName.length());
2834                                             lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
2835                                             outputArray(lineStr.data(),lineStr.length());
2836                                             
2837                                             delete fs; fs=0;
2838                                           }
2839                                         }
2840 <*>"/*"/"*/"                            |
2841 <*>"/*"[*]?                             {
2842                                           if (YY_START==SkipVerbatim || YY_START==SkipCond)
2843                                           {
2844                                             REJECT;
2845                                           }
2846                                           else
2847                                           {
2848                                             outputArray(yytext,(int)yyleng);
2849                                             g_lastCContext=YY_START;
2850                                             g_commentCount=1;
2851                                             if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2852                                             BEGIN(SkipCComment);
2853                                           }
2854                                         }
2855 <*>"//"[/]?                             {
2856                                           if (YY_START==SkipVerbatim || YY_START==SkipCond)
2857                                           {
2858                                             REJECT;
2859                                           }
2860                                           else
2861                                           {
2862                                             outputArray(yytext,(int)yyleng);
2863                                             g_lastCPPContext=YY_START;
2864                                             if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2865                                             BEGIN(SkipCPPComment);
2866                                           }
2867                                         }
2868 <*>\n                                   { 
2869                                           outputChar('\n');
2870                                           g_yyLineNr++; 
2871                                         }
2872 <*>.                                    {
2873                                           g_expectGuard = FALSE;
2874                                           outputChar(*yytext);
2875                                         }
2876
2877 %%
2878
2879 /*@ ----------------------------------------------------------------------------
2880  */
2881
2882 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
2883 {
2884   //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2885   if (pos<expr.length())
2886   {
2887     //printf("%c=expr()\n",expr.at(pos));
2888     return expr.at(pos++);
2889   }
2890   else if (rest && !rest->isEmpty())
2891   {
2892     int cc=rest->at(0);
2893     *rest=rest->right(rest->length()-1);
2894     //printf("%c=rest\n",cc);
2895     return cc;
2896   }
2897   else
2898   {
2899     int cc=yyinput();
2900     //printf("%d=yyinput() %d\n",cc,EOF);
2901     return cc;
2902   }
2903 }
2904  
2905 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
2906 {
2907   //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2908   if (pos<expr.length())
2909   {
2910     //printf("%c=expr()\n",expr.at(pos));
2911     return expr.at(pos);
2912   }
2913   else if (rest && !rest->isEmpty())
2914   {
2915     int cc=rest->at(0);
2916     //printf("%c=rest\n",cc);
2917     return cc;
2918   }
2919   else
2920   {
2921     int cc=yyinput();
2922     returnCharToStream(cc);
2923     //unput((char)cc);
2924     //printf("%c=yyinput()\n",cc);
2925     return cc;
2926   }
2927 }
2928
2929 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
2930 {
2931   //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2932   if (pos<expr.length())
2933   {
2934     pos++;
2935   }
2936   else if (rest)
2937   {
2938     //printf("Prepending to rest!\n");
2939     char cs[2];cs[0]=c;cs[1]='\0';
2940     rest->prepend(cs);
2941   }
2942   else
2943   {
2944     //unput(c);
2945     returnCharToStream(c);
2946   }
2947   //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2948 }
2949
2950 void addSearchDir(const char *dir)
2951 {
2952   QFileInfo fi(dir);
2953   if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8());
2954
2955
2956 void initPreprocessor()
2957 {
2958   g_pathList = new QStrList;
2959   addSearchDir(".");
2960   g_expandedDict = new DefineDict(17);
2961 }
2962
2963 void cleanUpPreprocessor()
2964 {
2965   delete g_expandedDict; g_expandedDict=0;
2966   delete g_pathList; g_pathList=0;
2967   DefineManager::deleteInstance();
2968 }
2969
2970
2971 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
2972 {
2973   printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2974   uint orgOffset=output.curPos();
2975   //printf("##########################\n%s\n####################\n",
2976   //    input.data());
2977
2978   g_macroExpansion = Config_getBool("MACRO_EXPANSION");
2979   g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF");
2980   g_skip=FALSE;
2981   g_curlyCount=0;
2982   g_nospaces=FALSE;
2983   g_inputBuf=&input;
2984   g_inputBufPos=0;
2985   g_outputBuf=&output;
2986   g_includeStack.setAutoDelete(TRUE);
2987   g_includeStack.clear();
2988   g_expandedDict->setAutoDelete(FALSE);
2989   g_expandedDict->clear();
2990   g_condStack.clear();
2991   g_condStack.setAutoDelete(TRUE);
2992   //g_fileDefineDict->clear();
2993
2994   setFileName(fileName);
2995   g_inputFileDef = g_yyFileDef;
2996   DefineManager::instance().startContext(g_yyFileName);
2997   
2998   static bool firstTime=TRUE;
2999   if (firstTime)
3000   {
3001     // add predefined macros
3002     char *defStr;
3003     QStrList &predefList = Config_getList("PREDEFINED");
3004     QStrListIterator sli(predefList);
3005     for (sli.toFirst();(defStr=sli.current());++sli)
3006     {
3007       QCString ds = defStr;
3008       int i_equals=ds.find('=');
3009       int i_obrace=ds.find('(');
3010       int i_cbrace=ds.find(')');
3011       bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
3012
3013       if (i_obrace==0) continue; // no define name
3014
3015       if (i_obrace<i_equals && i_cbrace<i_equals && 
3016           i_obrace!=-1      && i_cbrace!=-1      && 
3017           i_obrace<i_cbrace
3018          ) // predefined function macro definition
3019       {
3020         //printf("predefined function macro '%s'\n",defStr);
3021         QRegExp reId("[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*"); // regexp matching an id
3022         QDict<int> argDict(17);
3023         argDict.setAutoDelete(TRUE);
3024         int i=i_obrace+1,p,l,count=0;
3025         // gather the formal arguments in a dictionary 
3026         while (i<i_cbrace && (p=reId.match(ds,i,&l)))
3027         {
3028           if (l>0) // see bug375037
3029           {
3030             argDict.insert(ds.mid(p,l),new int(count++));
3031             i=p+l;
3032           }
3033           else
3034           {
3035             i++;
3036           }
3037         }
3038         // strip definition part
3039         QCString tmp=ds.right(ds.length()-i_equals-1);
3040         QCString definition;
3041         i=0;
3042         // substitute all occurrences of formal arguments by their 
3043         // corresponding markers
3044         while ((p=reId.match(tmp,i,&l))!=-1)
3045         {
3046           if (p>i) definition+=tmp.mid(i,p-i);
3047           int *argIndex;
3048           if ((argIndex=argDict[tmp.mid(p,l)])!=0)
3049           {
3050             QCString marker;
3051             marker.sprintf(" @%d ",*argIndex);
3052             definition+=marker;
3053           }
3054           else
3055           {
3056             definition+=tmp.mid(p,l);
3057           }
3058           i=p+l;
3059         }
3060         if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
3061
3062         // add define definition to the dictionary of defines for this file
3063         QCString dname = ds.left(i_obrace);
3064         if (!dname.isEmpty())
3065         {
3066           Define *def = new Define;
3067           def->name         = dname;
3068           def->definition   = definition; 
3069           def->nargs        = count;
3070           def->isPredefined = TRUE;
3071           def->nonRecursive = nonRecursive;
3072           def->fileDef      = g_yyFileDef;
3073           def->fileName     = fileName;
3074           DefineManager::instance().addDefine(g_yyFileName,def);
3075         }
3076
3077         //printf("#define `%s' `%s' #nargs=%d\n",
3078         //  def->name.data(),def->definition.data(),def->nargs);
3079       }
3080       else if ((i_obrace==-1 || i_obrace>i_equals) &&
3081           (i_cbrace==-1 || i_cbrace>i_equals) &&
3082           !ds.isEmpty() && (int)ds.length()>i_equals
3083           ) // predefined non-function macro definition
3084       {
3085         //printf("predefined normal macro '%s'\n",defStr);
3086         Define *def = new Define;
3087         if (i_equals==-1) // simple define without argument
3088         {
3089           def->name = ds;
3090           def->definition = "1"; // substitute occurrences by 1 (true)
3091         }
3092         else // simple define with argument
3093         {
3094           int ine=i_equals - (nonRecursive ? 1 : 0);
3095           def->name = ds.left(ine);
3096           def->definition = ds.right(ds.length()-i_equals-1);
3097         }
3098         if (!def->name.isEmpty())
3099         {
3100           def->nargs = -1;
3101           def->isPredefined = TRUE;
3102           def->nonRecursive = nonRecursive;
3103           def->fileDef      = g_yyFileDef;
3104           def->fileName     = fileName;
3105           DefineManager::instance().addDefine(g_yyFileName,def);
3106         }
3107         else
3108         {
3109           delete def;
3110         }
3111
3112         //printf("#define `%s' `%s' #nargs=%d\n",
3113         //  def->name.data(),def->definition.data(),def->nargs);
3114       }
3115     }
3116     //firstTime=FALSE;
3117   }
3118  
3119   g_yyLineNr = 1;
3120   g_yyColNr  = 1;
3121   g_level    = 0;
3122   g_ifcount  = 0;
3123
3124   BEGIN( Start );
3125   
3126   g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
3127   g_guardName.resize(0);
3128   g_lastGuardName.resize(0);
3129   g_guardExpr.resize(0);
3130   
3131   preYYlex();
3132   g_lexInit=TRUE;
3133
3134   while (!g_condStack.isEmpty())
3135   {
3136     CondCtx *ctx = g_condStack.pop();
3137     QCString sectionInfo = " ";
3138     if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data()); 
3139     warn(fileName,ctx->lineNr,"Conditional section%sdoes not have "
3140         "a corresponding \\endcond command within this file.",sectionInfo.data());
3141   }
3142   // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
3143   forceEndCondSection();
3144
3145   // remove locally defined macros so they can be redefined in another source file
3146   //if (g_fileDefineDict->count()>0)
3147   //{
3148   //  QDictIterator<Define> di(*g_fileDefineDict);
3149   //  Define *d;
3150   //  for (di.toFirst();(d=di.current());++di)
3151   //  {
3152   //    g_globalDefineDict->remove(di.currentKey());
3153   //  }
3154   //  g_fileDefineDict->clear();
3155   //}
3156
3157   if (Debug::isFlagSet(Debug::Preprocessor))
3158   {
3159     char *orgPos=output.data()+orgOffset;
3160     char *newPos=output.data()+output.curPos();
3161     Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos);
3162     int line=1;
3163     Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
3164     while (orgPos<newPos) 
3165     {
3166       putchar(*orgPos);
3167       if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3168       orgPos++;
3169     }
3170     Debug::print(Debug::Preprocessor,0,"\n---------\n");
3171     if (DefineManager::instance().defineContext().count()>0)
3172     {
3173       Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n");
3174       Debug::print(Debug::Preprocessor,0,"---------\n");
3175       QDictIterator<Define> di(DefineManager::instance().defineContext());
3176       Define *def;
3177       for (di.toFirst();(def=di.current());++di)
3178       {
3179         Debug::print(Debug::Preprocessor,0,"%s ",def->name.data());
3180       }
3181       Debug::print(Debug::Preprocessor,0,"\n---------\n");
3182     }
3183     else
3184     {
3185       Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n");
3186     }
3187   }
3188   DefineManager::instance().endContext();
3189   printlex(yy_flex_debug, FALSE, __FILE__, fileName);
3190 }
3191
3192 void preFreeScanner()
3193 {
3194 #if defined(YY_FLEX_SUBMINOR_VERSION) 
3195   if (g_lexInit)
3196   {
3197     preYYlex_destroy();
3198   }
3199 #endif
3200 }
3201
3202 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
3203 extern "C" { // some bogus code to keep the compiler happy
3204 //  int  preYYwrap() { return 1 ; }
3205   void preYYdummy() { yy_flex_realloc(0,0); } 
3206 }
3207 #endif
3208