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