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