summaryrefslogtreecommitdiffstats
path: root/src/commentcnv.l
diff options
context:
space:
mode:
Diffstat (limited to 'src/commentcnv.l')
-rw-r--r--src/commentcnv.l207
1 files changed, 179 insertions, 28 deletions
diff --git a/src/commentcnv.l b/src/commentcnv.l
index 76c624f..7c182e2 100644
--- a/src/commentcnv.l
+++ b/src/commentcnv.l
@@ -22,19 +22,36 @@
#include <stdio.h>
#include <stdlib.h>
+#include <qstack.h>
+#include <qregexp.h>
+
#include "bufstr.h"
#include "debug.h"
#include "message.h"
#include "config.h"
#include "doxygen.h"
-static BufStr *g_inBuf;
-static BufStr *g_outBuf;
-static int g_inBufPos;
-static int g_col;
-static int g_blockHeadCol;
-static bool g_mlBrief;
-static int g_readLineCtx;
+struct CondCtx
+{
+ CondCtx(int line,QCString id,bool b)
+ : lineNr(line),sectionId(id), skip(b) {}
+ int lineNr;
+ QCString sectionId;
+ bool skip;
+};
+
+static BufStr * g_inBuf;
+static BufStr * g_outBuf;
+static int g_inBufPos;
+static int g_col;
+static int g_blockHeadCol;
+static bool g_mlBrief;
+static int g_readLineCtx;
+static bool g_skip;
+static QCString g_fileName;
+static int g_lineNr;
+static int g_condCtx;
+static QStack<CondCtx> g_condStack;
static void replaceCommentMarker(const char *s,int len)
{
@@ -44,6 +61,7 @@ static void replaceCommentMarker(const char *s,int len)
while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
{
g_outBuf->addChar(c);
+ g_lineNr += c=='\n';
p++;
}
// replace start of comment marker by spaces
@@ -82,20 +100,115 @@ static inline int computeIndent(const char *s)
static inline void copyToOutput(const char *s,int len)
{
- g_outBuf->addArray(s,len);
int i;
- static int tabSize=Config_getInt("TAB_SIZE");
- for (i=0;i<len;i++)
+ if (g_skip) // only add newlines.
{
- switch (s[i])
+ for (i=0;i<len;i++)
{
- case '\n': g_col=0; break;
- case '\t': g_col+=tabSize-(g_col%tabSize); break;
- default: g_col++; break;
+ if (s[i]=='\n')
+ {
+ g_outBuf->addChar('\n');
+ g_lineNr++;
+ }
+ }
+ }
+ else
+ {
+ g_outBuf->addArray(s,len);
+ static int tabSize=Config_getInt("TAB_SIZE");
+ for (i=0;i<len;i++)
+ {
+ switch (s[i])
+ {
+ case '\n': g_col=0; g_lineNr++; break;
+ case '\t': g_col+=tabSize-(g_col%tabSize); break;
+ default: g_col++; break;
+ }
}
}
}
+static void startCondSection(const char *sectId)
+{
+ g_condStack.push(new CondCtx(g_lineNr,sectId,g_skip));
+ if (Config_getList("ENABLED_SECTIONS").find(sectId)!=-1)
+ {
+ //printf("*** Section is enabled!\n");
+ }
+ else
+ {
+ //printf("*** Section is disabled!\n");
+ g_skip=TRUE;
+ }
+}
+
+static void endCondSection()
+{
+ if (g_condStack.isEmpty())
+ {
+ warn(g_fileName,g_lineNr,"Found \\endcond command without matching \\cond");
+ g_skip=FALSE;
+ }
+ else
+ {
+ CondCtx *ctx = g_condStack.pop();
+ g_skip=ctx->skip;
+ }
+}
+
+/** remove and executes \\cond and \\endcond commands in \a s */
+static QCString handleCondCmdInAliases(const QCString &s)
+{
+ QCString result;
+ //printf("handleCondCmdInAliases(%s)\n",s.data());
+ static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*");
+ int p=0,i,l;
+ while ((i=cmdPat.match(s,p,&l))!=-1)
+ {
+ result+=s.mid(p,i-p);
+ QCString cmd = s.mid(i+1,l-1);
+ //printf("Found command %s\n",cmd.data());
+ if (cmd=="cond")
+ {
+ int sp=i+l,ep;
+ const char *arg=s.data()+sp;
+ char c;
+ // skip spaces
+ while ((c=*arg) && (c==' ' || c=='\t')) arg++,sp++;
+ // read argument
+ if (*arg=='\n') // no arg
+ {
+ startCondSection(" ");
+ ep=sp;
+ }
+ else // get argument
+ {
+ while ((c=*arg) && isId(c)) arg++,ep++;
+ if (ep>sp)
+ {
+ QCString id = s.mid(sp,ep-sp);
+ //printf("Found conditional section id %s\n",id.data());
+ startCondSection(id);
+ }
+ }
+ p=ep;
+ }
+ else if (cmd=="endcond")
+ {
+ endCondSection();
+ p=i+l;
+ }
+ else
+ {
+ result+=s.mid(i,l);
+ p=i+l;
+ }
+ }
+ result+=s.right(s.length()-p);
+ return result;
+}
+
+
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
@@ -122,6 +235,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
%x CComment
%x Verbatim
%x ReadLine
+%x CondLine
%%
@@ -213,17 +327,6 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
copyToOutput(yytext,yyleng);
BEGIN(Scan);
}
-<CComment>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
- QCString *pValue=Doxygen::aliasDict[yytext+1];
- if (pValue)
- {
- copyToOutput(pValue->data(),pValue->length());
- }
- else
- {
- copyToOutput(yytext,yyleng);
- }
- }
<CComment>. {
copyToOutput(yytext,yyleng);
}
@@ -276,11 +379,47 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
copyToOutput(yytext,yyleng);
BEGIN(g_readLineCtx);
}
-<ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
+<CComment,ReadLine>("\\\\"|"@@")[a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
+ copyToOutput(yytext,yyleng);
+ }
+<CComment,ReadLine>[\\@]"cond"[ \t]+ { // conditional section
+ g_condCtx = YY_START;
+ BEGIN(CondLine);
+ }
+<CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
+ bool oldSkip=g_skip;
+ endCondSection();
+ if (YY_START==CComment && oldSkip && !g_skip)
+ {
+ //printf("** Adding start of comment!\n");
+ g_outBuf->addChar('/');
+ g_outBuf->addChar('*');
+ }
+ }
+<CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]* {
+ bool oldSkip=g_skip;
+ startCondSection(yytext);
+ if (g_condCtx==CComment && !oldSkip && g_skip)
+ {
+ //printf("** Adding terminator for comment!\n");
+ g_outBuf->addChar('*');
+ g_outBuf->addChar('/');
+ }
+ BEGIN(g_condCtx);
+ }
+<CondLine>[ \t]*
+<CComment,ReadLine>[\\@]"cond"[ \t]*\n |
+<CondLine>. { // forgot section id?
+ startCondSection(" "); // fake section id causing the section to be hidden unconditionally
+ if (*yytext=='\n') g_lineNr++;
+ if (YY_START==CondLine) BEGIN(g_condCtx);
+ }
+<CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
QCString *pValue=Doxygen::aliasDict[yytext+1];
if (pValue)
{
- copyToOutput(pValue->data(),pValue->length());
+ QCString val = handleCondCmdInAliases(*pValue);
+ copyToOutput(val.data(),val.length());
}
else
{
@@ -320,16 +459,28 @@ void replaceComment(int offset)
* -# It converts multi-line C++ style comment blocks (that are aligned)
* to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
* -# It replaces aliases with their definition (see ALIASES)
+ * -# It handles conditional sections (\cond...\endcond blocks)
*/
-void convertCppComments(BufStr *inBuf,BufStr *outBuf)
+void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
{
g_inBuf = inBuf;
g_outBuf = outBuf;
g_inBufPos = 0;
g_col = 0;
g_mlBrief = Config_getBool("MULTILINE_CPP_IS_BRIEF");
+ g_skip = FALSE;
+ g_fileName = fileName;
+ g_lineNr = 0;
+ g_condStack.clear();
+ g_condStack.setAutoDelete(TRUE);
BEGIN(Scan);
yylex();
+ while (!g_condStack.isEmpty())
+ {
+ CondCtx *ctx = g_condStack.pop();
+ warn(g_fileName,ctx->lineNr,"Conditional section with %s does not have "
+ "a corresponding \\endcond command within this file.",ctx->sectionId.data());
+ }
if (Debug::isFlagSet(Debug::CommentCnv))
{
msg("-------------\n%s\n-------------\n",g_outBuf->data());