Orb/Doxygen/addon/doxywizard/config.l
changeset 4 468f4c8d3d5b
equal deleted inserted replaced
3:d8fccb2cd802 4:468f4c8d3d5b
       
     1 /******************************************************************************
       
     2  *
       
     3  * $Id: config_templ.l,v 1.8 2001/01/01 10:15:16 root Exp $
       
     4  *
       
     5  * Copyright (C) 1997-2007 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  */
       
    14 
       
    15 %{
       
    16 
       
    17 /*
       
    18  *	includes
       
    19  */
       
    20 #include "config.h"
       
    21 #include "input.h"
       
    22 #include <QtCore>
       
    23 
       
    24 #define MAX_INCLUDE_DEPTH 10
       
    25 
       
    26 
       
    27 /* -----------------------------------------------------------------
       
    28  *
       
    29  *	static variables
       
    30  */
       
    31 
       
    32 struct ConfigFileState
       
    33 {
       
    34   int lineNr;
       
    35   FILE *file;
       
    36   YY_BUFFER_STATE oldState;
       
    37   YY_BUFFER_STATE newState;
       
    38   QString fileName;
       
    39 };  
       
    40 
       
    41 static const QHash<QString,Input*>   *g_options;
       
    42 static FILE                          *g_file;
       
    43 static QString                        g_yyFileName;
       
    44 static QString                        g_includeName;
       
    45 static QVariant                       g_includePathList;
       
    46 static QStack<ConfigFileState*>       g_includeStack;  
       
    47 static int                            g_includeDepth;
       
    48 static QVariant                      *g_arg;
       
    49 static Input                         *g_curOption=0;
       
    50 static QString                        g_elemStr;
       
    51 static QTextCodec                    *g_codec     = QTextCodec::codecForName("UTF-8");
       
    52 static QString                        g_codecName = QString::fromAscii("UTF-8");
       
    53 static int                            g_lastState;
       
    54 static QByteArray                     g_tmpString;
       
    55 
       
    56 /* -----------------------------------------------------------------
       
    57  */
       
    58 #undef	YY_INPUT
       
    59 #define	YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
       
    60 
       
    61 static int yyread(char *buf,int maxSize)
       
    62 {
       
    63     // no file included
       
    64     if (g_includeStack.isEmpty()) 
       
    65     {
       
    66       return fread(buf,1,maxSize,g_file);
       
    67     } 
       
    68     else 
       
    69     {
       
    70       return fread(buf,1,maxSize,g_includeStack.top()->file);
       
    71     }
       
    72 }
       
    73 
       
    74 void config_err(const char *fmt, ...)
       
    75 {
       
    76   va_list args;
       
    77   va_start(args, fmt);
       
    78   vfprintf(stderr, fmt, args);
       
    79   va_end(args); 
       
    80 }
       
    81 void config_warn(const char *fmt, ...)
       
    82 {
       
    83   va_list args;
       
    84   va_start(args, fmt);
       
    85   vfprintf(stderr, fmt, args);
       
    86   va_end(args);
       
    87 }
       
    88 
       
    89 static void substEnvVarsInStrList(QStringList &sl);
       
    90 static void substEnvVarsInString(QString &s);
       
    91 
       
    92 static void checkEncoding()
       
    93 {
       
    94   Input *option = g_options->value(QString::fromAscii("DOXYFILE_ENCODING"));
       
    95   if (option && option->value().toString()!=g_codecName)
       
    96   {
       
    97     QTextCodec *newCodec = QTextCodec::codecForName(option->value().toString().toAscii());
       
    98     if (newCodec)
       
    99     {
       
   100       g_codec = newCodec;
       
   101       g_codecName = option->value().toString();
       
   102     }
       
   103   }
       
   104 }
       
   105 
       
   106 static FILE *tryPath(const QString &path,const QString &fileName)
       
   107 {
       
   108   QString absName=!path.isEmpty() ? path+QString::fromAscii("/")+fileName : fileName;
       
   109   QFileInfo fi(absName);
       
   110   if (fi.exists() && fi.isFile())
       
   111   {
       
   112     FILE *f = fopen(absName.toLocal8Bit(),"r");
       
   113     if (f==NULL)
       
   114       config_err("Error: could not open file %s for reading\n",absName.toLatin1().data());
       
   115     else 
       
   116       return f;
       
   117   }
       
   118   return NULL;
       
   119 }
       
   120 
       
   121 static FILE *findFile(const QString &fileName)
       
   122 {
       
   123   if (QFileInfo(fileName).isAbsolute()) // absolute path
       
   124   {
       
   125     return tryPath(QString(), fileName);
       
   126   }
       
   127 
       
   128   // relative path, try with include paths in the list
       
   129   QStringList sl = g_includePathList.toStringList();
       
   130   substEnvVarsInStrList(sl);
       
   131   foreach (QString s, sl) 
       
   132   {
       
   133     FILE *f = tryPath(s,fileName);
       
   134     if (f) return f;
       
   135   }
       
   136   // try cwd if g_includePathList fails
       
   137   return tryPath(QString::fromAscii("."),fileName);
       
   138 }
       
   139 
       
   140 static void readIncludeFile(const QString &incName)
       
   141 {
       
   142   if (g_includeDepth==MAX_INCLUDE_DEPTH) 
       
   143   {
       
   144     config_err("Error: maximum include depth (%d) reached, %s is not included. Aborting...\n",
       
   145 	MAX_INCLUDE_DEPTH,qPrintable(incName));
       
   146     exit(1);
       
   147   } 
       
   148 
       
   149   QString inc = incName;
       
   150   substEnvVarsInString(inc);
       
   151   inc = inc.trimmed();
       
   152   uint incLen = inc.length();
       
   153   if (inc.at(0)==QChar::fromAscii('"') && 
       
   154       inc.at(incLen-1)==QChar::fromAscii('"')) // strip quotes
       
   155   {
       
   156     inc=inc.mid(1,incLen-2);
       
   157   }
       
   158 
       
   159   FILE *f = findFile(inc);
       
   160   if (f) // see if the include file can be found
       
   161   {
       
   162     // For debugging
       
   163 #if SHOW_INCLUDES
       
   164     for (i=0;i<includeStack.count();i++) msg("  ");
       
   165     msg("@INCLUDE = %s: parsing...\n",inc.toLatin1().data());
       
   166 #endif
       
   167 
       
   168     // store the state of the old file 
       
   169     ConfigFileState *fs=new ConfigFileState;
       
   170     fs->oldState=YY_CURRENT_BUFFER;
       
   171     fs->fileName=g_yyFileName;
       
   172     fs->file=f;
       
   173     // push the state on the stack
       
   174     g_includeStack.push(fs);
       
   175     // set the scanner to the include file
       
   176     yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
       
   177     fs->newState=YY_CURRENT_BUFFER;
       
   178     g_yyFileName=inc;
       
   179     g_includeDepth++;
       
   180   } 
       
   181   else
       
   182   {
       
   183     config_err("Error: @INCLUDE = %s: not found!\n",inc.toLatin1().data());
       
   184     exit(1);
       
   185   }
       
   186 }
       
   187 
       
   188 
       
   189 %}
       
   190 
       
   191 %option nounput
       
   192 %option noyywrap
       
   193 %option yylineno
       
   194 
       
   195 %x      Start
       
   196 %x	SkipComment
       
   197 %x      SkipInvalid
       
   198 %x      GetString
       
   199 %x      GetStrList
       
   200 %x      GetQuotedString
       
   201 %x      GetEnvVar
       
   202 %x      Include
       
   203 
       
   204 %%
       
   205 
       
   206 <*>\0x0d
       
   207 <Start,GetString,GetStrList,SkipInvalid>"#"	 { BEGIN(SkipComment); }
       
   208 <Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"="	 { QString cmd = g_codec->toUnicode(yytext);
       
   209                                            cmd=cmd.left(cmd.length()-1).trimmed(); 
       
   210 					   g_curOption = g_options->value(cmd);
       
   211 					   if (g_curOption==0) // oops not known
       
   212 					   {
       
   213 					     config_err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n",
       
   214 						 qPrintable(cmd),yylineno,qPrintable(g_yyFileName)); 
       
   215 					     BEGIN(SkipInvalid);
       
   216 					   }
       
   217 					   else // known tag
       
   218 					   {
       
   219 					     //option->setEncoding(encoding);
       
   220 					     g_arg = &g_curOption->value();
       
   221 					     switch(g_curOption->kind())
       
   222 					     {
       
   223 					       case Input::StrList:
       
   224 						 g_elemStr = QString();
       
   225 						 *g_arg = QStringList();
       
   226 					         BEGIN(GetStrList);
       
   227 					         break;
       
   228 					       case Input::String:
       
   229 					         BEGIN(GetString);
       
   230 					         break;
       
   231 					       case Input::Int:
       
   232 					         BEGIN(GetString);
       
   233 					         break;
       
   234 					       case Input::Bool:
       
   235 					         BEGIN(GetString);
       
   236 						 break;
       
   237 					       case Input::Obsolete:
       
   238 					         config_err("Warning: Tag `%s' at line %d of file %s has become obsolete.\n"
       
   239 						            "To avoid this warning please update your configuration "
       
   240 							    "file using \"doxygen -u\"\n", qPrintable(cmd),
       
   241 							    yylineno,qPrintable(g_yyFileName)); 
       
   242 					         BEGIN(SkipInvalid);
       
   243 						 break;
       
   244 					     }
       
   245 					   }
       
   246 					}
       
   247 <Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+="	{ QString cmd=g_codec->toUnicode(yytext);
       
   248                                           cmd=cmd.left(cmd.length()-2).trimmed(); 
       
   249 					  g_curOption = g_options->value(cmd);
       
   250 					  if (g_curOption==0) // oops not known
       
   251 					  {
       
   252 					    config_err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n",
       
   253 						yytext,yylineno,qPrintable(g_yyFileName)); 
       
   254 					    BEGIN(SkipInvalid);
       
   255 					  }
       
   256 					  else // known tag
       
   257 					  {
       
   258 					    switch(g_curOption->kind())
       
   259 					    {
       
   260 					      case Input::StrList:
       
   261 						g_arg = &g_curOption->value();
       
   262 						g_elemStr=QString();
       
   263 					        BEGIN(GetStrList);
       
   264 					        break;
       
   265 					      case Input::String:
       
   266 					      case Input::Int:
       
   267 					      case Input::Bool:
       
   268 					        config_err("Warning: operator += not supported for `%s'. Ignoring line at line %d, file %s\n",
       
   269 						    yytext,yylineno,qPrintable(g_yyFileName)); 
       
   270 					        BEGIN(SkipInvalid);
       
   271 						break;
       
   272 					      case Input::Obsolete:
       
   273 					         config_err("Warning: Tag `%s' at line %d of file %s has become obsolete.\n"
       
   274 						            "To avoid this warning please update your configuration "
       
   275 							    "file using \"doxygen -u\"\n", 
       
   276 							    qPrintable(cmd),yylineno,qPrintable(g_yyFileName)); 
       
   277 					         BEGIN(SkipInvalid);
       
   278 						 break;
       
   279 					     }
       
   280 					   }
       
   281 					}
       
   282 <Start>"@INCLUDE_PATH"[ \t]*"=" 	{ BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_elemStr=QString(); }
       
   283   /* include a config file */
       
   284 <Start>"@INCLUDE"[ \t]*"="     		{ BEGIN(Include);}
       
   285 <Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { 
       
   286   					  readIncludeFile(g_codec->toUnicode(yytext)); 
       
   287   					  BEGIN(Start);
       
   288 					}
       
   289 <<EOF>>					{
       
   290                                           //printf("End of include file\n");
       
   291 					  //printf("Include stack depth=%d\n",g_includeStack.count());
       
   292                                           if (g_includeStack.isEmpty())
       
   293 					  {
       
   294 					    //printf("Terminating scanner!\n");
       
   295 					    yyterminate();
       
   296 					  }
       
   297 					  else
       
   298 					  {
       
   299 					    ConfigFileState *fs = g_includeStack.pop();
       
   300 					    fclose(fs->file);
       
   301 					    YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
       
   302 					    yy_switch_to_buffer( fs->oldState );
       
   303 					    yy_delete_buffer( oldBuf );
       
   304 					    g_yyFileName=fs->fileName;
       
   305 					    delete fs; 
       
   306                                             g_includeDepth--;
       
   307 					  }
       
   308   					}
       
   309 
       
   310 <Start>[a-z_A-Z0-9]+			{ config_err("Warning: ignoring unknown tag `%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); }
       
   311 <GetString,SkipInvalid>\n	        { BEGIN(Start); }
       
   312 <GetStrList>\n				{ 
       
   313 					  if (!g_elemStr.isEmpty())
       
   314 					  {
       
   315 					    //printf("elemStr1=`%s'\n",elemStr.toLatin1().data());
       
   316 					    *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
       
   317 					  }
       
   318 					  BEGIN(Start); 
       
   319 					}
       
   320 <GetStrList>[ \t]+			{
       
   321   				          if (!g_elemStr.isEmpty())
       
   322 					  {
       
   323 					    //printf("elemStr2=`%s'\n",elemStr.toLatin1().data());
       
   324   					    *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
       
   325 					  }
       
   326 					  g_elemStr = QString();
       
   327   					}
       
   328 <GetString>[^ \"\t\r\n]+		{ 
       
   329                                           *g_arg = QVariant(g_codec->toUnicode(yytext)); 
       
   330                                           checkEncoding();
       
   331                                         }
       
   332 <GetString,GetStrList,SkipInvalid>"\""	{ g_lastState=YY_START;
       
   333   					  BEGIN(GetQuotedString); 
       
   334                                           g_tmpString="";
       
   335 					}
       
   336 <GetQuotedString>"\""|"\n" 		{ 
       
   337                                           // we add a bogus space to signal that the string was quoted. This space will be stripped later on.
       
   338                                           g_tmpString+=" ";
       
   339   					  //printf("Quoted String = `%s'\n",tmpString.toLatin1().data());
       
   340   					  if (g_lastState==GetString)
       
   341 					  {
       
   342 					    *g_arg = g_codec->toUnicode(g_tmpString);
       
   343                                             checkEncoding();
       
   344 					  }
       
   345 					  else
       
   346 					  {
       
   347 					    g_elemStr+=g_codec->toUnicode(g_tmpString);
       
   348 					  }
       
   349 					  if (*yytext=='\n')
       
   350 					  {
       
   351 					    config_err("Warning: Missing end quote (\") on line %d, file %s\n",yylineno,
       
   352                                                 qPrintable(g_yyFileName));
       
   353 					  }
       
   354 					  BEGIN(g_lastState);
       
   355   					}
       
   356 <GetQuotedString>"\\\""			{
       
   357   					  g_tmpString+='"';
       
   358   					}
       
   359 <GetQuotedString>.			{ g_tmpString+=*yytext; }
       
   360 <GetStrList>[^ \#\"\t\r\n]+		{
       
   361   					  g_elemStr+=g_codec->toUnicode(yytext);
       
   362   					}
       
   363 <SkipComment>\n				{ BEGIN(Start); }
       
   364 <SkipComment>\\[ \r\t]*\n		{ BEGIN(Start); }
       
   365 <*>\\[ \r\t]*\n				{ }
       
   366 <*>\n
       
   367 <*>.					
       
   368 
       
   369 %%
       
   370 
       
   371 /*@ ----------------------------------------------------------------------------
       
   372  */
       
   373 
       
   374 static void substEnvVarsInString(QString &s)
       
   375 {
       
   376   static QRegExp re(QString::fromAscii("\\$\\([a-z_A-Z0-9]+\\)"));
       
   377   if (s.isEmpty()) return;
       
   378   int p=0;
       
   379   int i,l;
       
   380   //printf("substEnvVarInString(%s) start\n",s.toLatin1().data());
       
   381   while ((i=re.indexIn(s,p))!=-1)
       
   382   {
       
   383     l = re.matchedLength();
       
   384     //printf("Found environment var s.mid(%d,%d)=`%s'\n",i+2,l-3,s.mid(i+2,l-3).toLatin1().data());
       
   385     QString env=g_codec->toUnicode(getenv(s.mid(i+2,l-3).toLatin1()));
       
   386     substEnvVarsInString(env); // recursively expand variables if needed.
       
   387     s = s.left(i)+env+s.right(s.length()-i-l);
       
   388     p=i+env.length(); // next time start at the end of the expanded string
       
   389   }
       
   390   s=s.trimmed(); // to strip the bogus space that was added when an argument
       
   391                          // has quotes
       
   392   //printf("substEnvVarInString(%s) end\n",s.toLatin1().data());
       
   393 }
       
   394 
       
   395 static void substEnvVarsInStrList(QStringList &sl)
       
   396 {
       
   397   QStringList out;
       
   398 
       
   399   foreach (QString result, sl)
       
   400   {
       
   401     // an argument with quotes will have an extra space at the end, so wasQuoted will be TRUE.
       
   402     bool wasQuoted = (result.indexOf(QChar::fromAscii(' '))!=-1) || 
       
   403                      (result.indexOf(QChar::fromAscii('\t'))!=-1);
       
   404     // here we strip the quote again
       
   405     substEnvVarsInString(result);
       
   406 
       
   407     //printf("Result %s was quoted=%d\n",result.toLatin1().data(),wasQuoted);
       
   408 
       
   409     if (!wasQuoted) /* as a result of the expansion, a single string
       
   410 		       may have expanded into a list, which we'll
       
   411 		       add to sl. If the orginal string already 
       
   412 		       contained multiple elements no further 
       
   413 		       splitting is done to allow quoted items with spaces! */
       
   414     {
       
   415       int l=result.length();
       
   416       int i,p=0;
       
   417       // skip spaces
       
   418       // search for a "word"
       
   419       for (i=0;i<l;i++)
       
   420       {
       
   421 	QChar c=0;
       
   422 	// skip until start of new word
       
   423 	while (i<l && ((c=result.at(i))==QChar::fromAscii(' ') || c==QChar::fromAscii('\t'))) i++; 
       
   424 	p=i; // p marks the start index of the word
       
   425 	// skip until end of a word
       
   426 	while (i<l && ((c=result.at(i))!=QChar::fromAscii(' ') && 
       
   427 	              c!=QChar::fromAscii('\t') && 
       
   428 		      c!=QChar::fromAscii('"'))) i++;
       
   429 	if (i<l) // not at the end of the string
       
   430 	{
       
   431 	  if (c==QChar::fromAscii('"')) // word within quotes
       
   432 	  {
       
   433 	    p=i+1;
       
   434 	    for (i++;i<l;i++)
       
   435 	    {
       
   436 	      c=result.at(i);
       
   437 	      if (c==QChar::fromAscii('"')) // end quote
       
   438 	      {
       
   439                 out += result.mid(p,i-p);
       
   440 		p=i+1;
       
   441 		break; 
       
   442 	      }
       
   443 	      else if (c==QChar::fromAscii('\\')) // skip escaped stuff
       
   444 	      {
       
   445 		i++;
       
   446 	      }
       
   447 	    }
       
   448 	  }
       
   449 	  else if (c==QChar::fromAscii(' ') || c==QChar::fromAscii('\t')) // separator
       
   450 	  {
       
   451             out += result.mid(p,i-p);
       
   452 	    p=i+1;
       
   453 	  }
       
   454 	}
       
   455       }
       
   456       if (p!=l) // add the leftover as a string
       
   457       {
       
   458         out += result.right(l-p);
       
   459       }
       
   460     }
       
   461     else // just goto the next element in the list
       
   462     {
       
   463       out += result;
       
   464     }
       
   465   }
       
   466   sl = out;
       
   467 }
       
   468 
       
   469 //--------------------------------------------------------------------------
       
   470 
       
   471 bool parseConfig(
       
   472       const QString &fileName,
       
   473       const QHash<QString,Input *> &options
       
   474     )
       
   475 {
       
   476   QHashIterator<QString, Input*> i(options);
       
   477   g_file = fopen(fileName.toLocal8Bit(),"r");
       
   478   if (g_file==NULL) return false;
       
   479 
       
   480   // reset all values
       
   481   i.toFront();
       
   482   while (i.hasNext()) 
       
   483   {
       
   484     i.next();
       
   485     if (i.value())
       
   486     {
       
   487       i.value()->reset();
       
   488     }
       
   489   }
       
   490 
       
   491   // parse config file
       
   492   g_options       = &options;
       
   493   g_yyFileName    = fileName;
       
   494   g_includeStack.clear();
       
   495   g_includeDepth  = 0;
       
   496   configrestart( configin );
       
   497   BEGIN( Start );
       
   498   configlex();
       
   499 
       
   500   // update the values in the UI
       
   501   i.toFront();
       
   502   while (i.hasNext()) 
       
   503   {
       
   504     i.next();
       
   505     if (i.value())
       
   506     {
       
   507       //printf("Updating: %s\n",qPrintable(i.key()));
       
   508       i.value()->update();
       
   509     }
       
   510     else
       
   511     {
       
   512       printf("Invalid option: %s\n",qPrintable(i.key()));
       
   513     }
       
   514   } 
       
   515   fclose(g_file);
       
   516   return true;
       
   517 }
       
   518 
       
   519 void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s)
       
   520 {
       
   521   QChar c;
       
   522   bool needsEscaping=FALSE;
       
   523   // convert the string back to it original encoding
       
   524   //QByteArray se = codec->fromUnicode(s);
       
   525   t.setCodec(codec);
       
   526   const QChar *p=s.data();
       
   527   if (!s.isEmpty() && !p->isNull())
       
   528   {
       
   529     while (!(c=*p++).isNull() && !needsEscaping) 
       
   530     {
       
   531       needsEscaping = (c==QChar::fromAscii(' ')  || 
       
   532 	               c==QChar::fromAscii('\n') || 
       
   533 		       c==QChar::fromAscii('\t') || 
       
   534 		       c==QChar::fromAscii('"'));
       
   535     }
       
   536     if (needsEscaping)
       
   537     { 
       
   538       t << "\"";
       
   539       p=s.data();
       
   540       while (!p->isNull())
       
   541       {
       
   542 	if (*p   ==QChar::fromAscii(' ') && 
       
   543 	   *(p+1)==QChar::fromAscii('\0')) break; // skip inserted space at the end
       
   544 	if (*p   ==QChar::fromAscii('"')) t << "\\"; // escape quotes
       
   545 	t << *p++;
       
   546       }
       
   547       t << "\"";
       
   548     }
       
   549     else
       
   550     {
       
   551       t << s;
       
   552     }
       
   553   }
       
   554 }
       
   555