diff options
author | Dimitri van Heesch <dimitri@stack.nl> | 2013-05-25 22:25:01 (GMT) |
---|---|---|
committer | Dimitri van Heesch <dimitri@stack.nl> | 2013-05-26 18:42:23 (GMT) |
commit | 1941e88efd5d0f1f049b50eb258dff2a19e739d9 (patch) | |
tree | 9aa73264d2b7ace20267f8171299a3cde9c64074 /src | |
parent | ae845dea83a92093c18081db96014eb604f76d79 (diff) | |
download | Doxygen-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.l | 40 | ||||
-rw-r--r-- | src/docparser.cpp | 194 |
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 |