Doxygen
Markdown类 参考

Helper class to process markdown formatted text 更多...

#include <markdown.h>

+ Markdown 的协作图:

struct  LinkRef
 

Public 成员函数

 Markdown (const QCString &fileName, int lineNr, int indentLevel=0)
 
QCString process (const QCString &input, int &startNewlines, bool fromParseInput=false)
 
QCString extractPageTitle (QCString &docs, QCString &id, int &prepend)
 
void setIndentLevel (int level)
 

Private 类型

using Action_t = std::function< int(const char *, int, int)>
 

Private 成员函数

QCString detab (const QCString &s, int &refIndent)
 
QCString processQuotations (const QCString &s, int refIndent)
 
QCString processBlocks (const QCString &s, int indent)
 
QCString isBlockCommand (const char *data, int offset, int size)
 
void findEndOfLine (const char *data, int size, int &pi, int &i, int &end)
 
int processHtmlTagWrite (const char *data, int offset, int size, bool doWrite)
 Process a HTML tag. 更多...
 
int processHtmlTag (const char *data, int offset, int size)
 
int processEmphasis (const char *data, int offset, int size)
 
int processEmphasis1 (const char *data, int size, char c)
 process single emphasis 更多...
 
int processEmphasis2 (const char *data, int size, char c)
 process double emphasis 更多...
 
int processEmphasis3 (const char *data, int size, char c)
 Parsing triple emphasis. 更多...
 
int processNmdash (const char *data, int off, int size)
 Process ndash and mdashes 更多...
 
int processQuoted (const char *data, int, int size)
 Process quoted section "...", can contain one embedded newline 更多...
 
int processCodeSpan (const char *data, int, int size)
 '‘’ parsing a code span (assuming codespan != 0) 更多...
 
void addStrEscapeUtf8Nbsp (const char *s, int len)
 
int processSpecialCommand (const char *data, int offset, int size)
 
int processLink (const char *data, int, int size)
 
int findEmphasisChar (const char *data, int size, char c, int c_size)
 looks for the next emph char, skipping other constructs, and stopping when either it is found, or we are at the end of a paragraph. 更多...
 
void processInline (const char *data, int size)
 
void writeMarkdownImage (const char *fmt, bool explicitTitle, const QCString &title, const QCString &content, const QCString &link, const FileDef *fd)
 
int isHeaderline (const char *data, int size, bool allowAdjustLevel)
 returns whether the line is a setext-style hdr underline 更多...
 
int isAtxHeader (const char *data, int size, QCString &header, QCString &id, bool allowAdjustLevel)
 
void writeOneLineHeaderOrRuler (const char *data, int size)
 
void writeFencedCodeBlock (const char *data, const char *lng, int blockStart, int blockEnd)
 
int writeBlockQuote (const char *data, int size)
 
int writeCodeBlock (const char *data, int size, int refIndent)
 
int writeTableBlock (const char *data, int size)
 

Private 属性

std::unordered_map< std::string, LinkRefm_linkRefs
 
QCString m_fileName
 
int m_lineNr = 0
 
int m_indentLevel =0
 
GrowBuf m_out
 
Markdown::Action_t m_actions [256]
 

详细描述

Helper class to process markdown formatted text

在文件 markdown.h32 行定义.

成员类型定义说明

◆ Action_t

using Markdown::Action_t = std::function<int(const char *,int,int)>
private

在文件 markdown.h80 行定义.

构造及析构函数说明

◆ Markdown()

Markdown::Markdown ( const QCString fileName,
int  lineNr,
int  indentLevel = 0 
)

在文件 markdown.cpp207 行定义.

208  : m_fileName(fileName), m_lineNr(lineNr), m_indentLevel(indentLevel)
209 {
210  using namespace std::placeholders;
211  // setup callback table for special characters
212  m_actions[(unsigned int)'_'] = std::bind(&Markdown::processEmphasis, this,_1,_2,_3);
213  m_actions[(unsigned int)'*'] = std::bind(&Markdown::processEmphasis, this,_1,_2,_3);
214  m_actions[(unsigned int)'~'] = std::bind(&Markdown::processEmphasis, this,_1,_2,_3);
215  m_actions[(unsigned int)'`'] = std::bind(&Markdown::processCodeSpan, this,_1,_2,_3);
216  m_actions[(unsigned int)'\\']= std::bind(&Markdown::processSpecialCommand,this,_1,_2,_3);
217  m_actions[(unsigned int)'@'] = std::bind(&Markdown::processSpecialCommand,this,_1,_2,_3);
218  m_actions[(unsigned int)'['] = std::bind(&Markdown::processLink, this,_1,_2,_3);
219  m_actions[(unsigned int)'!'] = std::bind(&Markdown::processLink, this,_1,_2,_3);
220  m_actions[(unsigned int)'<'] = std::bind(&Markdown::processHtmlTag, this,_1,_2,_3);
221  m_actions[(unsigned int)'-'] = std::bind(&Markdown::processNmdash, this,_1,_2,_3);
222  m_actions[(unsigned int)'"'] = std::bind(&Markdown::processQuoted, this,_1,_2,_3);
223  (void)m_lineNr; // not used yet
224 }

引用了 m_actions, m_lineNr, processCodeSpan(), processEmphasis(), processHtmlTag(), processLink(), processNmdash(), processQuoted() , 以及 processSpecialCommand().

成员函数说明

◆ addStrEscapeUtf8Nbsp()

void Markdown::addStrEscapeUtf8Nbsp ( const char *  s,
int  len 
)
private

在文件 markdown.cpp1312 行定义.

1313 {
1314  TRACE(s);
1315  if (Portable::strnstr(s,g_doxy_nsbp,len)==0) // no escape needed -> fast
1316  {
1317  m_out.addStr(s,len);
1318  }
1319  else // escape needed -> slow
1320  {
1321  m_out.addStr(substitute(QCString(s).left(len),g_doxy_nsbp,(const char *)g_utf8_nbsp));
1322  }
1323 }

引用了 GrowBuf::addStr(), g_doxy_nsbp, g_utf8_nbsp, m_out, Portable::strnstr(), substitute() , 以及 TRACE.

被这些函数引用 processSpecialCommand() , 以及 writeFencedCodeBlock().

◆ detab()

QCString Markdown::detab ( const QCString s,
int &  refIndent 
)
private

在文件 markdown.cpp2932 行定义.

2933 {
2934  TRACE(s);
2935  int tabSize = Config_getInt(TAB_SIZE);
2936  int size = s.length();
2937  m_out.clear();
2938  m_out.reserve(size);
2939  const char *data = s.data();
2940  int i=0;
2941  int col=0;
2942  const int maxIndent=1000000; // value representing infinity
2943  int minIndent=maxIndent;
2944  while (i<size)
2945  {
2946  signed char c = (signed char)data[i++];
2947  switch(c)
2948  {
2949  case '\t': // expand tab
2950  {
2951  int stop = tabSize - (col%tabSize);
2952  //printf("expand at %d stop=%d\n",col,stop);
2953  col+=stop;
2954  while (stop--) m_out.addChar(' ');
2955  }
2956  break;
2957  case '\n': // reset column counter
2958  m_out.addChar(c);
2959  col=0;
2960  break;
2961  case ' ': // increment column counter
2962  m_out.addChar(c);
2963  col++;
2964  break;
2965  default: // non-whitespace => update minIndent
2966  if (c<0 && i<size) // multibyte sequence
2967  {
2968  // special handling of the UTF-8 nbsp character 0xC2 0xA0
2969  int nb = isUTF8NonBreakableSpace(data);
2970  if (nb>0)
2971  {
2973  i+=nb-1;
2974  }
2975  else
2976  {
2977  int bytes = getUTF8CharNumBytes(c);
2978  for (int j=0;j<bytes-1 && c;j++)
2979  {
2980  m_out.addChar(c);
2981  c = data[i++];
2982  }
2983  m_out.addChar(c);
2984  }
2985  }
2986  else
2987  {
2988  m_out.addChar(c);
2989  }
2990  if (col<minIndent) minIndent=col;
2991  col++;
2992  }
2993  }
2994  if (minIndent!=maxIndent) refIndent=minIndent; else refIndent=0;
2995  m_out.addChar(0);
2996  //printf("detab refIndent=%d\n",refIndent);
2997  return m_out.get();
2998 }

引用了 GrowBuf::addChar(), GrowBuf::addStr(), GrowBuf::clear(), Config_getInt, QCString::data(), g_doxy_nsbp, GrowBuf::get(), getUTF8CharNumBytes(), isUTF8NonBreakableSpace(), QCString::length(), m_out, GrowBuf::reserve() , 以及 TRACE.

被这些函数引用 process().

◆ extractPageTitle()

QCString Markdown::extractPageTitle ( QCString docs,
QCString id,
int &  prepend 
)

在文件 markdown.cpp2881 行定义.

2882 {
2883  TRACE(docs);
2884  // first first non-empty line
2885  prepend = 0;
2886  QCString title;
2887  int i=0;
2888  int size=docs.size();
2889  QCString docs_org(docs);
2890  const char *data = docs_org.data();
2891  docs = "";
2892  while (i<size && (data[i]==' ' || data[i]=='\n'))
2893  {
2894  if (data[i]=='\n') prepend++;
2895  i++;
2896  }
2897  if (i>=size) { TRACE_RESULT(""); return ""; }
2898  int end1=i+1;
2899  while (end1<size && data[end1-1]!='\n') end1++;
2900  //printf("i=%d end1=%d size=%d line='%s'\n",i,end1,size,docs.mid(i,end1-i).data());
2901  // first line from i..end1
2902  if (end1<size)
2903  {
2904  // second line form end1..end2
2905  int end2=end1+1;
2906  while (end2<size && data[end2-1]!='\n') end2++;
2907  if (isHeaderline(data+end1,size-end1,FALSE))
2908  {
2909  convertStringFragment(title,data+i,end1-i-1);
2910  docs+="\n\n"+docs_org.mid(end2);
2911  id = extractTitleId(title, 0);
2912  //printf("extractPageTitle(title='%s' docs='%s' id='%s')\n",title.data(),docs.data(),id.data());
2913  TRACE_RESULT(title);
2914  return title;
2915  }
2916  }
2917  if (i<end1 && isAtxHeader(data+i,end1-i,title,id,FALSE)>0)
2918  {
2919  docs+="\n";
2920  docs+=docs_org.mid(end1);
2921  }
2922  else
2923  {
2924  docs=docs_org;
2925  id = extractTitleId(title, 0);
2926  }
2927  //printf("extractPageTitle(title='%s' docs='%s' id='%s')\n",qPrint(title),qPrint(docs),qPrint(id));
2928  TRACE_RESULT(title);
2929  return title;
2930 }

引用了 convertStringFragment(), QCString::data(), extractTitleId(), FALSE, isAtxHeader(), isHeaderline(), QCString::mid(), QCString::size(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 MarkdownOutlineParser::parseInput().

◆ findEmphasisChar()

int Markdown::findEmphasisChar ( const char *  data,
int  size,
char  c,
int  c_size 
)
private

looks for the next emph char, skipping other constructs, and stopping when either it is found, or we are at the end of a paragraph.

在文件 markdown.cpp431 行定义.

432 {
433  TRACE(data);
434  int i = 1;
435 
436  while (i<size)
437  {
438  while (i<size && data[i]!=c && data[i]!='`' &&
439  data[i]!='\\' && data[i]!='@' &&
440  !(data[i]=='/' && data[i-1]=='<') && // html end tag also ends emphasis
441  data[i]!='\n') i++;
442  //printf("findEmphasisChar: data=[%s] i=%d c=%c\n",data,i,data[i]);
443 
444  // not counting escaped chars or characters that are unlikely
445  // to appear as the end of the emphasis char
446  if (ignoreCloseEmphChar(i-1))
447  {
448  i++;
449  continue;
450  }
451  else
452  {
453  // get length of emphasis token
454  int len = 0;
455  while (i+len<size && data[i+len]==c)
456  {
457  len++;
458  }
459 
460  if (len>0)
461  {
462  if (len!=c_size || (i<size-len && isIdChar(i+len))) // to prevent touching some_underscore_identifier
463  {
464  i=i+len;
465  continue;
466  }
467  TRACE_RESULT(i);
468  return i; // found it
469  }
470  }
471 
472  // skipping a code span
473  if (data[i]=='`')
474  {
475  int snb=0;
476  while (i<size && data[i]=='`') snb++,i++;
477 
478  // find same pattern to end the span
479  int enb=0;
480  while (i<size && enb<snb)
481  {
482  if (data[i]=='`') enb++;
483  if (snb==1 && data[i]=='\'') break; // ` ended by '
484  i++;
485  }
486  }
487  else if (data[i]=='@' || data[i]=='\\')
488  { // skip over blocks that should not be processed
489  QCString endBlockName = isBlockCommand(data+i,i,size-i);
490  if (!endBlockName.isEmpty())
491  {
492  i++;
493  int l = endBlockName.length();
494  while (i<size-l)
495  {
496  if ((data[i]=='\\' || data[i]=='@') && // command
497  data[i-1]!='\\' && data[i-1]!='@') // not escaped
498  {
499  if (qstrncmp(&data[i+1],endBlockName.data(),l)==0)
500  {
501  break;
502  }
503  }
504  i++;
505  }
506  }
507  else if (i<size-1 && isIdChar(i+1)) // @cmd, stop processing, see bug 690385
508  {
509  TRACE_RESULT(0);
510  return 0;
511  }
512  else
513  {
514  i++;
515  }
516  }
517  else if (data[i-1]=='<' && data[i]=='/') // html end tag invalidates emphasis
518  {
519  TRACE_RESULT(0);
520  return 0;
521  }
522  else if (data[i]=='\n') // end * or _ at paragraph boundary
523  {
524  i++;
525  while (i<size && data[i]==' ') i++;
526  if (i>=size || data[i]=='\n') { TRACE_RESULT(0); return 0; } // empty line -> paragraph
527  }
528  else // should not get here!
529  {
530  i++;
531  }
532 
533  }
534  TRACE_RESULT(0);
535  return 0;
536 }

引用了 QCString::data(), ignoreCloseEmphChar, isBlockCommand(), QCString::isEmpty(), isIdChar, QCString::length(), qstrncmp(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 processEmphasis1(), processEmphasis2() , 以及 processEmphasis3().

◆ findEndOfLine()

void Markdown::findEndOfLine ( const char *  data,
int  size,
int &  pi,
int &  i,
int &  end 
)
private

在文件 markdown.cpp2438 行定义.

2440 {
2441  TRACE(data);
2442  // find end of the line
2443  int nb=0;
2444  end=i+1;
2445  //while (end<=size && data[end-1]!='\n')
2446  int j=0;
2447  while (end<=size && (j=isNewline(data+end-1))==0)
2448  {
2449  // while looking for the end of the line we might encounter a block
2450  // that needs to be passed unprocessed.
2451  if ((data[end-1]=='\\' || data[end-1]=='@') && // command
2452  (end<=1 || (data[end-2]!='\\' && data[end-2]!='@')) // not escaped
2453  )
2454  {
2455  QCString endBlockName = isBlockCommand(data+end-1,end-1,size-(end-1));
2456  end++;
2457  if (!endBlockName.isEmpty())
2458  {
2459  int l = endBlockName.length();
2460  for (;end<size-l-1;end++) // search for end of block marker
2461  {
2462  if ((data[end]=='\\' || data[end]=='@') &&
2463  data[end-1]!='\\' && data[end-1]!='@'
2464  )
2465  {
2466  if (qstrncmp(&data[end+1],endBlockName.data(),l)==0)
2467  {
2468  // found end marker, skip over this block
2469  //printf("feol.block m_out={%s}\n",qPrint(QCString(data+i).left(end+l+1-i)));
2470  end = end + l + 2;
2471  break;
2472  }
2473  }
2474  }
2475  }
2476  }
2477  else if (nb==0 && data[end-1]=='<' && end<size-6 &&
2478  (end<=1 || (data[end-2]!='\\' && data[end-2]!='@'))
2479  )
2480  {
2481  if (tolower(data[end])=='p' && tolower(data[end+1])=='r' &&
2482  tolower(data[end+2])=='e' && (data[end+3]=='>' || data[end+3]==' ')) // <pre> tag
2483  {
2484  // skip part until including </pre>
2485  end = end + processHtmlTagWrite(data+end-1,end-1,size-end+1,false) + 2;
2486  break;
2487  }
2488  else
2489  {
2490  end++;
2491  }
2492  }
2493  else if (nb==0 && data[end-1]=='`')
2494  {
2495  while (end<=size && data[end-1]=='`') end++,nb++;
2496  }
2497  else if (nb>0 && data[end-1]=='`')
2498  {
2499  int enb=0;
2500  while (end<=size && data[end-1]=='`') end++,enb++;
2501  if (enb==nb) nb=0;
2502  }
2503  else
2504  {
2505  end++;
2506  }
2507  }
2508  if (j>0) end+=j-1;
2509  //printf("findEndOfLine pi=%d i=%d end=%d {%s}\n",pi,i,end,qPrint(QCString(data+i).left(end-i)));
2510 }

引用了 QCString::data(), end(), isBlockCommand(), QCString::isEmpty(), isNewline(), QCString::length(), processHtmlTagWrite(), qstrncmp() , 以及 TRACE.

被这些函数引用 processBlocks() , 以及 processQuotations().

◆ isAtxHeader()

int Markdown::isAtxHeader ( const char *  data,
int  size,
QCString header,
QCString id,
bool  allowAdjustLevel 
)
private

在文件 markdown.cpp1618 行定义.

1620 {
1621  TRACE(data);
1622  int i = 0, end;
1623  int level = 0, blanks=0;
1624 
1625  // find start of header text and determine heading level
1626  while (i<size && data[i]==' ') i++;
1627  if (i>=size || data[i]!='#')
1628  {
1629  TRACE_RESULT(0);
1630  return 0;
1631  }
1632  while (i<size && level<6 && data[i]=='#') i++,level++;
1633  while (i<size && data[i]==' ') i++,blanks++;
1634  if (level==1 && blanks==0)
1635  {
1636  TRACE_RESULT(0);
1637  return 0; // special case to prevent #someid seen as a header (see bug 671395)
1638  }
1639 
1640  // find end of header text
1641  end=i;
1642  while (end<size && data[end]!='\n') end++;
1643  while (end>i && (data[end-1]=='#' || data[end-1]==' ')) end--;
1644 
1645  // store result
1646  convertStringFragment(header,data+i,end-i);
1647  id = extractTitleId(header, level);
1648  if (!id.isEmpty()) // strip #'s between title and id
1649  {
1650  i=header.length()-1;
1651  while (i>=0 && (header.at(i)=='#' || header.at(i)==' ')) i--;
1652  header=header.left(i+1);
1653  }
1654 
1655  if (allowAdjustLevel && level==1 && m_indentLevel==-1)
1656  {
1657  // in case we find a `# Section` on a markdown page that started with the same level
1658  // header, we no longer need to artificially decrease the paragraph level.
1659  // So both
1660  // -------------------
1661  // # heading 1 <-- here we set g_indentLevel to -1
1662  // # heading 2 <-- here we set g_indentLevel back to 0 such that this will be a @section
1663  // -------------------
1664  // and
1665  // -------------------
1666  // # heading 1 <-- here we set g_indentLevel to -1
1667  // ## heading 2 <-- here we keep g_indentLevel at -1 such that @subsection will be @section
1668  // -------------------
1669  // will convert to
1670  // -------------------
1671  // @page md_page Heading 1
1672  // @section autotoc_md1 Heading 2
1673  // -------------------
1674 
1675  m_indentLevel=0;
1676  }
1677  int res = level+m_indentLevel;
1678  TRACE_RESULT(res);
1679  return res;
1680 }

引用了 QCString::at(), convertStringFragment(), end(), extractTitleId(), QCString::left(), QCString::length(), m_indentLevel, TRACE , 以及 TRACE_RESULT.

被这些函数引用 extractPageTitle() , 以及 writeOneLineHeaderOrRuler().

◆ isBlockCommand()

QCString Markdown::isBlockCommand ( const char *  data,
int  offset,
int  size 
)
private

在文件 markdown.cpp364 行定义.

365 {
366  TRACE(data);
367  bool openBracket = offset>0 && data[-1]=='{';
368  bool isEscaped = offset>0 && (data[-1]=='\\' || data[-1]=='@');
369  if (isEscaped) return QCString();
370 
371  int end=1;
372  while (end<size && (data[end]>='a' && data[end]<='z')) end++;
373  if (end==1) return QCString();
374  QCString blockName;
375  convertStringFragment(blockName,data+1,end-1);
376  if (blockName=="code" && openBracket)
377  {
378  TRACE_RESULT("}");
379  return "}";
380  }
381  else if (blockName=="dot" ||
382  blockName=="code" ||
383  blockName=="msc" ||
384  blockName=="verbatim" ||
385  blockName=="latexonly" ||
386  blockName=="htmlonly" ||
387  blockName=="xmlonly" ||
388  blockName=="rtfonly" ||
389  blockName=="manonly" ||
390  blockName=="docbookonly"
391  )
392  {
393  QCString result = "end"+blockName;
394  TRACE_RESULT(result);
395  return result;
396  }
397  else if (blockName=="startuml")
398  {
399  TRACE_RESULT("enduml");
400  return "enduml";
401  }
402  else if (blockName=="f" && end<size)
403  {
404  if (data[end]=='$')
405  {
406  TRACE_RESULT("f$");
407  return "f$";
408  }
409  else if (data[end]=='(')
410  {
411  TRACE_RESULT("f)");
412  return "f)";
413  }
414  else if (data[end]=='[')
415  {
416  TRACE_RESULT("f]");
417  return "f]";
418  }
419  else if (data[end]=='{')
420  {
421  TRACE_RESULT("f}");
422  return "f}";
423  }
424  }
425  return QCString();
426 }

引用了 convertStringFragment(), end(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 findEmphasisChar(), findEndOfLine(), processBlocks() , 以及 processSpecialCommand().

◆ isHeaderline()

int Markdown::isHeaderline ( const char *  data,
int  size,
bool  allowAdjustLevel 
)
private

returns whether the line is a setext-style hdr underline

在文件 markdown.cpp1401 行定义.

1402 {
1403  TRACE(data);
1404  int i=0, c=0;
1405  while (i<size && data[i]==' ') i++;
1406 
1407  // test of level 1 header
1408  if (data[i]=='=')
1409  {
1410  while (i<size && data[i]=='=') i++,c++;
1411  while (i<size && data[i]==' ') i++;
1412  int level = (c>1 && (i>=size || data[i]=='\n')) ? 1 : 0;
1413  if (allowAdjustLevel && level==1 && m_indentLevel==-1)
1414  {
1415  // In case a page starts with a header line we use it as title, promoting it to @page.
1416  // We set g_indentLevel to -1 to promoting the other sections if they have a deeper
1417  // nesting level than the page header, i.e. @section..@subsection becomes @page..@section.
1418  // In case a section at the same level is found (@section..@section) however we need
1419  // to undo this (and the result will be @page..@section).
1420  m_indentLevel=0;
1421  }
1422  TRACE_RESULT(m_indentLevel+level);
1423  return m_indentLevel+level;
1424  }
1425  // test of level 2 header
1426  if (data[i]=='-')
1427  {
1428  while (i<size && data[i]=='-') i++,c++;
1429  while (i<size && data[i]==' ') i++;
1430  return (c>1 && (i>=size || data[i]=='\n')) ? m_indentLevel+2 : 0;
1431  }
1432  TRACE_RESULT(0);
1433  return 0;
1434 }

引用了 m_indentLevel, TRACE , 以及 TRACE_RESULT.

被这些函数引用 extractPageTitle() , 以及 processBlocks().

◆ process()

QCString Markdown::process ( const QCString input,
int &  startNewlines,
bool  fromParseInput = false 
)

在文件 markdown.cpp3002 行定义.

3003 {
3004  if (input.isEmpty()) return input;
3005  int refIndent;
3006 
3007  // for replace tabs by spaces
3008  QCString s = input;
3009  if (s.at(s.length()-1)!='\n') s += "\n"; // see PR #6766
3010  s = detab(s,refIndent);
3011  //printf("======== DeTab =========\n---- output -----\n%s\n---------\n",qPrint(s));
3012 
3013  // then process quotation blocks (as these may contain other blocks)
3014  s = processQuotations(s,refIndent);
3015  //printf("======== Quotations =========\n---- output -----\n%s\n---------\n",qPrint(s));
3016 
3017  // then process block items (headers, rules, and code blocks, references)
3018  s = processBlocks(s,refIndent);
3019  //printf("======== Blocks =========\n---- output -----\n%s\n---------\n",qPrint(s));
3020 
3021  // finally process the inline markup (links, emphasis and code spans)
3022  m_out.clear();
3023  processInline(s.data(),s.length());
3024  m_out.addChar(0);
3025  if (fromParseInput)
3026  {
3027  Debug::print(Debug::Markdown,0,"---- output -----\n%s\n=========\n",qPrint(m_out.get()));
3028  }
3029  else
3030  {
3031  Debug::print(Debug::Markdown,0,"======== Markdown =========\n---- input ------- \n%s\n---- output -----\n%s\n=========\n",qPrint(input),qPrint(m_out.get()));
3032  }
3033 
3034  // post processing
3035  QCString result = substitute(m_out.get(),g_doxy_nsbp,"&nbsp;");
3036  const char *p = result.data();
3037  if (p)
3038  {
3039  while (*p==' ') p++; // skip over spaces
3040  while (*p=='\n') {startNewlines++;p++;}; // skip over newlines
3041  if (qstrncmp(p,"<br>",4)==0) p+=4; // skip over <br>
3042  }
3043  if (p>result.data())
3044  {
3045  // strip part of the input
3046  result = result.mid(static_cast<int>(p-result.data()));
3047  }
3048  return result;
3049 }

引用了 GrowBuf::addChar(), QCString::at(), GrowBuf::clear(), QCString::data(), detab(), g_doxy_nsbp, GrowBuf::get(), QCString::isEmpty(), QCString::length(), m_out, Debug::Markdown, QCString::mid(), Debug::print(), processBlocks(), processInline(), processQuotations(), qPrint(), qstrncmp() , 以及 substitute().

被这些函数引用 VHDLOutlineParser::handleCommentBlock(), DocPara::handleInclude() , 以及 MarkdownOutlineParser::parseInput().

◆ processBlocks()

QCString Markdown::processBlocks ( const QCString s,
int  indent 
)
private

在文件 markdown.cpp2634 行定义.

2635 {
2636  TRACE(s);
2637  m_out.clear();
2638  const char *data = s.data();
2639  int size = s.length();
2640  int i=0,end=0,pi=-1,ref,level;
2641  QCString id,link,title;
2642  int blockIndent = indent;
2643 
2644  // get indent for the first line
2645  end = i+1;
2646  int sp=0;
2647  while (end<=size && data[end-1]!='\n')
2648  {
2649  if (data[end-1]==' ') sp++;
2650  end++;
2651  }
2652 
2653 #if 0 // commented m_out, since starting with a comment block is probably a usage error
2654  // see also http://stackoverflow.com/q/20478611/784672
2655 
2656  // special case when the documentation starts with a code block
2657  // since the first line is skipped when looking for a code block later on.
2658  if (end>codeBlockIndent && isCodeBlock(data,0,end,blockIndent))
2659  {
2660  i=writeCodeBlock(m_out,data,size,blockIndent);
2661  end=i+1;
2662  pi=-1;
2663  }
2664 #endif
2665 
2666  int currentIndent = indent;
2667  int listIndent = indent;
2668  bool insideList = false;
2669  bool newBlock = false;
2670  // process each line
2671  while (i<size)
2672  {
2673  findEndOfLine(data,size,pi,i,end);
2674  // line is now found at [i..end)
2675 
2676  int lineIndent=0;
2677  while (lineIndent<end && data[i+lineIndent]==' ') lineIndent++;
2678  //printf("** lineIndent=%d line=(%s)\n",lineIndent,qPrint(QCString(data+i).left(end-i)));
2679 
2680  if (newBlock)
2681  {
2682  //printf("** end of block\n");
2683  if (insideList && lineIndent<currentIndent) // end of list
2684  {
2685  //printf("** end of list\n");
2686  currentIndent = indent;
2687  blockIndent = indent;
2688  insideList = false;
2689  }
2690  newBlock = false;
2691  }
2692 
2693  if ((listIndent=isListMarker(data+i,end-i))) // see if we need to increase the indent level
2694  {
2695  if (listIndent<currentIndent+4)
2696  {
2697  //printf("** start of list\n");
2698  insideList = true;
2699  currentIndent = listIndent;
2700  blockIndent = listIndent;
2701  }
2702  }
2703  else if (isEndOfList(data+i,end-i))
2704  {
2705  //printf("** end of list\n");
2706  insideList = false;
2707  currentIndent = listIndent;
2708  blockIndent = listIndent;
2709  }
2710  else if (isEmptyLine(data+i,end-i))
2711  {
2712  //printf("** new block\n");
2713  newBlock = true;
2714  }
2715 
2716  //printf("indent=%d listIndent=%d blockIndent=%d\n",indent,listIndent,blockIndent);
2717 
2718  //printf("findEndOfLine: pi=%d i=%d end=%d\n",pi,i,end);
2719 
2720  if (pi!=-1)
2721  {
2722  int blockStart,blockEnd,blockOffset;
2723  QCString lang;
2724  blockIndent = currentIndent;
2725  //printf("isHeaderLine(%s)=%d\n",QCString(data+i).left(size-i).data(),level);
2726  QCString endBlockName;
2727  if (data[i]=='@' || data[i]=='\\') endBlockName = isBlockCommand(data+i,i,size-i);
2728  if (!endBlockName.isEmpty())
2729  {
2730  // handle previous line
2731  if (isLinkRef(data+pi,i-pi,id,link,title))
2732  {
2733  m_linkRefs.insert({id.lower().str(),LinkRef(link,title)});
2734  }
2735  else
2736  {
2737  writeOneLineHeaderOrRuler(data+pi,i-pi);
2738  }
2739  m_out.addChar(data[i]);
2740  i++;
2741  int l = endBlockName.length();
2742  while (i<size-l)
2743  {
2744  if ((data[i]=='\\' || data[i]=='@') && // command
2745  data[i-1]!='\\' && data[i-1]!='@') // not escaped
2746  {
2747  if (qstrncmp(&data[i+1],endBlockName.data(),l)==0)
2748  {
2749  m_out.addChar(data[i]);
2750  m_out.addStr(endBlockName);
2751  pi=i;
2752  i+=l+1;
2753  break;
2754  }
2755  }
2756  m_out.addChar(data[i]);
2757  i++;
2758  }
2759  }
2760  else if ((level=isHeaderline(data+i,size-i,TRUE))>0)
2761  {
2762  //printf("Found header at %d-%d\n",i,end);
2763  while (pi<size && data[pi]==' ') pi++;
2764  QCString header;
2765  convertStringFragment(header,data+pi,i-pi-1);
2766  id = extractTitleId(header, level);
2767  //printf("header='%s' is='%s'\n",qPrint(header),qPrint(id));
2768  if (!header.isEmpty())
2769  {
2770  if (!id.isEmpty())
2771  {
2772  m_out.addStr(level==1?"@section ":"@subsection ");
2773  m_out.addStr(id);
2774  m_out.addStr(" ");
2775  m_out.addStr(header);
2776  m_out.addStr("\n\n");
2777  }
2778  else
2779  {
2780  m_out.addStr(level==1?"<h1>":"<h2>");
2781  m_out.addStr(header);
2782  m_out.addStr(level==1?"\n</h1>\n":"\n</h2>\n");
2783  }
2784  }
2785  else
2786  {
2787  m_out.addStr("\n<hr>\n");
2788  }
2789  pi=-1;
2790  i=end;
2791  end=i+1;
2792  continue;
2793  }
2794  else if ((ref=isLinkRef(data+pi,size-pi,id,link,title)))
2795  {
2796  //printf("found link ref: id='%s' link='%s' title='%s'\n",
2797  // qPrint(id),qPrint(link),qPrint(title));
2798  m_linkRefs.insert({id.lower().str(),LinkRef(link,title)});
2799  i=ref+pi;
2800  pi=-1;
2801  end=i+1;
2802  }
2803  else if (isFencedCodeBlock(data+pi,size-pi,currentIndent,lang,blockStart,blockEnd,blockOffset))
2804  {
2805  //printf("Found FencedCodeBlock lang='%s' start=%d end=%d code={%s}\n",
2806  // qPrint(lang),blockStart,blockEnd,QCString(data+pi+blockStart).left(blockEnd-blockStart).data());
2807  writeFencedCodeBlock(data+pi,lang.data(),blockStart,blockEnd);
2808  i=pi+blockOffset;
2809  pi=-1;
2810  end=i+1;
2811  continue;
2812  }
2813  else if (isCodeBlock(data+i,i,end-i,blockIndent))
2814  {
2815  // skip previous line (it is empty anyway)
2816  i+=writeCodeBlock(data+i,size-i,blockIndent);
2817  pi=-1;
2818  end=i+1;
2819  continue;
2820  }
2821  else if (isTableBlock(data+pi,size-pi))
2822  {
2823  i=pi+writeTableBlock(data+pi,size-pi);
2824  pi=-1;
2825  end=i+1;
2826  continue;
2827  }
2828  else
2829  {
2830  writeOneLineHeaderOrRuler(data+pi,i-pi);
2831  }
2832  }
2833  pi=i;
2834  i=end;
2835  }
2836  //printf("last line %d size=%d\n",i,size);
2837  if (pi!=-1 && pi<size) // deal with the last line
2838  {
2839  if (isLinkRef(data+pi,size-pi,id,link,title))
2840  {
2841  //printf("found link ref: id='%s' link='%s' title='%s'\n",
2842  // qPrint(id),qPrint(link),qPrint(title));
2843  m_linkRefs.insert({id.lower().str(),LinkRef(link,title)});
2844  }
2845  else
2846  {
2847  writeOneLineHeaderOrRuler(data+pi,size-pi);
2848  }
2849  }
2850 
2851  m_out.addChar(0);
2852  return m_out.get();
2853 }

引用了 GrowBuf::addChar(), GrowBuf::addStr(), GrowBuf::clear(), codeBlockIndent, convertStringFragment(), QCString::data(), end(), extractTitleId(), findEndOfLine(), GrowBuf::get(), isBlockCommand(), isCodeBlock(), QCString::isEmpty(), isEmptyLine(), isEndOfList(), isFencedCodeBlock(), isHeaderline(), isLinkRef(), isListMarker(), isTableBlock(), QCString::length(), m_linkRefs, m_out, qstrncmp(), TRACE, TRUE, writeCodeBlock(), writeFencedCodeBlock(), writeOneLineHeaderOrRuler() , 以及 writeTableBlock().

被这些函数引用 process().

◆ processCodeSpan()

int Markdown::processCodeSpan ( const char *  data,
int  ,
int  size 
)
private

'‘’ parsing a code span (assuming codespan != 0)

在文件 markdown.cpp1234 行定义.

1235 {
1236  TRACE(data);
1237  int end, nb = 0, i, f_begin, f_end;
1238 
1239  /* counting the number of backticks in the delimiter */
1240  while (nb<size && data[nb]=='`')
1241  {
1242  nb++;
1243  }
1244 
1245  /* finding the next delimiter */
1246  i = 0;
1247  int nl=0;
1248  for (end=nb; end<size && i<nb && nl<2; end++)
1249  {
1250  if (data[end]=='`')
1251  {
1252  i++;
1253  }
1254  else if (data[end]=='\n')
1255  {
1256  i=0;
1257  nl++;
1258  }
1259  else if (data[end]=='\'' && nb==1 && (end==size-1 || (end<size-1 && !isIdChar(end+1))))
1260  { // look for quoted strings like 'some word', but skip strings like `it's cool`
1261  QCString textFragment;
1262  convertStringFragment(textFragment,data+nb,end-nb);
1263  m_out.addStr("&lsquo;");
1264  m_out.addStr(textFragment);
1265  m_out.addStr("&rsquo;");
1266  return end+1;
1267  }
1268  else
1269  {
1270  i=0;
1271  }
1272  }
1273  if (i < nb && end >= size)
1274  {
1275  TRACE_RESULT(0);
1276  return 0; // no matching delimiter
1277  }
1278  if (nl==2) // too many newlines inside the span
1279  {
1280  TRACE_RESULT(0);
1281  return 0;
1282  }
1283 
1284  // trimming outside whitespaces
1285  f_begin = nb;
1286  while (f_begin < end && data[f_begin]==' ')
1287  {
1288  f_begin++;
1289  }
1290  f_end = end - nb;
1291  while (f_end > nb && data[f_end-1]==' ')
1292  {
1293  f_end--;
1294  }
1295 
1296  //printf("found code span '%s'\n",qPrint(QCString(data+f_begin).left(f_end-f_begin)));
1297 
1298  /* real code span */
1299  if (f_begin < f_end)
1300  {
1301  QCString codeFragment;
1302  convertStringFragment(codeFragment,data+f_begin,f_end-f_begin);
1303  m_out.addStr("<tt>");
1304  //m_out.addStr(convertToHtml(codeFragment,TRUE));
1305  m_out.addStr(escapeSpecialChars(codeFragment));
1306  m_out.addStr("</tt>");
1307  }
1308  TRACE_RESULT(end);
1309  return end;
1310 }

引用了 GrowBuf::addStr(), convertStringFragment(), end(), escapeSpecialChars(), isIdChar, m_out, TRACE , 以及 TRACE_RESULT.

被这些函数引用 Markdown().

◆ processEmphasis()

int Markdown::processEmphasis ( const char *  data,
int  offset,
int  size 
)
private

在文件 markdown.cpp833 行定义.

834 {
835  TRACE(data);
836  if ((offset>0 && !isOpenEmphChar(-1)) || // invalid char before * or _
837  (size>1 && data[0]!=data[1] && !(isIdChar(1) || extraChar(1) || data[1]=='[')) || // invalid char after * or _
838  (size>2 && data[0]==data[1] && !(isIdChar(2) || extraChar(2) || data[2]=='['))) // invalid char after ** or __
839  {
840  TRACE_RESULT(0);
841  return 0;
842  }
843 
844  char c = data[0];
845  int ret;
846  if (size>2 && c!='~' && data[1]!=c) // _bla or *bla
847  {
848  // whitespace cannot follow an opening emphasis
849  if (data[1]==' ' || data[1]=='\n' ||
850  (ret = processEmphasis1(data+1, size-1, c)) == 0)
851  {
852  TRACE_RESULT(0);
853  return 0;
854  }
855  return ret+1;
856  }
857  if (size>3 && data[1]==c && data[2]!=c) // __bla or **bla
858  {
859  if (data[2]==' ' || data[2]=='\n' ||
860  (ret = processEmphasis2(data+2, size-2, c)) == 0)
861  {
862  TRACE_RESULT(0);
863  return 0;
864  }
865  return ret+2;
866  }
867  if (size>4 && c!='~' && data[1]==c && data[2]==c && data[3]!=c) // ___bla or ***bla
868  {
869  if (data[3]==' ' || data[3]=='\n' ||
870  (ret = processEmphasis3(data+3, size-3, c)) == 0)
871  {
872  TRACE_RESULT(0);
873  return 0;
874  }
875  TRACE_RESULT(ret+3);
876  return ret+3;
877  }
878  TRACE_RESULT(0);
879  return 0;
880 }

引用了 extraChar, isIdChar, isOpenEmphChar, processEmphasis1(), processEmphasis2(), processEmphasis3(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 Markdown().

◆ processEmphasis1()

int Markdown::processEmphasis1 ( const char *  data,
int  size,
char  c 
)
private

process single emphasis

在文件 markdown.cpp539 行定义.

540 {
541  TRACE(data);
542  int i = 0, len;
543 
544  /* skipping one symbol if coming from emph3 */
545  if (size>1 && data[0]==c && data[1]==c) { i=1; }
546 
547  while (i<size)
548  {
549  len = findEmphasisChar(data+i, size-i, c, 1);
550  if (len==0) { TRACE_RESULT(0); return 0; }
551  i+=len;
552  if (i>=size) { TRACE_RESULT(0); return 0; }
553 
554  if (i+1<size && data[i+1]==c)
555  {
556  i++;
557  continue;
558  }
559  if (data[i]==c && data[i-1]!=' ' && data[i-1]!='\n')
560  {
561  m_out.addStr("<em>");
562  processInline(data,i);
563  m_out.addStr("</em>");
564  TRACE_RESULT(i+1);
565  return i+1;
566  }
567  }
568  TRACE_RESULT(0);
569  return 0;
570 }

引用了 GrowBuf::addStr(), findEmphasisChar(), m_out, processInline(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 processEmphasis() , 以及 processEmphasis3().

◆ processEmphasis2()

int Markdown::processEmphasis2 ( const char *  data,
int  size,
char  c 
)
private

process double emphasis

在文件 markdown.cpp573 行定义.

574 {
575  TRACE(data);
576  int i = 0, len;
577 
578  while (i<size)
579  {
580  len = findEmphasisChar(data+i, size-i, c, 2);
581  if (len==0)
582  {
583  TRACE_RESULT(0);
584  return 0;
585  }
586  i += len;
587  if (i+1<size && data[i]==c && data[i+1]==c && i && data[i-1]!=' ' &&
588  data[i-1]!='\n'
589  )
590  {
591  if (c == '~') m_out.addStr("<strike>");
592  else m_out.addStr("<strong>");
593  processInline(data,i);
594  if (c == '~') m_out.addStr("</strike>");
595  else m_out.addStr("</strong>");
596  TRACE_RESULT(i+2);
597  return i + 2;
598  }
599  i++;
600  }
601  TRACE_RESULT(0);
602  return 0;
603 }

引用了 GrowBuf::addStr(), findEmphasisChar(), m_out, processInline(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 processEmphasis() , 以及 processEmphasis3().

◆ processEmphasis3()

int Markdown::processEmphasis3 ( const char *  data,
int  size,
char  c 
)
private

Parsing triple emphasis.

Finds the first closing tag, and delegates to the other emph

在文件 markdown.cpp608 行定义.

609 {
610  TRACE(data);
611  int i = 0, len;
612 
613  while (i<size)
614  {
615  len = findEmphasisChar(data+i, size-i, c, 3);
616  if (len==0)
617  {
618  TRACE_RESULT(0);
619  return 0;
620  }
621  i+=len;
622 
623  /* skip whitespace preceded symbols */
624  if (data[i]!=c || data[i-1]==' ' || data[i-1]=='\n')
625  {
626  continue;
627  }
628 
629  if (i+2<size && data[i+1]==c && data[i+2]==c)
630  {
631  m_out.addStr("<em><strong>");
632  processInline(data,i);
633  m_out.addStr("</strong></em>");
634  TRACE_RESULT(i+3);
635  return i+3;
636  }
637  else if (i+1<size && data[i+1]==c)
638  {
639  // double symbol found, handing over to emph1
640  len = processEmphasis1(data-2, size+2, c);
641  if (len==0)
642  {
643  TRACE_RESULT(0);
644  return 0;
645  }
646  else
647  {
648  TRACE_RESULT(len-2);
649  return len - 2;
650  }
651  }
652  else
653  {
654  // single symbol found, handing over to emph2
655  len = processEmphasis2(data-1, size+1, c);
656  if (len==0)
657  {
658  TRACE_RESULT(0);
659  return 0;
660  }
661  else
662  {
663  TRACE_RESULT(len-1);
664  return len - 1;
665  }
666  }
667  }
668  TRACE_RESULT(0);
669  return 0;
670 }

引用了 GrowBuf::addStr(), findEmphasisChar(), m_out, processEmphasis1(), processEmphasis2(), processInline(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 processEmphasis().

◆ processHtmlTag()

int Markdown::processHtmlTag ( const char *  data,
int  offset,
int  size 
)
private

在文件 markdown.cpp827 行定义.

828 {
829  TRACE(data);
830  return processHtmlTagWrite(data,offset,size,true);
831 }

引用了 processHtmlTagWrite() , 以及 TRACE.

被这些函数引用 Markdown().

◆ processHtmlTagWrite()

int Markdown::processHtmlTagWrite ( const char *  data,
int  offset,
int  size,
bool  doWrite 
)
private

Process a HTML tag.

Note that

..

are treated specially, in the sense that all code inside is written unprocessed

在文件 markdown.cpp737 行定义.

738 {
739  TRACE(data);
740  if (offset>0 && data[-1]=='\\') { TRACE_RESULT(0); return 0; } // escaped <
741 
742  // find the end of the html tag
743  int i=1;
744  int l=0;
745  // compute length of the tag name
746  while (i<size && isIdChar(i)) i++,l++;
747  QCString tagName;
748  convertStringFragment(tagName,data+1,i-1);
749  if (tagName.lower()=="pre") // found <pre> tag
750  {
751  bool insideStr=FALSE;
752  while (i<size-6)
753  {
754  char c=data[i];
755  if (!insideStr && c=='<') // potential start of html tag
756  {
757  if (data[i+1]=='/' &&
758  tolower(data[i+2])=='p' && tolower(data[i+3])=='r' &&
759  tolower(data[i+4])=='e' && tolower(data[i+5])=='>')
760  { // found </pre> tag, copy from start to end of tag
761  if (doWrite) m_out.addStr(data,i+6);
762  //printf("found <pre>..</pre> [%d..%d]\n",0,i+6);
763  TRACE_RESULT(i+6);
764  return i+6;
765  }
766  }
767  else if (insideStr && c=='"')
768  {
769  if (data[i-1]!='\\') insideStr=FALSE;
770  }
771  else if (c=='"')
772  {
773  insideStr=TRUE;
774  }
775  i++;
776  }
777  }
778  else // some other html tag
779  {
780  if (l>0 && i<size)
781  {
782  if (data[i]=='/' && i<size-1 && data[i+1]=='>') // <bla/>
783  {
784  //printf("Found htmlTag={%s}\n",qPrint(QCString(data).left(i+2)));
785  if (doWrite) m_out.addStr(data,i+2);
786  TRACE_RESULT(i+2);
787  return i+2;
788  }
789  else if (data[i]=='>') // <bla>
790  {
791  //printf("Found htmlTag={%s}\n",qPrint(QCString(data).left(i+1)));
792  if (doWrite) m_out.addStr(data,i+1);
793  TRACE_RESULT(i+1);
794  return i+1;
795  }
796  else if (data[i]==' ') // <bla attr=...
797  {
798  i++;
799  bool insideAttr=FALSE;
800  while (i<size)
801  {
802  if (!insideAttr && data[i]=='"')
803  {
804  insideAttr=TRUE;
805  }
806  else if (data[i]=='"' && data[i-1]!='\\')
807  {
808  insideAttr=FALSE;
809  }
810  else if (!insideAttr && data[i]=='>') // found end of tag
811  {
812  //printf("Found htmlTag={%s}\n",qPrint(QCString(data).left(i+1)));
813  if (doWrite) m_out.addStr(data,i+1);
814  TRACE_RESULT(i+1);
815  return i+1;
816  }
817  i++;
818  }
819  }
820  }
821  }
822  //printf("Not a valid html tag\n");
823  TRACE_RESULT(0);
824  return 0;
825 }

引用了 GrowBuf::addStr(), convertStringFragment(), FALSE, isIdChar, QCString::lower(), m_out, TRACE, TRACE_RESULT , 以及 TRUE.

被这些函数引用 findEndOfLine() , 以及 processHtmlTag().

◆ processInline()

void Markdown::processInline ( const char *  data,
int  size 
)
private

在文件 markdown.cpp1376 行定义.

1377 {
1378  TRACE(data);
1379  int i=0, end=0;
1380  Action_t action;
1381  while (i<size)
1382  {
1383  while (end<size && ((action=m_actions[(uchar)data[end]])==0)) end++;
1384  m_out.addStr(data+i,end-i);
1385  if (end>=size) break;
1386  i=end;
1387  end = action(data+i,i,size-i);
1388  if (end<=0)
1389  {
1390  end=i+1-end;
1391  }
1392  else
1393  {
1394  i+=end;
1395  end=i;
1396  }
1397  }
1398 }

引用了 GrowBuf::addStr(), end(), m_actions, m_out , 以及 TRACE.

被这些函数引用 process(), processEmphasis1(), processEmphasis2(), processEmphasis3() , 以及 processLink().

◆ processLink()

int Markdown::processLink ( const char *  data,
int  ,
int  size 
)
private

在文件 markdown.cpp909 行定义.

910 {
911  TRACE(data);
912  QCString content;
913  QCString link;
914  QCString title;
915  int contentStart,contentEnd,linkStart,titleStart,titleEnd;
916  bool isImageLink = FALSE;
917  bool isToc = FALSE;
918  int i=1;
919  if (data[0]=='!')
920  {
921  isImageLink = TRUE;
922  if (size<2 || data[1]!='[')
923  {
924  TRACE_RESULT(0);
925  return 0;
926  }
927  i++;
928  }
929  contentStart=i;
930  int level=1;
931  int nlTotal=0;
932  int nl=0;
933  // find the matching ]
934  while (i<size)
935  {
936  if (data[i-1]=='\\') // skip escaped characters
937  {
938  }
939  else if (data[i]=='[')
940  {
941  level++;
942  }
943  else if (data[i]==']')
944  {
945  level--;
946  if (level<=0) break;
947  }
948  else if (data[i]=='\n')
949  {
950  nl++;
951  if (nl>1) { TRACE_RESULT(0); return 0; } // only allow one newline in the content
952  }
953  i++;
954  }
955  nlTotal += nl;
956  nl = 0;
957  if (i>=size) return 0; // premature end of comment -> no link
958  contentEnd=i;
959  convertStringFragment(content,data+contentStart,contentEnd-contentStart);
960  //printf("processLink: content={%s}\n",qPrint(content));
961  if (!isImageLink && content.isEmpty()) { TRACE_RESULT(0); return 0; } // no link text
962  i++; // skip over ]
963 
964  // skip whitespace
965  while (i<size && data[i]==' ') i++;
966  if (i<size && data[i]=='\n') // one newline allowed here
967  {
968  i++;
969  nl++;
970  // skip more whitespace
971  while (i<size && data[i]==' ') i++;
972  }
973  nlTotal += nl;
974  nl = 0;
975 
976  bool explicitTitle=FALSE;
977  if (i<size && data[i]=='(') // inline link
978  {
979  i++;
980  while (i<size && data[i]==' ') i++;
981  bool uriFormat=false;
982  if (i<size && data[i]=='<') { i++; uriFormat=true; }
983  linkStart=i;
984  int braceCount=1;
985  while (i<size && data[i]!='\'' && data[i]!='"' && braceCount>0)
986  {
987  if (data[i]=='\n') // unexpected EOL
988  {
989  nl++;
990  if (nl>1) { TRACE_RESULT(0); return 0; }
991  }
992  else if (data[i]=='(')
993  {
994  braceCount++;
995  }
996  else if (data[i]==')')
997  {
998  braceCount--;
999  }
1000  if (braceCount>0)
1001  {
1002  i++;
1003  }
1004  }
1005  nlTotal += nl;
1006  nl = 0;
1007  if (i>=size || data[i]=='\n') { TRACE_RESULT(0); return 0; }
1008  convertStringFragment(link,data+linkStart,i-linkStart);
1009  link = link.stripWhiteSpace();
1010  //printf("processLink: link={%s}\n",qPrint(link));
1011  if (link.isEmpty()) { TRACE_RESULT(0); return 0; }
1012  if (uriFormat && link.at(link.length()-1)=='>') link=link.left(link.length()-1);
1013 
1014  // optional title
1015  if (data[i]=='\'' || data[i]=='"')
1016  {
1017  char c = data[i];
1018  i++;
1019  titleStart=i;
1020  nl=0;
1021  while (i<size && data[i]!=')')
1022  {
1023  if (data[i]=='\n')
1024  {
1025  if (nl>1) { TRACE_RESULT(0); return 0; }
1026  nl++;
1027  }
1028  i++;
1029  }
1030  if (i>=size)
1031  {
1032  TRACE_RESULT(0);
1033  return 0;
1034  }
1035  titleEnd = i-1;
1036  // search back for closing marker
1037  while (titleEnd>titleStart && data[titleEnd]==' ') titleEnd--;
1038  if (data[titleEnd]==c) // found it
1039  {
1040  convertStringFragment(title,data+titleStart,titleEnd-titleStart);
1041  //printf("processLink: title={%s}\n",qPrint(title));
1042  }
1043  else
1044  {
1045  TRACE_RESULT(0);
1046  return 0;
1047  }
1048  }
1049  i++;
1050  }
1051  else if (i<size && data[i]=='[') // reference link
1052  {
1053  i++;
1054  linkStart=i;
1055  nl=0;
1056  // find matching ]
1057  while (i<size && data[i]!=']')
1058  {
1059  if (data[i]=='\n')
1060  {
1061  nl++;
1062  if (nl>1) { TRACE_RESULT(0); return 0; }
1063  }
1064  i++;
1065  }
1066  if (i>=size) { TRACE_RESULT(0); return 0; }
1067  // extract link
1068  convertStringFragment(link,data+linkStart,i-linkStart);
1069  //printf("processLink: link={%s}\n",qPrint(link));
1070  link = link.stripWhiteSpace();
1071  if (link.isEmpty()) // shortcut link
1072  {
1073  link=content;
1074  }
1075  // lookup reference
1076  QCString link_lower = link.lower();
1077  auto lr_it=m_linkRefs.find(link_lower.str());
1078  if (lr_it!=m_linkRefs.end()) // found it
1079  {
1080  link = lr_it->second.link;
1081  title = lr_it->second.title;
1082  //printf("processLink: ref: link={%s} title={%s}\n",qPrint(link),qPrint(title));
1083  }
1084  else // reference not found!
1085  {
1086  //printf("processLink: ref {%s} do not exist\n",link.qPrint(lower()));
1087  TRACE_RESULT(0);
1088  return 0;
1089  }
1090  i++;
1091  }
1092  else if (i<size && data[i]!=':' && !content.isEmpty()) // minimal link ref notation [some id]
1093  {
1094  QCString content_lower = content.lower();
1095  auto lr_it = m_linkRefs.find(content_lower.str());
1096  //printf("processLink: minimal link {%s} lr=%p",qPrint(content),lr);
1097  if (lr_it!=m_linkRefs.end()) // found it
1098  {
1099  link = lr_it->second.link;
1100  title = lr_it->second.title;
1101  explicitTitle=TRUE;
1102  i=contentEnd;
1103  }
1104  else if (content=="TOC")
1105  {
1106  isToc=TRUE;
1107  i=contentEnd;
1108  }
1109  else
1110  {
1111  TRACE_RESULT(0);
1112  return 0;
1113  }
1114  i++;
1115  }
1116  else
1117  {
1118  TRACE_RESULT(0);
1119  return 0;
1120  }
1121  nlTotal += nl;
1122  nl = 0;
1123  if (isToc) // special case for [TOC]
1124  {
1125  int toc_level = Config_getInt(TOC_INCLUDE_HEADINGS);
1126  if (toc_level > 0 && toc_level <=5)
1127  {
1128  m_out.addStr("@tableofcontents{html:");
1129  m_out.addStr(QCString().setNum(toc_level));
1130  m_out.addStr("}");
1131  }
1132  }
1133  else if (isImageLink)
1134  {
1135  bool ambig;
1136  FileDef *fd=0;
1137  if (link.find("@ref ")!=-1 || link.find("\\ref ")!=-1 ||
1138  (fd=findFileDef(Doxygen::imageNameLinkedMap,link,ambig)))
1139  // assume doxygen symbol link or local image link
1140  {
1141  writeMarkdownImage("html", explicitTitle, title, content, link, fd);
1142  writeMarkdownImage("latex", explicitTitle, title, content, link, fd);
1143  writeMarkdownImage("rtf", explicitTitle, title, content, link, fd);
1144  writeMarkdownImage("docbook", explicitTitle, title, content, link, fd);
1145  }
1146  else
1147  {
1148  m_out.addStr("<img src=\"");
1149  m_out.addStr(link);
1150  m_out.addStr("\" alt=\"");
1151  m_out.addStr(content);
1152  m_out.addStr("\"");
1153  if (!title.isEmpty())
1154  {
1155  m_out.addStr(" title=\"");
1156  m_out.addStr(substitute(title.simplifyWhiteSpace(),"\"","&quot;"));
1157  m_out.addStr("\"");
1158  }
1159  m_out.addStr("/>");
1160  }
1161  }
1162  else
1163  {
1164  SrcLangExt lang = getLanguageFromFileName(link);
1165  int lp=-1;
1166  if ((lp=link.find("@ref "))!=-1 || (lp=link.find("\\ref "))!=-1 || (lang==SrcLangExt_Markdown && !isURL(link)))
1167  // assume doxygen symbol link
1168  {
1169  if (lp==-1) // link to markdown page
1170  {
1171  m_out.addStr("@ref ");
1172  if (!(Portable::isAbsolutePath(link) || isURL(link)))
1173  {
1174  FileInfo forg(link.str());
1175  if (forg.exists() && forg.isReadable())
1176  {
1177  link = forg.absFilePath();
1178  }
1179  else if (!(forg.exists() && forg.isReadable()))
1180  {
1181  FileInfo fi(m_fileName.str());
1182  QCString mdFile = m_fileName.left(m_fileName.length()-(uint)fi.fileName().length()) + link;
1183  FileInfo fmd(mdFile.str());
1184  if (fmd.exists() && fmd.isReadable())
1185  {
1186  link = fmd.absFilePath().data();
1187  }
1188  }
1189  }
1190  }
1191  m_out.addStr(link);
1192  m_out.addStr(" \"");
1193  if (explicitTitle && !title.isEmpty())
1194  {
1195  m_out.addStr(title);
1196  }
1197  else
1198  {
1199  m_out.addStr(content);
1200  }
1201  m_out.addStr("\"");
1202  }
1203  else if (link.find('/')!=-1 || link.find('.')!=-1 || link.find('#')!=-1)
1204  { // file/url link
1205  m_out.addStr("<a href=\"");
1206  m_out.addStr(link);
1207  m_out.addStr("\"");
1208  for (int ii = 0; ii < nlTotal; ii++) m_out.addStr("\n");
1209  if (!title.isEmpty())
1210  {
1211  m_out.addStr(" title=\"");
1212  m_out.addStr(substitute(title.simplifyWhiteSpace(),"\"","&quot;"));
1213  m_out.addStr("\"");
1214  }
1215  m_out.addStr(" ");
1217  m_out.addStr(">");
1218  content = content.simplifyWhiteSpace();
1219  processInline(content.data(),content.length());
1220  m_out.addStr("</a>");
1221  }
1222  else // avoid link to e.g. F[x](y)
1223  {
1224  //printf("no link for '%s'\n",qPrint(link));
1225  TRACE_RESULT(0);
1226  return 0;
1227  }
1228  }
1229  TRACE_RESULT(i);
1230  return i;
1231 }

引用了 FileInfo::absFilePath(), GrowBuf::addStr(), QCString::at(), Config_getInt, convertStringFragment(), QCString::data(), FileInfo::exists(), externalLinkTarget(), FALSE, FileInfo::fileName(), QCString::find(), findFileDef(), getLanguageFromFileName(), Doxygen::imageNameLinkedMap, Portable::isAbsolutePath(), QCString::isEmpty(), FileInfo::isReadable(), isURL(), QCString::left(), QCString::length(), QCString::lower(), m_fileName, m_linkRefs, m_out, processInline(), QCString::simplifyWhiteSpace(), SrcLangExt_Markdown, QCString::str(), QCString::stripWhiteSpace(), substitute(), TRACE, TRACE_RESULT, TRUE , 以及 writeMarkdownImage().

被这些函数引用 Markdown().

◆ processNmdash()

int Markdown::processNmdash ( const char *  data,
int  off,
int  size 
)
private

Process ndash and mdashes

在文件 markdown.cpp673 行定义.

674 {
675  TRACE(data);
676  // precondition: data[0]=='-'
677  int i=1;
678  int count=1;
679  if (i<size && data[i]=='-') // found --
680  {
681  count++,i++;
682  }
683  if (i<size && data[i]=='-') // found ---
684  {
685  count++,i++;
686  }
687  if (i<size && data[i]=='-') // found ----
688  {
689  count++;
690  }
691  if (count>=2 && off>=2 && qstrncmp(data-2,"<!",2)==0)
692  { TRACE_RESULT(1-count); return 1-count; } // start HTML comment
693  if (count==2 && (data[2]=='>'))
694  { TRACE_RESULT(0); return 0; } // end HTML comment
695  if (count==2 && (off<8 || qstrncmp(data-8,"operator",8)!=0)) // -- => ndash
696  {
697  m_out.addStr("&ndash;");
698  TRACE_RESULT(2);
699  return 2;
700  }
701  else if (count==3) // --- => ndash
702  {
703  m_out.addStr("&mdash;");
704  TRACE_RESULT(3);
705  return 3;
706  }
707  // not an ndash or mdash
708  TRACE_RESULT(0);
709  return 0;
710 }

引用了 GrowBuf::addStr(), m_out, qstrncmp(), TRACE , 以及 TRACE_RESULT.

被这些函数引用 Markdown().

◆ processQuotations()

QCString Markdown::processQuotations ( const QCString s,
int  refIndent 
)
private

在文件 markdown.cpp2533 行定义.

2534 {
2535  TRACE(s);
2536  m_out.clear();
2537  const char *data = s.data();
2538  int size = s.length();
2539  int i=0,end=0,pi=-1;
2540  int blockStart,blockEnd,blockOffset;
2541  bool newBlock = false;
2542  bool insideList = false;
2543  int currentIndent = refIndent;
2544  int listIndent = refIndent;
2545  QCString lang;
2546  while (i<size)
2547  {
2548  findEndOfLine(data,size,pi,i,end);
2549  // line is now found at [i..end)
2550 
2551  int lineIndent=0;
2552  while (lineIndent<end && data[i+lineIndent]==' ') lineIndent++;
2553  //printf("** lineIndent=%d line=(%s)\n",lineIndent,qPrint(QCString(data+i).left(end-i)));
2554 
2555  if (newBlock)
2556  {
2557  //printf("** end of block\n");
2558  if (insideList && lineIndent<currentIndent) // end of list
2559  {
2560  //printf("** end of list\n");
2561  currentIndent = refIndent;
2562  insideList = false;
2563  }
2564  newBlock = false;
2565  }
2566 
2567  if ((listIndent=isListMarker(data+i,end-i))) // see if we need to increase the indent level
2568  {
2569  if (listIndent<currentIndent+4)
2570  {
2571  //printf("** start of list\n");
2572  insideList = true;
2573  currentIndent = listIndent;
2574  }
2575  }
2576  else if (isEndOfList(data+i,end-i))
2577  {
2578  //printf("** end of list\n");
2579  insideList = false;
2580  currentIndent = listIndent;
2581  }
2582  else if (isEmptyLine(data+i,end-i))
2583  {
2584  //printf("** new block\n");
2585  newBlock = true;
2586  }
2587  //printf("currentIndent=%d listIndent=%d refIndent=%d\n",currentIndent,listIndent,refIndent);
2588 
2589  if (pi!=-1)
2590  {
2591  if (isFencedCodeBlock(data+pi,size-pi,currentIndent,lang,blockStart,blockEnd,blockOffset))
2592  {
2593  writeFencedCodeBlock(data+pi,lang.data(),blockStart,blockEnd);
2594  i=pi+blockOffset;
2595  pi=-1;
2596  end=i+1;
2597  continue;
2598  }
2599  else if (isBlockQuote(data+pi,i-pi,currentIndent))
2600  {
2601  i = pi+writeBlockQuote(data+pi,size-pi);
2602  pi=-1;
2603  end=i+1;
2604  continue;
2605  }
2606  else
2607  {
2608  //printf("quote m_out={%s}\n",QCString(data+pi).left(i-pi).data());
2609  m_out.addStr(data+pi,i-pi);
2610  }
2611  }
2612  pi=i;
2613  i=end;
2614  }
2615  if (pi!=-1 && pi<size) // deal with the last line
2616  {
2617  if (isBlockQuote(data+pi,size-pi,currentIndent))
2618  {
2619  writeBlockQuote(data+pi,size-pi);
2620  }
2621  else
2622  {
2623  m_out.addStr(data+pi,size-pi);
2624  }
2625  }
2626  m_out.addChar(0);
2627 
2628  //printf("Process quotations\n---- input ----\n%s\n---- output ----\n%s\n------------\n",
2629  // qPrint(s),m_out.get());
2630 
2631  return m_out.get();
2632 }

引用了 GrowBuf::addChar(), GrowBuf::addStr(), GrowBuf::clear(), QCString::data(), end(), findEndOfLine(), GrowBuf::get(), isBlockQuote(), isEmptyLine(), isEndOfList(), isFencedCodeBlock(), isListMarker(), QCString::length(), m_out, TRACE, writeBlockQuote() , 以及 writeFencedCodeBlock().

被这些函数引用 process().

◆ processQuoted()

int Markdown::processQuoted ( const char *  data,
int  ,
int  size 
)
private

Process quoted section "...", can contain one embedded newline

在文件 markdown.cpp713 行定义.

714 {
715  TRACE(data);
716  int i=1;
717  int nl=0;
718  while (i<size && data[i]!='"' && nl<2)
719  {
720  if (data[i]=='\n') nl++;
721  i++;
722  }
723  if (i<size && data[i]=='"' && nl<2)
724  {
725  m_out.addStr(data,i+1);
726  TRACE_RESULT(i+2);
727  return i+1;
728  }
729  // not a quoted section
730  TRACE_RESULT(0);
731  return 0;
732 }

引用了 GrowBuf::addStr(), m_out, TRACE , 以及 TRACE_RESULT.

被这些函数引用 Markdown().

◆ processSpecialCommand()

int Markdown::processSpecialCommand ( const char *  data,
int  offset,
int  size 
)
private

在文件 markdown.cpp1325 行定义.

1326 {
1327  TRACE(data);
1328  int i=1;
1329  QCString endBlockName = isBlockCommand(data,offset,size);
1330  if (!endBlockName.isEmpty())
1331  {
1332  TRACE_MORE("endBlockName=%s\n",qPrint(endBlockName));
1333  int l = endBlockName.length();
1334  while (i<size-l)
1335  {
1336  if ((data[i]=='\\' || data[i]=='@') && // command
1337  data[i-1]!='\\' && data[i-1]!='@') // not escaped
1338  {
1339  if (qstrncmp(&data[i+1],endBlockName.data(),l)==0)
1340  {
1341  //printf("found end at %d\n",i);
1342  addStrEscapeUtf8Nbsp(data,i+1+l);
1343  TRACE_RESULT(i+1+l);
1344  return i+1+l;
1345  }
1346  }
1347  i++;
1348  }
1349  }
1350  if (size>1 && data[0]=='\\')
1351  {
1352  char c=data[1];
1353  if (c=='[' || c==']' || c=='*' || c=='!' || c=='(' || c==')' || c=='`' || c=='_')
1354  {
1355  m_out.addChar(data[1]);
1356  TRACE_RESULT(2);
1357  return 2;
1358  }
1359  else if (c=='-' && size>3 && data[2]=='-' && data[3]=='-') // \---
1360  {
1361  m_out.addStr(&data[1],3);
1362  TRACE_RESULT(2);
1363  return 4;
1364  }
1365  else if (c=='-' && size>2 && data[2]=='-') // \--
1366  {
1367  m_out.addStr(&data[1],2);
1368  TRACE_RESULT(3);
1369  return 3;
1370  }
1371  }
1372  TRACE_RESULT(0);
1373  return 0;
1374 }

引用了 GrowBuf::addChar(), GrowBuf::addStr(), addStrEscapeUtf8Nbsp(), QCString::data(), isBlockCommand(), QCString::isEmpty(), QCString::length(), m_out, qPrint(), qstrncmp(), TRACE, TRACE_MORE , 以及 TRACE_RESULT.

被这些函数引用 Markdown().

◆ setIndentLevel()

void Markdown::setIndentLevel ( int  level)
inline

在文件 markdown.h38 行定义.

38 { m_indentLevel = level; }

引用了 m_indentLevel.

被这些函数引用 MarkdownOutlineParser::parseInput().

◆ writeBlockQuote()

int Markdown::writeBlockQuote ( const char *  data,
int  size 
)
private

在文件 markdown.cpp2323 行定义.

2324 {
2325  TRACE(data);
2326  int l;
2327  int i=0;
2328  int curLevel=0;
2329  int end=0;
2330  while (i<size)
2331  {
2332  // find end of this line
2333  end=i+1;
2334  while (end<=size && data[end-1]!='\n') end++;
2335  int j=i;
2336  int level=0;
2337  int indent=i;
2338  // compute the quoting level
2339  while (j<end && (data[j]==' ' || data[j]=='>'))
2340  {
2341  if (data[j]=='>') { level++; indent=j+1; }
2342  else if (j>0 && data[j-1]=='>') indent=j+1;
2343  j++;
2344  }
2345  if (j>0 && data[j-1]=='>' &&
2346  !(j==size || data[j]=='\n')) // disqualify last > if not followed by space
2347  {
2348  indent--;
2349  level--;
2350  j--;
2351  }
2352  if (!level && data[j-1]!='\n') level=curLevel; // lazy
2353  if (level>curLevel) // quote level increased => add start markers
2354  {
2355  for (l=curLevel;l<level-1;l++)
2356  {
2357  m_out.addStr("<blockquote>");
2358  }
2359  m_out.addStr("<blockquote>&zwj;"); // empty blockquotes are also shown
2360  }
2361  else if (level<curLevel) // quote level decreased => add end markers
2362  {
2363  for (l=level;l<curLevel;l++)
2364  {
2365  m_out.addStr("</blockquote>");
2366  }
2367  }
2368  curLevel=level;
2369  if (level==0) break; // end of quote block
2370  // copy line without quotation marks
2371  m_out.addStr(data+indent,end-indent);
2372  // proceed with next line
2373  i=end;
2374  }
2375  // end of comment within blockquote => add end markers
2376  for (l=0;l<curLevel;l++)
2377  {
2378  m_out.addStr("</blockquote>");
2379  }
2380  TRACE_RESULT(i);
2381  return i;
2382 }

引用了 GrowBuf::addStr(), end(), m_out, TRACE , 以及 TRACE_RESULT.

被这些函数引用 processQuotations().

◆ writeCodeBlock()

int Markdown::writeCodeBlock ( const char *  data,
int  size,
int  refIndent 
)
private

在文件 markdown.cpp2384 行定义.

2385 {
2386  TRACE(data);
2387  int i=0,end;
2388  //printf("writeCodeBlock: data={%s}\n",qPrint(QCString(data).left(size)));
2389  // no need for \ilinebr here as the previous line was empty and was skipped
2390  m_out.addStr("@verbatim\n");
2391  int emptyLines=0;
2392  while (i<size)
2393  {
2394  // find end of this line
2395  end=i+1;
2396  while (end<=size && data[end-1]!='\n') end++;
2397  int j=i;
2398  int indent=0;
2399  while (j<end && data[j]==' ') j++,indent++;
2400  //printf("j=%d end=%d indent=%d refIndent=%d tabSize=%d data={%s}\n",
2401  // j,end,indent,refIndent,Config_getInt(TAB_SIZE),qPrint(QCString(data+i).left(end-i-1)));
2402  if (j==end-1) // empty line
2403  {
2404  emptyLines++;
2405  i=end;
2406  }
2407  else if (indent>=refIndent+codeBlockIndent) // enough indent to continue the code block
2408  {
2409  while (emptyLines>0) // write skipped empty lines
2410  {
2411  // add empty line
2412  m_out.addStr("\n");
2413  emptyLines--;
2414  }
2415  // add code line minus the indent
2416  m_out.addStr(data+i+refIndent+codeBlockIndent,end-i-refIndent-codeBlockIndent);
2417  i=end;
2418  }
2419  else // end of code block
2420  {
2421  break;
2422  }
2423  }
2424  m_out.addStr("@endverbatim\\ilinebr ");
2425  while (emptyLines>0) // write skipped empty lines
2426  {
2427  // add empty line
2428  m_out.addStr("\n");
2429  emptyLines--;
2430  }
2431  //printf("i=%d\n",i);
2432  TRACE_RESULT(i);
2433  return i;
2434 }

引用了 GrowBuf::addStr(), codeBlockIndent, end(), m_out, TRACE , 以及 TRACE_RESULT.

被这些函数引用 processBlocks().

◆ writeFencedCodeBlock()

void Markdown::writeFencedCodeBlock ( const char *  data,
const char *  lng,
int  blockStart,
int  blockEnd 
)
private

在文件 markdown.cpp2512 行定义.

2514 {
2515  TRACE(data);
2516  QCString lang = lng;
2517  if (!lang.isEmpty() && lang.at(0)=='.') lang=lang.mid(1);
2518  while (*data==' ' || *data=='\t')
2519  {
2520  m_out.addChar(*data++);
2521  blockStart--;
2522  blockEnd--;
2523  }
2524  m_out.addStr("@code");
2525  if (!lang.isEmpty())
2526  {
2527  m_out.addStr("{"+lang+"}");
2528  }
2529  addStrEscapeUtf8Nbsp(data+blockStart,blockEnd-blockStart);
2530  m_out.addStr("@endcode");
2531 }

引用了 GrowBuf::addChar(), GrowBuf::addStr(), addStrEscapeUtf8Nbsp(), QCString::at(), QCString::isEmpty(), m_out, QCString::mid() , 以及 TRACE.

被这些函数引用 processBlocks() , 以及 processQuotations().

◆ writeMarkdownImage()

void Markdown::writeMarkdownImage ( const char *  fmt,
bool  explicitTitle,
const QCString title,
const QCString content,
const QCString link,
const FileDef fd 
)
private

在文件 markdown.cpp882 行定义.

885 {
886  m_out.addStr("@image{inline} ");
887  m_out.addStr(fmt);
888  m_out.addStr(" ");
889  m_out.addStr(link.mid(fd ? 0 : 5));
890  if (!explicitTitle && !content.isEmpty())
891  {
892  m_out.addStr(" \"");
893  m_out.addStr(escapeDoubleQuotes(content));
894  m_out.addStr("\"");
895  }
896  else if ((content.isEmpty() || explicitTitle) && !title.isEmpty())
897  {
898  m_out.addStr(" \"");
900  m_out.addStr("\"");
901  }
902  else
903  {
904  m_out.addStr(" ");// so the line break will not be part of the image name
905  }
906  m_out.addStr("\\ilinebr");
907 }

引用了 GrowBuf::addStr(), escapeDoubleQuotes(), QCString::isEmpty(), m_out , 以及 QCString::mid().

被这些函数引用 processLink().

◆ writeOneLineHeaderOrRuler()

void Markdown::writeOneLineHeaderOrRuler ( const char *  data,
int  size 
)
private

在文件 markdown.cpp2266 行定义.

2267 {
2268  TRACE(data);
2269  int level;
2270  QCString header;
2271  QCString id;
2272  if (isHRuler(data,size))
2273  {
2274  m_out.addStr("<hr>\n");
2275  }
2276  else if ((level=isAtxHeader(data,size,header,id,TRUE)))
2277  {
2278  QCString hTag;
2279  if (level<5 && !id.isEmpty())
2280  {
2281  switch(level)
2282  {
2283  case 1: m_out.addStr("@section ");
2284  break;
2285  case 2: m_out.addStr("@subsection ");
2286  break;
2287  case 3: m_out.addStr("@subsubsection ");
2288  break;
2289  default: m_out.addStr("@paragraph ");
2290  break;
2291  }
2292  m_out.addStr(id);
2293  m_out.addStr(" ");
2294  m_out.addStr(header);
2295  m_out.addStr("\n");
2296  }
2297  else
2298  {
2299  if (!id.isEmpty())
2300  {
2301  m_out.addStr("\\anchor "+id+"\\ilinebr ");
2302  }
2303  hTag.sprintf("h%d",level);
2304  m_out.addStr("<"+hTag+">");
2305  m_out.addStr(header);
2306  m_out.addStr("</"+hTag+">\n");
2307  }
2308  }
2309  else if (size>0) // nothing interesting -> just output the line
2310  {
2311  int tmpSize = size;
2312  if (data[size-1] == '\n') tmpSize--;
2313  m_out.addStr(data,tmpSize);
2314 
2315  if (hasLineBreak(data,size))
2316  {
2317  m_out.addStr("<br>");
2318  }
2319  if (tmpSize != size) m_out.addChar('\n');
2320  }
2321 }

引用了 GrowBuf::addChar(), GrowBuf::addStr(), hasLineBreak(), isAtxHeader(), isHRuler(), m_out, QCString::sprintf(), TRACE , 以及 TRUE.

被这些函数引用 processBlocks().

◆ writeTableBlock()

int Markdown::writeTableBlock ( const char *  data,
int  size 
)
private

在文件 markdown.cpp2046 行定义.

2047 {
2048  TRACE(data);
2049  int i=0,j,k;
2050  int columns,start,end,cc;
2051 
2052  i = findTableColumns(data,size,start,end,columns);
2053 
2054  int headerStart = start;
2055  int headerEnd = end;
2056 
2057  // read cell alignments
2058  int ret = findTableColumns(data+i,size-i,start,end,cc);
2059  k=0;
2060  std::vector<int> columnAlignment(columns);
2061 
2062  bool leftMarker=FALSE,rightMarker=FALSE;
2063  bool startFound=FALSE;
2064  j=start+i;
2065  while (j<=end+i)
2066  {
2067  if (!startFound)
2068  {
2069  if (data[j]==':') { leftMarker=TRUE; startFound=TRUE; }
2070  if (data[j]=='-') startFound=TRUE;
2071  //printf(" data[%d]=%c startFound=%d\n",j,data[j],startFound);
2072  }
2073  if (data[j]=='-') rightMarker=FALSE;
2074  else if (data[j]==':') rightMarker=TRUE;
2075  if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\')))
2076  {
2077  if (k<columns)
2078  {
2079  columnAlignment[k] = markersToAlignment(leftMarker,rightMarker);
2080  //printf("column[%d] alignment=%d\n",k,columnAlignment[k]);
2081  leftMarker=FALSE;
2082  rightMarker=FALSE;
2083  startFound=FALSE;
2084  }
2085  k++;
2086  }
2087  j++;
2088  }
2089  if (k<columns)
2090  {
2091  columnAlignment[k] = markersToAlignment(leftMarker,rightMarker);
2092  //printf("column[%d] alignment=%d\n",k,columnAlignment[k]);
2093  }
2094  // proceed to next line
2095  i+=ret;
2096 
2097  // Store the table cell information by row then column. This
2098  // allows us to handle row spanning.
2099  std::vector<std::vector<TableCell> > tableContents;
2100 
2101  int m=headerStart;
2102  std::vector<TableCell> headerContents(columns);
2103  for (k=0;k<columns;k++)
2104  {
2105  while (m<=headerEnd && (data[m]!='|' || (m>0 && data[m-1]=='\\')))
2106  {
2107  headerContents[k].cellText += data[m++];
2108  }
2109  m++;
2110  // do the column span test before stripping white space
2111  // || is spanning columns, | | is not
2112  headerContents[k].colSpan = headerContents[k].cellText.isEmpty();
2113  headerContents[k].cellText = headerContents[k].cellText.stripWhiteSpace();
2114  }
2115  tableContents.push_back(headerContents);
2116 
2117  // write table cells
2118  while (i<size)
2119  {
2120  ret = findTableColumns(data+i,size-i,start,end,cc);
2121  if (cc!=columns) break; // end of table
2122 
2123  j=start+i;
2124  k=0;
2125  std::vector<TableCell> rowContents(columns);
2126  while (j<=end+i)
2127  {
2128  if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\')))
2129  {
2130  // do the column span test before stripping white space
2131  // || is spanning columns, | | is not
2132  rowContents[k].colSpan = rowContents[k].cellText.isEmpty();
2133  rowContents[k].cellText = rowContents[k].cellText.stripWhiteSpace();
2134  k++;
2135  } // if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\')))
2136  else
2137  {
2138  rowContents[k].cellText += data[j];
2139  } // else { if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) }
2140  j++;
2141  } // while (j<=end+i)
2142  // do the column span test before stripping white space
2143  // || is spanning columns, | | is not
2144  rowContents[k].colSpan = rowContents[k].cellText.isEmpty();
2145  rowContents[k].cellText = rowContents[k].cellText.stripWhiteSpace();
2146  tableContents.push_back(rowContents);
2147 
2148  // proceed to next line
2149  i+=ret;
2150  }
2151 
2152  m_out.addStr("<table class=\"markdownTable\">");
2153  QCString cellTag("th"), cellClass("class=\"markdownTableHead");
2154  for (unsigned row = 0; row < tableContents.size(); row++)
2155  {
2156  if (row)
2157  {
2158  if (row % 2)
2159  {
2160  m_out.addStr("\n<tr class=\"markdownTableRowOdd\">");
2161  }
2162  else
2163  {
2164  m_out.addStr("\n<tr class=\"markdownTableRowEven\">");
2165  }
2166  }
2167  else
2168  {
2169  m_out.addStr("\n <tr class=\"markdownTableHead\">");
2170  }
2171  for (int c = 0; c < columns; c++)
2172  {
2173  // save the cell text for use after column span computation
2174  QCString cellText(tableContents[row][c].cellText);
2175 
2176  // Row span handling. Spanning rows will contain a caret ('^').
2177  // If the current cell contains just a caret, this is part of an
2178  // earlier row's span and the cell should not be added to the
2179  // output.
2180  if (tableContents[row][c].cellText == "^")
2181  {
2182  continue;
2183  }
2184  if (tableContents[row][c].colSpan)
2185  {
2186  int cr = c;
2187  while ( cr >= 0 && tableContents[row][cr].colSpan)
2188  {
2189  cr--;
2190  };
2191  if (cr >= 0 && tableContents[row][cr].cellText == "^") continue;
2192  }
2193  unsigned rowSpan = 1, spanRow = row+1;
2194  while ((spanRow < tableContents.size()) &&
2195  (tableContents[spanRow][c].cellText == "^"))
2196  {
2197  spanRow++;
2198  rowSpan++;
2199  }
2200 
2201  m_out.addStr(" <" + cellTag + " " + cellClass);
2202  // use appropriate alignment style
2203  switch (columnAlignment[c])
2204  {
2205  case AlignLeft: m_out.addStr("Left\""); break;
2206  case AlignRight: m_out.addStr("Right\""); break;
2207  case AlignCenter: m_out.addStr("Center\""); break;
2208  case AlignNone: m_out.addStr("None\""); break;
2209  }
2210 
2211  if (rowSpan > 1)
2212  {
2213  QCString spanStr;
2214  spanStr.setNum(rowSpan);
2215  m_out.addStr(" rowspan=\"" + spanStr + "\"");
2216  }
2217  // Column span handling, assumes that column spans will have
2218  // empty strings, which would indicate the sequence "||", used
2219  // to signify spanning columns.
2220  unsigned colSpan = 1;
2221  while ((c < columns-1) && tableContents[row][c+1].colSpan)
2222  {
2223  c++;
2224  colSpan++;
2225  }
2226  if (colSpan > 1)
2227  {
2228  QCString spanStr;
2229  spanStr.setNum(colSpan);
2230  m_out.addStr(" colspan=\"" + spanStr + "\"");
2231  }
2232  // need at least one space on either side of the cell text in
2233  // order for doxygen to do other formatting
2234  m_out.addStr("> " + cellText + " \\ilinebr </" + cellTag + ">");
2235  }
2236  cellTag = "td";
2237  cellClass = "class=\"markdownTableBody";
2238  m_out.addStr(" </tr>");
2239  }
2240  m_out.addStr("</table>\n");
2241 
2242  TRACE_RESULT(i);
2243  return i;
2244 }

引用了 GrowBuf::addStr(), AlignCenter, AlignLeft, AlignNone, AlignRight, end(), FALSE, findTableColumns(), m_out, markersToAlignment(), QCString::setNum(), TRACE, TRACE_RESULT , 以及 TRUE.

被这些函数引用 processBlocks().

类成员变量说明

◆ m_actions

Markdown::Action_t Markdown::m_actions[256]
private

在文件 markdown.h87 行定义.

被这些函数引用 Markdown() , 以及 processInline().

◆ m_fileName

QCString Markdown::m_fileName
private

在文件 markdown.h83 行定义.

被这些函数引用 processLink().

◆ m_indentLevel

int Markdown::m_indentLevel =0
private

在文件 markdown.h85 行定义.

被这些函数引用 isAtxHeader(), isHeaderline() , 以及 setIndentLevel().

◆ m_lineNr

int Markdown::m_lineNr = 0
private

在文件 markdown.h84 行定义.

被这些函数引用 Markdown().

◆ m_linkRefs

std::unordered_map<std::string,LinkRef> Markdown::m_linkRefs
private

在文件 markdown.h82 行定义.

被这些函数引用 processBlocks() , 以及 processLink().

◆ m_out


该类的文档由以下文件生成:
Markdown::writeOneLineHeaderOrRuler
void writeOneLineHeaderOrRuler(const char *data, int size)
Definition: markdown.cpp:2266
TRACE
#define TRACE(data)
Definition: markdown.cpp:162
AlignLeft
@ AlignLeft
Definition: markdown.cpp:226
findFileDef
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition: util.cpp:3222
isLinkRef
static int isLinkRef(const char *data, int size, QCString &refid, QCString &link, QCString &title)
returns end of the link ref if this is indeed a link reference.
Definition: markdown.cpp:1466
Markdown::isAtxHeader
int isAtxHeader(const char *data, int size, QCString &header, QCString &id, bool allowAdjustLevel)
Definition: markdown.cpp:1618
Doxygen::imageNameLinkedMap
static FileNameLinkedMap * imageNameLinkedMap
Definition: doxygen.h:89
Markdown::isHeaderline
int isHeaderline(const char *data, int size, bool allowAdjustLevel)
returns whether the line is a setext-style hdr underline
Definition: markdown.cpp:1401
Markdown::writeTableBlock
int writeTableBlock(const char *data, int size)
Definition: markdown.cpp:2046
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
GrowBuf::get
char * get()
Definition: growbuf.h:94
Markdown::processHtmlTagWrite
int processHtmlTagWrite(const char *data, int offset, int size, bool doWrite)
Process a HTML tag.
Definition: markdown.cpp:737
Markdown::processEmphasis1
int processEmphasis1(const char *data, int size, char c)
process single emphasis
Definition: markdown.cpp:539
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
Markdown::findEndOfLine
void findEndOfLine(const char *data, int size, int &pi, int &i, int &end)
Definition: markdown.cpp:2438
Markdown::processBlocks
QCString processBlocks(const QCString &s, int indent)
Definition: markdown.cpp:2634
QCString::size
uint size() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:150
SrcLangExt
SrcLangExt
Language as given by extension
Definition: types.h:41
g_doxy_nsbp
const char * g_doxy_nsbp
Definition: markdown.cpp:232
QCString::str
std::string str() const
Definition: qcstring.h:442
Markdown::Action_t
std::function< int(const char *, int, int)> Action_t
Definition: markdown.h:80
isListMarker
static int isListMarker(const char *data, int size)
Definition: markdown.cpp:1773
QCString::at
char & at(size_t i)
Returns a reference to the character at index i.
Definition: qcstring.h:477
Markdown::isBlockCommand
QCString isBlockCommand(const char *data, int offset, int size)
Definition: markdown.cpp:364
GrowBuf::addStr
void addStr(const QCString &s)
Definition: growbuf.h:57
QCString::find
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:38
isURL
bool isURL(const QCString &url)
Checks whether the given url starts with a supported protocol
Definition: util.cpp:6561
qstrncmp
int qstrncmp(const char *str1, const char *str2, size_t len)
Definition: qcstring.h:91
hasLineBreak
static bool hasLineBreak(const char *data, int size)
Definition: markdown.cpp:2247
GrowBuf::addChar
void addChar(char c)
Definition: growbuf.h:54
end
DirIterator end(const DirIterator &) noexcept
Definition: dir.cpp:128
Markdown::processEmphasis
int processEmphasis(const char *data, int offset, int size)
Definition: markdown.cpp:833
Markdown::m_lineNr
int m_lineNr
Definition: markdown.h:84
uint
unsigned uint
Definition: qcstring.h:40
Portable::strnstr
const char * strnstr(const char *haystack, const char *needle, size_t haystack_len)
Definition: portable.cpp:581
AlignNone
@ AlignNone
Definition: markdown.cpp:226
QCString::stripWhiteSpace
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition: qcstring.h:243
Config_getInt
#define Config_getInt(name)
Definition: config.h:34
uchar
unsigned char uchar
Definition: qcstring.h:38
escapeDoubleQuotes
static QCString escapeDoubleQuotes(const QCString &s)
Definition: markdown.cpp:249
QCString::left
QCString left(size_t len) const
Definition: qcstring.h:212
Markdown::m_linkRefs
std::unordered_map< std::string, LinkRef > m_linkRefs
Definition: markdown.h:82
Markdown::processNmdash
int processNmdash(const char *data, int off, int size)
Process ndash and mdashes
Definition: markdown.cpp:673
codeBlockIndent
const int codeBlockIndent
Definition: markdown.cpp:233
AlignCenter
@ AlignCenter
Definition: markdown.cpp:226
Markdown::processQuotations
QCString processQuotations(const QCString &s, int refIndent)
Definition: markdown.cpp:2533
Debug::print
static void print(DebugMask mask, int prio, const char *fmt,...)
Definition: debug.cpp:57
Markdown::processCodeSpan
int processCodeSpan(const char *data, int, int size)
'‘’ parsing a code span (assuming codespan != 0)
Definition: markdown.cpp:1234
QCString::simplifyWhiteSpace
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition: qcstring.cpp:180
escapeSpecialChars
static QCString escapeSpecialChars(const QCString &s)
Definition: markdown.cpp:270
Markdown::writeFencedCodeBlock
void writeFencedCodeBlock(const char *data, const char *lng, int blockStart, int blockEnd)
Definition: markdown.cpp:2512
markersToAlignment
static Alignment markersToAlignment(bool leftMarker, bool rightMarker)
helper function to convert presence of left and/or right alignment markers to a alignment value
Definition: markdown.cpp:323
isNewline
int isNewline(const char *data)
Definition: markdown.cpp:239
findTableColumns
int findTableColumns(const char *data, int size, int &start, int &end, int &columns)
Finds the location of the table's contains in the string data.
Definition: markdown.cpp:1958
Markdown::processSpecialCommand
int processSpecialCommand(const char *data, int offset, int size)
Definition: markdown.cpp:1325
isFencedCodeBlock
static bool isFencedCodeBlock(const char *data, int size, int refIndent, QCString &lang, int &start, int &end, int &offset)
Definition: markdown.cpp:1811
QCString::lower
QCString lower() const
Definition: qcstring.h:232
Markdown::detab
QCString detab(const QCString &s, int &refIndent)
Definition: markdown.cpp:2932
Markdown::processInline
void processInline(const char *data, int size)
Definition: markdown.cpp:1376
extraChar
#define extraChar(i)
Definition: markdown.cpp:180
Markdown::writeBlockQuote
int writeBlockQuote(const char *data, int size)
Definition: markdown.cpp:2323
isEmptyLine
static bool isEmptyLine(const char *data, int size)
Definition: markdown.cpp:1682
GrowBuf::reserve
void reserve(uint size)
Definition: growbuf.h:52
Markdown::findEmphasisChar
int findEmphasisChar(const char *data, int size, char c, int c_size)
looks for the next emph char, skipping other constructs, and stopping when either it is found,...
Definition: markdown.cpp:431
getLanguageFromFileName
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition: util.cpp:5574
TRUE
#define TRUE
Definition: qcstring.h:36
Markdown::m_fileName
QCString m_fileName
Definition: markdown.h:83
isEndOfList
static bool isEndOfList(const char *data, int size)
Definition: markdown.cpp:1784
Markdown::writeCodeBlock
int writeCodeBlock(const char *data, int size, int refIndent)
Definition: markdown.cpp:2384
Markdown::processQuoted
int processQuoted(const char *data, int, int size)
Process quoted section "...", can contain one embedded newline
Definition: markdown.cpp:713
Markdown::processEmphasis2
int processEmphasis2(const char *data, int size, char c)
process double emphasis
Definition: markdown.cpp:573
externalLinkTarget
QCString externalLinkTarget(const bool parent)
Definition: util.cpp:6323
QCString::setNum
QCString & setNum(short n)
Definition: qcstring.h:372
getUTF8CharNumBytes
uint8_t getUTF8CharNumBytes(char c)
Returns the number of bytes making up a single UTF8 character given the first byte in the sequence.
Definition: utf8.cpp:23
Markdown::m_actions
Markdown::Action_t m_actions[256]
Definition: markdown.h:87
g_utf8_nbsp
const uchar g_utf8_nbsp[3]
Definition: markdown.cpp:231
isUTF8NonBreakableSpace
int isUTF8NonBreakableSpace(const char *input)
Check if the first character pointed at by input is a non-breakable whitespace character.
Definition: utf8.cpp:228
isBlockQuote
bool isBlockQuote(const char *data, int size, int indent)
returns TRUE if this line starts a block quote
Definition: markdown.cpp:1437
QCString::mid
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition: qcstring.h:224
substitute
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition: qcstring.cpp:465
Markdown::addStrEscapeUtf8Nbsp
void addStrEscapeUtf8Nbsp(const char *s, int len)
Definition: markdown.cpp:1312
Debug::Markdown
@ Markdown
Definition: debug.h:37
TRACE_MORE
#define TRACE_MORE(...)
Definition: markdown.cpp:163
isOpenEmphChar
#define isOpenEmphChar(i)
Definition: markdown.cpp:186
FileInfo
Minimal replacement for QFileInfo.
Definition: fileinfo.h:22
Markdown::m_out
GrowBuf m_out
Definition: markdown.h:86
Markdown::m_indentLevel
int m_indentLevel
Definition: markdown.h:85
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
isTableBlock
static bool isTableBlock(const char *data, int size)
Returns TRUE iff data points to the start of a table block
Definition: markdown.cpp:2003
extractTitleId
static QCString extractTitleId(QCString &title, int level)
Definition: markdown.cpp:1589
SrcLangExt_Markdown
@ SrcLangExt_Markdown
Definition: types.h:57
QCString::data
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string
Definition: qcstring.h:153
isIdChar
#define isIdChar(i)
Definition: markdown.cpp:174
FileDef
A model of a file symbol.
Definition: filedef.h:73
isHRuler
static bool isHRuler(const char *data, int size)
Definition: markdown.cpp:1559
Markdown::processLink
int processLink(const char *data, int, int size)
Definition: markdown.cpp:909
Portable::isAbsolutePath
bool isAbsolutePath(const QCString &fileName)
Definition: portable.cpp:496
Markdown::writeMarkdownImage
void writeMarkdownImage(const char *fmt, bool explicitTitle, const QCString &title, const QCString &content, const QCString &link, const FileDef *fd)
Definition: markdown.cpp:882
GrowBuf::clear
void clear()
Definition: growbuf.h:53
convertStringFragment
static void convertStringFragment(QCString &result, const char *data, int size)
Definition: markdown.cpp:312
ignoreCloseEmphChar
#define ignoreCloseEmphChar(i)
Definition: markdown.cpp:193
isCodeBlock
static bool isCodeBlock(const char *data, int offset, int size, int &indent)
Definition: markdown.cpp:1868
AlignRight
@ AlignRight
Definition: markdown.cpp:226
QCString::sprintf
QCString & sprintf(const char *format,...)
Definition: qcstring.cpp:24
Markdown::processHtmlTag
int processHtmlTag(const char *data, int offset, int size)
Definition: markdown.cpp:827
Markdown::processEmphasis3
int processEmphasis3(const char *data, int size, char c)
Parsing triple emphasis.
Definition: markdown.cpp:608
FALSE
#define FALSE
Definition: qcstring.h:33
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108
TRACE_RESULT
#define TRACE_RESULT(v)
Definition: markdown.cpp:164