1 /******************************************************************************
3 * $Id: config_templ.l,v 1.8 2001/01/01 10:15:16 root Exp $
5 * Copyright (C) 1997-2012 by Dimitri van Heesch.
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.
24 #define MAX_INCLUDE_DEPTH 10
27 /* -----------------------------------------------------------------
32 struct ConfigFileState
36 YY_BUFFER_STATE oldState;
37 YY_BUFFER_STATE newState;
41 static const QHash<QString,Input*> *g_options;
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;
56 /* -----------------------------------------------------------------
59 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
61 static int yyread(char *buf,int maxSize)
64 if (g_includeStack.isEmpty())
66 return fread(buf,1,maxSize,g_file);
70 return fread(buf,1,maxSize,g_includeStack.top()->file);
74 void config_err(const char *fmt, ...)
78 vfprintf(stderr, fmt, args);
81 void config_warn(const char *fmt, ...)
85 vfprintf(stderr, fmt, args);
89 static void substEnvVarsInStrList(QStringList &sl);
90 static void substEnvVarsInString(QString &s);
92 static void checkEncoding()
94 Input *option = g_options->value(QString::fromAscii("DOXYFILE_ENCODING"));
95 if (option && option->value().toString()!=g_codecName)
97 QTextCodec *newCodec = QTextCodec::codecForName(option->value().toString().toAscii());
101 g_codecName = option->value().toString();
106 static FILE *tryPath(const QString &path,const QString &fileName)
108 QString absName=!path.isEmpty() ? path+QString::fromAscii("/")+fileName : fileName;
109 QFileInfo fi(absName);
110 if (fi.exists() && fi.isFile())
112 FILE *f = fopen(absName.toLocal8Bit(),"r");
114 config_err("Error: could not open file %s for reading\n",absName.toLatin1().data());
121 static FILE *findFile(const QString &fileName)
123 if (QFileInfo(fileName).isAbsolute()) // absolute path
125 return tryPath(QString(), fileName);
128 // relative path, try with include paths in the list
129 QStringList sl = g_includePathList.toStringList();
130 substEnvVarsInStrList(sl);
131 foreach (QString s, sl)
133 FILE *f = tryPath(s,fileName);
136 // try cwd if g_includePathList fails
137 return tryPath(QString::fromAscii("."),fileName);
140 static void readIncludeFile(const QString &incName)
142 if (g_includeDepth==MAX_INCLUDE_DEPTH)
144 config_err("Error: maximum include depth (%d) reached, %s is not included. Aborting...\n",
145 MAX_INCLUDE_DEPTH,qPrintable(incName));
149 QString inc = incName;
150 substEnvVarsInString(inc);
152 uint incLen = inc.length();
153 if (inc.at(0)==QChar::fromAscii('"') &&
154 inc.at(incLen-1)==QChar::fromAscii('"')) // strip quotes
156 inc=inc.mid(1,incLen-2);
159 FILE *f = findFile(inc);
160 if (f) // see if the include file can be found
164 for (i=0;i<includeStack.count();i++) msg(" ");
165 msg("@INCLUDE = %s: parsing...\n",inc.toLatin1().data());
168 // store the state of the old file
169 ConfigFileState *fs=new ConfigFileState;
170 fs->oldState=YY_CURRENT_BUFFER;
171 fs->fileName=g_yyFileName;
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;
183 config_err("Error: @INCLUDE = %s: not found!\n",inc.toLatin1().data());
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
213 config_err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n",
214 qPrintable(cmd),yylineno,qPrintable(g_yyFileName));
219 //option->setEncoding(encoding);
220 g_arg = &g_curOption->value();
221 switch(g_curOption->kind())
224 g_elemStr = QString();
225 *g_arg = QStringList();
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));
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
252 config_err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n",
253 yytext,yylineno,qPrintable(g_yyFileName));
258 switch(g_curOption->kind())
261 g_arg = &g_curOption->value();
268 config_err("Warning: operator += not supported for `%s'. Ignoring line at line %d, file %s\n",
269 yytext,yylineno,qPrintable(g_yyFileName));
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));
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));
290 //printf("End of include file\n");
291 //printf("Include stack depth=%d\n",g_includeStack.count());
292 if (g_includeStack.isEmpty())
294 //printf("Terminating scanner!\n");
299 ConfigFileState *fs = g_includeStack.pop();
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;
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); }
313 if (!g_elemStr.isEmpty())
315 //printf("elemStr1=`%s'\n",elemStr.toLatin1().data());
316 *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
321 if (!g_elemStr.isEmpty())
323 //printf("elemStr2=`%s'\n",elemStr.toLatin1().data());
324 *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
326 g_elemStr = QString();
328 <GetString>[^ \"\t\r\n]+ {
329 *g_arg = QVariant(g_codec->toUnicode(yytext));
332 <GetString,GetStrList,SkipInvalid>"\"" { g_lastState=YY_START;
333 BEGIN(GetQuotedString);
336 <GetQuotedString>"\""|"\n" {
337 // we add a bogus space to signal that the string was quoted. This space will be stripped later on.
339 //printf("Quoted String = `%s'\n",tmpString.toLatin1().data());
340 if (g_lastState==GetString)
342 *g_arg = g_codec->toUnicode(g_tmpString);
347 g_elemStr+=g_codec->toUnicode(g_tmpString);
351 config_err("Warning: Missing end quote (\") on line %d, file %s\n",yylineno,
352 qPrintable(g_yyFileName));
356 <GetQuotedString>"\\\"" {
359 <GetQuotedString>. { g_tmpString+=*yytext; }
360 <GetStrList>[^ \#\"\t\r\n]+ {
361 g_elemStr+=g_codec->toUnicode(yytext);
363 <SkipComment>\n { BEGIN(Start); }
364 <SkipComment>\\[ \r\t]*\n { BEGIN(Start); }
371 /*@ ----------------------------------------------------------------------------
374 static void substEnvVarsInString(QString &s)
376 static QRegExp re(QString::fromAscii("\\$\\([a-z_A-Z0-9]+\\)"));
377 if (s.isEmpty()) return;
380 //printf("substEnvVarInString(%s) start\n",s.toLatin1().data());
381 while ((i=re.indexIn(s,p))!=-1)
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
390 s=s.trimmed(); // to strip the bogus space that was added when an argument
392 //printf("substEnvVarInString(%s) end\n",s.toLatin1().data());
395 static void substEnvVarsInStrList(QStringList &sl)
399 foreach (QString result, sl)
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);
407 //printf("Result %s was quoted=%d\n",result.toLatin1().data(),wasQuoted);
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! */
415 int l=result.length();
418 // search for a "word"
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
431 if (c==QChar::fromAscii('"')) // word within quotes
437 if (c==QChar::fromAscii('"')) // end quote
439 out += result.mid(p,i-p);
443 else if (c==QChar::fromAscii('\\')) // skip escaped stuff
449 else if (c==QChar::fromAscii(' ') || c==QChar::fromAscii('\t')) // separator
451 out += result.mid(p,i-p);
456 if (p!=l) // add the leftover as a string
458 out += result.right(l-p);
461 else // just goto the next element in the list
469 //--------------------------------------------------------------------------
472 const QString &fileName,
473 const QHash<QString,Input *> &options
476 QHashIterator<QString, Input*> i(options);
477 g_file = fopen(fileName.toLocal8Bit(),"r");
478 if (g_file==NULL) return false;
492 g_options = &options;
493 g_yyFileName = fileName;
494 g_includeStack.clear();
496 configrestart( configin );
500 // update the values in the UI
507 //printf("Updating: %s\n",qPrintable(i.key()));
512 printf("Invalid option: %s\n",qPrintable(i.key()));
519 void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s)
522 bool needsEscaping=FALSE;
523 // convert the string back to it original encoding
524 //QByteArray se = codec->fromUnicode(s);
526 const QChar *p=s.data();
527 if (!s.isEmpty() && !p->isNull())
529 while (!(c=*p++).isNull() && !needsEscaping)
531 needsEscaping = (c==QChar::fromAscii(' ') ||
532 c==QChar::fromAscii('\n') ||
533 c==QChar::fromAscii('\t') ||
534 c==QChar::fromAscii('"'));
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