1 /******************************************************************************
3 * $Id: config_templ.l,v 1.8 2001/01/01 10:15:16 root Exp $
5 * Copyright (C) 1997-2015 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.
15 %option never-interactive
16 %option prefix="config_doxywYY"
31 #include <QStringList>
33 #include <QTextStream>
35 #define YY_NO_UNISTD_H 1
37 #define MAX_INCLUDE_DEPTH 10
40 /* -----------------------------------------------------------------
45 struct ConfigFileState
49 YY_BUFFER_STATE oldState;
50 YY_BUFFER_STATE newState;
54 static const QHash<QString,Input*> *g_options;
56 static QString g_yyFileName;
57 static QString g_includeName;
58 static QVariant g_includePathList;
59 static QStack<ConfigFileState*> g_includeStack;
60 static int g_includeDepth;
61 static QVariant *g_arg;
62 static Input *g_curOption=0;
63 static QString g_elemStr;
64 static QTextCodec *g_codec = QTextCodec::codecForName("UTF-8");
65 static QString g_codecName = QString::fromLatin1("UTF-8");
66 static int g_lastState;
67 static QByteArray g_tmpString;
69 /* -----------------------------------------------------------------
72 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
74 static int yyread(char *buf,int maxSize)
77 if (g_includeStack.isEmpty())
79 return fread(buf,1,maxSize,g_file);
83 return fread(buf,1,maxSize,g_includeStack.top()->file);
87 static QString warning_str = QString::fromLatin1("warning: ");
88 static QString error_str = QString::fromLatin1("error: ");
90 void config_err(const char *fmt, ...)
92 QString msg = error_str;
93 msg.append(QString::fromLatin1(fmt));
96 vfprintf(stderr, qPrintable(msg), args);
99 void config_warn(const char *fmt, ...)
101 QString msg = warning_str;
102 msg.append(QString::fromLatin1(fmt));
105 vfprintf(stderr, qPrintable(msg), args);
109 static void substEnvVarsInStrList(QStringList &sl);
110 static void substEnvVarsInString(QString &s);
112 static void checkEncoding()
114 Input *option = g_options->value(QString::fromLatin1("DOXYFILE_ENCODING"));
115 if (option && option->value().toString()!=g_codecName)
117 QTextCodec *newCodec = QTextCodec::codecForName(option->value().toString().toLatin1());
121 g_codecName = option->value().toString();
126 static FILE *tryPath(const QString &path,const QString &fileName)
128 QString absName=!path.isEmpty() ? path+QString::fromLatin1("/")+fileName : fileName;
129 QFileInfo fi(absName);
130 if (fi.exists() && fi.isFile())
132 FILE *f = fopen(absName.toLocal8Bit(),"r");
134 config_err("could not open file %s for reading\n",qPrintable(absName));
141 static FILE *findFile(const QString &fileName)
143 if (QFileInfo(fileName).isAbsolute()) // absolute path
145 return tryPath(QString(), fileName);
148 // relative path, try with include paths in the list
149 QStringList sl = g_includePathList.toStringList();
150 substEnvVarsInStrList(sl);
151 foreach (QString s, sl)
153 FILE *f = tryPath(s,fileName);
156 // try cwd if g_includePathList fails
157 return tryPath(QString::fromLatin1("."),fileName);
160 static void readIncludeFile(const QString &incName)
162 if (g_includeDepth==MAX_INCLUDE_DEPTH)
164 config_err("maximum include depth (%d) reached, %s is not included. Aborting...\n",
165 MAX_INCLUDE_DEPTH,qPrintable(incName));
169 QString inc = incName;
170 substEnvVarsInString(inc);
172 uint incLen = inc.length();
173 if (inc.at(0)==QChar::fromLatin1('"') &&
174 inc.at(incLen-1)==QChar::fromLatin1('"')) // strip quotes
176 inc=inc.mid(1,incLen-2);
179 FILE *f = findFile(inc);
180 if (f) // see if the include file can be found
184 for (i=0;i<includeStack.count();i++) msg(" ");
185 msg("@INCLUDE = %s: parsing...\n",qPrintable(inc));
188 // store the state of the old file
189 ConfigFileState *fs=new ConfigFileState;
190 fs->oldState=YY_CURRENT_BUFFER;
191 fs->fileName=g_yyFileName;
193 // push the state on the stack
194 g_includeStack.push(fs);
195 // set the scanner to the include file
196 yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
197 fs->newState=YY_CURRENT_BUFFER;
203 config_err("@INCLUDE = %s: not found!\n",qPrintable(inc));
227 <Start,GetString,GetStrList,SkipInvalid>"#" { BEGIN(SkipComment); }
228 <Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QString cmd = g_codec->toUnicode(yytext);
229 cmd=cmd.left(cmd.length()-1).trimmed();
230 g_curOption = g_options->value(cmd);
231 if (g_curOption==0) // oops not known
233 config_warn("ignoring unsupported tag `%s' at line %d, file %s\n",
234 qPrintable(cmd),yylineno,qPrintable(g_yyFileName));
239 //option->setEncoding(encoding);
240 g_arg = &g_curOption->value();
241 switch(g_curOption->kind())
244 g_elemStr = QString();
245 *g_arg = QStringList();
257 case Input::Obsolete:
258 config_warn("Tag `%s' at line %d of file %s has become obsolete.\n"
259 "To avoid this warning please update your configuration "
260 "file using \"doxygen -u\"\n", qPrintable(cmd),
261 yylineno,qPrintable(g_yyFileName));
267 <Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QString cmd=g_codec->toUnicode(yytext);
268 cmd=cmd.left(cmd.length()-2).trimmed();
269 g_curOption = g_options->value(cmd);
270 if (g_curOption==0) // oops not known
272 config_warn("ignoring unsupported tag `%s' at line %d, file %s\n",
273 yytext,yylineno,qPrintable(g_yyFileName));
278 switch(g_curOption->kind())
281 g_arg = &g_curOption->value();
288 config_warn("operator += not supported for `%s'. Ignoring line at line %d, file %s\n",
289 yytext,yylineno,qPrintable(g_yyFileName));
292 case Input::Obsolete:
293 config_warn("Tag `%s' at line %d of file %s has become obsolete.\n"
294 "To avoid this warning please update your configuration "
295 "file using \"doxygen -u\"\n",
296 qPrintable(cmd),yylineno,qPrintable(g_yyFileName));
302 <Start>"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_elemStr=QString(); }
303 /* include a config file */
304 <Start>"@INCLUDE"[ \t]*"=" { BEGIN(Include);}
305 <Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") {
306 readIncludeFile(g_codec->toUnicode(yytext));
310 //printf("End of include file\n");
311 //printf("Include stack depth=%d\n",g_includeStack.count());
312 if (g_includeStack.isEmpty())
314 //printf("Terminating scanner!\n");
319 ConfigFileState *fs = g_includeStack.pop();
321 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
322 yy_switch_to_buffer( fs->oldState );
323 yy_delete_buffer( oldBuf );
324 g_yyFileName=fs->fileName;
330 <Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag `%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); }
331 <GetString,SkipInvalid>\n { BEGIN(Start); }
333 if (!g_elemStr.isEmpty())
335 //printf("elemStr1=`%s'\n",qPrintable(elemStr));
336 *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
341 if (!g_elemStr.isEmpty())
343 //printf("elemStr2=`%s'\n",qPrintable(elemStr));
344 *g_arg = QVariant(g_arg->toStringList() << g_elemStr);
346 g_elemStr = QString();
348 <GetString>[^ \"\t\r\n]+ {
349 *g_arg = QVariant(g_codec->toUnicode(yytext));
352 <GetString,GetStrList,SkipInvalid>"\"" { g_lastState=YY_START;
353 BEGIN(GetQuotedString);
356 <GetQuotedString>"\""|"\n" {
357 // we add a bogus space to signal that the string was quoted. This space will be stripped later on.
359 //printf("Quoted String = `%s'\n",qPrintable(tmpString));
360 if (g_lastState==GetString)
362 *g_arg = g_codec->toUnicode(g_tmpString);
367 g_elemStr+=g_codec->toUnicode(g_tmpString);
371 config_warn("Missing end quote (\") on line %d, file %s\n",yylineno,
372 qPrintable(g_yyFileName));
376 <GetQuotedString>"\\\"" {
379 <GetQuotedString>. { g_tmpString+=*yytext; }
380 <GetStrList>[^ \#\"\t\r\n]+ {
381 g_elemStr+=g_codec->toUnicode(yytext);
383 <SkipComment>\n { BEGIN(Start); }
384 <SkipComment>\\[ \r\t]*\n { BEGIN(Start); }
391 /*@ ----------------------------------------------------------------------------
394 static void substEnvVarsInString(QString &s)
396 static QRegExp re(QString::fromLatin1("\\$\\([a-z_A-Z0-9]+\\)"));
397 if (s.isEmpty()) return;
400 //printf("substEnvVarInString(%s) start\n",qPrintable(s));
401 while ((i=re.indexIn(s,p))!=-1)
403 l = re.matchedLength();
404 //printf("Found environment var s.mid(%d,%d)=`%s'\n",i+2,l-3,qPrintable(s.mid(i+2,l-3)));
405 QString env=g_codec->toUnicode(getenv(s.mid(i+2,l-3).toLatin1()));
406 substEnvVarsInString(env); // recursively expand variables if needed.
407 s = s.left(i)+env+s.right(s.length()-i-l);
408 p=i+env.length(); // next time start at the end of the expanded string
410 s=s.trimmed(); // to strip the bogus space that was added when an argument
412 //printf("substEnvVarInString(%s) end\n",qPrintable(s));
415 static void substEnvVarsInStrList(QStringList &sl)
419 foreach (QString result, sl)
421 // an argument with quotes will have an extra space at the end, so wasQuoted will be TRUE.
422 bool wasQuoted = (result.indexOf(QChar::fromLatin1(' '))!=-1) ||
423 (result.indexOf(QChar::fromLatin1('\t'))!=-1);
424 // here we strip the quote again
425 substEnvVarsInString(result);
427 //printf("Result %s was quoted=%d\n",qPrintable(result),wasQuoted);
429 if (!wasQuoted) /* as a result of the expansion, a single string
430 may have expanded into a list, which we'll
431 add to sl. If the original string already
432 contained multiple elements no further
433 splitting is done to allow quoted items with spaces! */
435 int l=result.length();
438 // search for a "word"
442 // skip until start of new word
443 while (i<l && ((c=result.at(i))==QChar::fromLatin1(' ') || c==QChar::fromLatin1('\t'))) i++;
444 p=i; // p marks the start index of the word
445 // skip until end of a word
446 while (i<l && ((c=result.at(i))!=QChar::fromLatin1(' ') &&
447 c!=QChar::fromLatin1('\t') &&
448 c!=QChar::fromLatin1('"'))) i++;
449 if (i<l) // not at the end of the string
451 if (c==QChar::fromLatin1('"')) // word within quotes
457 if (c==QChar::fromLatin1('"')) // end quote
459 out += result.mid(p,i-p);
463 else if (c==QChar::fromLatin1('\\')) // skip escaped stuff
469 else if (c==QChar::fromLatin1(' ') || c==QChar::fromLatin1('\t')) // separator
471 out += result.mid(p,i-p);
476 if (p!=l) // add the leftover as a string
478 out += result.right(l-p);
481 else // just goto the next element in the list
489 //--------------------------------------------------------------------------
492 const QString &fileName,
493 const QHash<QString,Input *> &options
496 QHashIterator<QString, Input*> i(options);
497 g_file = fopen(fileName.toLocal8Bit(),"r");
498 if (g_file==NULL) return false;
512 g_options = &options;
513 g_yyFileName = fileName;
514 g_includeStack.clear();
516 config_doxywYYrestart( config_doxywYYin );
520 // update the values in the UI
527 //printf("Updating: %s\n",qPrintable(i.key()));
532 printf("Invalid option: %s\n",qPrintable(i.key()));
539 void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s)
542 bool needsEscaping=false;
543 // convert the string back to it original encoding
544 //QByteArray se = codec->fromUnicode(s);
546 const QChar *p=s.data();
547 if (!s.isEmpty() && !p->isNull())
549 while (!(c=*p++).isNull() && !needsEscaping)
551 needsEscaping = (c==QChar::fromLatin1(' ') ||
552 c==QChar::fromLatin1('\n') ||
553 c==QChar::fromLatin1('\t') ||
554 c==QChar::fromLatin1('"'));
562 if (*p ==QChar::fromLatin1(' ') &&
563 *(p+1)==QChar::fromLatin1('\0')) break; // skip inserted space at the end
564 if (*p ==QChar::fromLatin1('"')) t << "\\"; // escape quotes