summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDimitri van Heesch <dimitri@stack.nl>2013-05-25 22:25:01 (GMT)
committerDimitri van Heesch <dimitri@stack.nl>2013-05-26 18:42:23 (GMT)
commit1941e88efd5d0f1f049b50eb258dff2a19e739d9 (patch)
tree9aa73264d2b7ace20267f8171299a3cde9c64074 /src
parentae845dea83a92093c18081db96014eb604f76d79 (diff)
downloadDoxygen-1941e88efd5d0f1f049b50eb258dff2a19e739d9.zip
Doxygen-1941e88efd5d0f1f049b50eb258dff2a19e739d9.tar.gz
Doxygen-1941e88efd5d0f1f049b50eb258dff2a19e739d9.tar.bz2
Bug 691315 - Line breaks are not copied/displayed properly when using @copydoc.
Bug 700788 - probably unintentional modification of behaviour of @copydetails
Diffstat (limited to 'src')
-rw-r--r--src/commentscan.l40
-rw-r--r--src/docparser.cpp194
2 files changed, 179 insertions, 55 deletions
diff --git a/src/commentscan.l b/src/commentscan.l
index 45f5425..ef70dfd 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -116,6 +116,8 @@ static bool handleToc(const QCString &s);
static bool handleInherit(const QCString &);
static bool handleExtends(const QCString &);
static bool handleCopyDoc(const QCString &);
+static bool handleCopyBrief(const QCString &);
+static bool handleCopyDetails(const QCString &);
typedef bool (*DocCmdFunc)(const QCString &name);
@@ -218,8 +220,8 @@ static DocCmdMap docCmdMap[] =
{ "author", 0, TRUE },
{ "authors", 0, TRUE },
{ "copydoc", &handleCopyDoc, TRUE },
- { "copybrief", 0, FALSE },
- { "copydetails", 0, TRUE },
+ { "copybrief", &handleCopyBrief, FALSE },
+ { "copydetails", &handleCopyDetails, TRUE },
{ "copyright", 0, TRUE },
{ "date", 0, TRUE },
{ "dotfile", 0, TRUE },
@@ -2674,9 +2676,43 @@ static bool handleExtends(const QCString &)
return FALSE;
}
+static bool handleCopyBrief(const QCString &)
+{
+ if (current->brief.isEmpty() && current->doc.isEmpty())
+ { // if we don't have a brief or detailed description yet,
+ // then the @copybrief should end up in the brief description.
+ // otherwise it will be copied inline (see bug691315 & bug700788)
+ setOutput(OutputBrief);
+ }
+ if (g_spaceBeforeCmd)
+ {
+ addOutput(' ');
+ g_spaceBeforeCmd=FALSE;
+ }
+ addOutput("\\copybrief ");
+ return FALSE;
+}
+
+static bool handleCopyDetails(const QCString &)
+{
+ setOutput(OutputDoc);
+ if (g_spaceBeforeCmd)
+ {
+ addOutput(' ');
+ g_spaceBeforeCmd=FALSE;
+ }
+ addOutput("\\copydetails ");
+ return FALSE;
+}
+
static bool handleCopyDoc(const QCString &)
{
setOutput(OutputBrief);
+ if (g_spaceBeforeCmd)
+ {
+ addOutput(' ');
+ g_spaceBeforeCmd=FALSE;
+ }
addOutput("\\copybrief ");
g_copyDocArg.resize(0);
BEGIN(CopyDoc);
diff --git a/src/docparser.cpp b/src/docparser.cpp
index 4d4f055..b1aba91 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -51,6 +51,7 @@
#include "reflist.h"
#include "formula.h"
#include "config.h"
+#include "growbuf.h"
// debug off
#define DBG(x) do {} while(0)
@@ -1528,39 +1529,6 @@ handlepara:
//---------------------------------------------------------------------------
-static int handleDocCopy(DocNode *parent,QList<DocNode> &children)
-{
- int tok=doctokenizerYYlex();
- int cmdId = Mappers::cmdMapper->map(g_token->name);
- if (tok!=TK_WHITESPACE)
- {
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(g_token->name));
- return 0;
- }
- tok=doctokenizerYYlex();
- if (tok==0)
- {
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
- "argument of command %s\n", qPrint(g_token->name));
- return 0;
- }
- else if (tok!=TK_WORD && tok!=TK_LNKWORD)
- {
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
- tokToString(tok),qPrint(g_token->name));
- return 0;
- }
- DocCopy *cpy = new DocCopy(parent,g_token->name,
- cmdId==CMD_COPYDOC || cmdId==CMD_COPYBRIEF,
- cmdId==CMD_COPYDOC || cmdId==CMD_COPYDETAILS);
- cpy->parse(children);
- delete cpy;
- return TK_NEWPARA;
-}
-
-//---------------------------------------------------------------------------
-
static void handleImg(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
{
HtmlAttribListIterator li(tagHtmlAttribs);
@@ -1757,10 +1725,6 @@ static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
{
delete par;
}
- if (retval==RetVal_CopyDoc)
- {
- retval=handleDocCopy(parent,children);
- }
} while (retval==TK_NEWPARA);
if (lastPar) lastPar->markLast();
@@ -3239,10 +3203,6 @@ int DocInternal::parse(int level)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found",doctokenizerYYlineno);
}
- else if (retval==RetVal_CopyDoc)
- {
- retval=handleDocCopy(this,m_children);
- }
} while (retval!=0 &&
retval!=RetVal_Section &&
retval!=RetVal_Subsection &&
@@ -5597,7 +5557,8 @@ int DocPara::handleCommand(const QCString &cmdName)
case CMD_COPYDOC: // fall through
case CMD_COPYBRIEF: // fall through
case CMD_COPYDETAILS:
- retval = RetVal_CopyDoc;
+ //retval = RetVal_CopyDoc;
+ // these commands should already be resolved by processCopyDoc()
break;
case CMD_INCLUDE:
handleInclude(cmdName,DocInclude::Include);
@@ -6648,10 +6609,6 @@ int DocSection::parse()
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
}
- else if (retval==RetVal_CopyDoc)
- {
- retval=handleDocCopy(this,m_children);
- }
} while (retval!=0 &&
retval!=RetVal_Internal &&
retval!=RetVal_Section &&
@@ -6868,10 +6825,6 @@ void DocRoot::parse()
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"found paragraph command outside of subsubsection context!");
}
- else if (retval==RetVal_CopyDoc)
- {
- retval=handleDocCopy(this,m_children);
- }
} while (retval!=0 && retval!=RetVal_Section && retval!=RetVal_Internal);
if (lastPar) lastPar->markLast();
@@ -6909,6 +6862,140 @@ void DocRoot::parse()
DBG(("DocRoot::parse() end\n"));
}
+static QCString extractCopyDocId(const char *data, uint &j, uint len)
+{
+ uint s=j;
+ uint e=j;
+ int round=0;
+ bool insideDQuote=FALSE;
+ bool insideSQuote=FALSE;
+ bool found=FALSE;
+ while (j<len && !found)
+ {
+ if (!insideSQuote && !insideDQuote)
+ {
+ switch (data[j])
+ {
+ case '(': round++; break;
+ case ')': round--; break;
+ case '"': insideDQuote=TRUE; break;
+ case '\'': insideSQuote=TRUE; break;
+ case ' ': // fall through
+ case '\t': // fall through
+ case '\n':
+ found=(round==0);
+ break;
+ }
+ }
+ else if (insideSQuote) // look for single quote end
+ {
+ if (data[j]=='\'' && (j==0 || data[j]!='\\'))
+ {
+ insideSQuote=FALSE;
+ }
+ }
+ else if (insideDQuote) // look for double quote end
+ {
+ if (data[j]=='"' && (j==0 || data[j]!='\\'))
+ {
+ insideDQuote=FALSE;
+ }
+ }
+ if (!found) j++;
+ }
+ e=j;
+ QCString id(e-s+1);
+ if (e>s) memcpy(id.data(),data+s,e-s);
+ id.at(e-s)='\0';
+ //printf("extractCopyDocId=%s input='%s'\n",id.data(),&data[s]);
+ return id;
+}
+
+static uint isCopyBriefOrDetailsCmd(const char *data, uint i,uint len,bool &brief)
+{
+ int j=0;
+ if (i==0 || (data[i-1]!='@' && data[i-1]!='\\')) // not an escaped command
+ {
+ if (i+10<len && qstrncmp(data+i+1,"copybrief",9)==0) // @copybrief or \copybrief
+ {
+ j=i+10;
+ brief=TRUE;
+ }
+ else if (i+12<len && qstrncmp(data+i+1,"copydetails",11)==0) // @copydetails or \copydetails
+ {
+ j=i+12;
+ brief=FALSE;
+ }
+ }
+ return j;
+}
+
+static QCString processCopyDoc(const char *data,uint &len)
+{
+ //printf("processCopyDoc start '%s'\n",data);
+ GrowBuf buf;
+ uint i=0;
+ while (i<len)
+ {
+ char c = data[i];
+ if (c=='@' || c=='\\') // look for a command
+ {
+ bool isBrief=TRUE;
+ uint j=isCopyBriefOrDetailsCmd(data,i,len,isBrief);
+ if (j>0)
+ {
+ // skip whitespace
+ while (j<len && (data[j]==' ' || data[j]=='\t')) j++;
+ // extract the argument
+ QCString id = extractCopyDocId(data,j,len);
+ Definition *def;
+ QCString doc,brief;
+ //printf("resolving docs='%s'\n",id.data());
+ if (findDocsForMemberOrCompound(id,&doc,&brief,&def))
+ {
+ //printf("found it def=%p brief='%s' doc='%s' isBrief=%d\n",def,brief.data(),doc.data(),isBrief);
+ if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
+ {
+ g_copyStack.append(def);
+ if (isBrief)
+ {
+ uint l=brief.length();
+ buf.addStr(processCopyDoc(brief,l));
+ }
+ else
+ {
+ uint l=doc.length();
+ buf.addStr(processCopyDoc(doc,l));
+ }
+ g_copyStack.remove(def);
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,
+ "Found recursive @copy%s or @copydoc relation for argument '%s'.\n",
+ isBrief?"brief":"details",id.data());
+ }
+ }
+ // skip over command
+ i=j;
+ }
+ else
+ {
+ buf.addChar(c);
+ i++;
+ }
+ }
+ else // not a command, just copy
+ {
+ buf.addChar(c);
+ i++;
+ }
+ }
+ len = buf.getPos();
+ buf.addChar(0);
+ return buf.get();
+}
+
//--------------------------------------------------------------------------
DocRoot *validatingParseDoc(const char *fileName,int startLine,
@@ -7074,12 +7161,13 @@ DocRoot *validatingParseDoc(const char *fileName,int startLine,
//printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
doctokenizerYYlineno=startLine;
- QCString inpStr=input;
- uint inpLen = inpStr.length();
- if (inpLen>0 && inpStr.at(inpLen-1)!='\n')
+ uint inpLen=qstrlen(input);
+ QCString inpStr = processCopyDoc(input,inpLen);
+ if (inpStr.isEmpty() || inpStr.at(inpStr.length()-1)!='\n')
{
inpStr+='\n';
}
+ //printf("processCopyDoc(in='%s' out='%s')\n",input,inpStr.data());
doctokenizerYYinit(inpStr,g_fileName);
// build abstract syntax tree