Doxygen
Loading...
Searching...
No Matches
markdown.cpp File Reference
#include <stdio.h>
#include <unordered_map>
#include <functional>
#include <atomic>
#include <array>
#include <string_view>
#include "markdown.h"
#include "debug.h"
#include "util.h"
#include "doxygen.h"
#include "commentscan.h"
#include "entry.h"
#include "config.h"
#include "message.h"
#include "portable.h"
#include "regex.h"
#include "fileinfo.h"
#include "trace.h"
#include "anchor.h"
#include "stringutil.h"
+ Include dependency graph for markdown.cpp:

Go to the source code of this file.

Classes

struct  TableCell
 
struct  Markdown::Private
 
struct  Markdown::Private::LinkRef
 
struct  MarkdownOutlineParser::Private
 

Macros

#define AUTO_TRACE(...)
 
#define AUTO_TRACE_ADD(...)
 
#define AUTO_TRACE_EXIT(...)
 
#define isIdChar(c)
 
#define extraChar(c)
 
#define isOpenEmphChar(c)
 
#define ignoreCloseEmphChar(c, cn)
 
#define isLiTag(i)
 

Enumerations

enum class  ExplicitPageResult { explicitPage , explicitMainPage , explicitDirPage , notExplicit }
 
enum  Alignment { AlignNone , AlignLeft , AlignCenter , AlignRight }
 

Functions

size_t isNewline (std::string_view data)
 
static QCString escapeDoubleQuotes (const QCString &s)
 
static QCString escapeSpecialChars (const QCString &s)
 
static Alignment markersToAlignment (bool leftMarker, bool rightMarker)
 helper function to convert presence of left and/or right alignment markers to a alignment value
 
static QCString getFilteredImageAttributes (std::string_view fmt, const QCString &attrs)
 parse the image attributes and return attributes for given format
 
static bool isBlockQuote (std::string_view data, size_t indent)
 returns true if this line starts a block quote
 
static size_t isLinkRef (std::string_view data, QCString &refid, QCString &link, QCString &title)
 returns end of the link ref if this is indeed a link reference.
 
static bool isHRuler (std::string_view data)
 
static bool isEmptyLine (std::string_view data)
 
static size_t computeIndentExcludingListMarkers (std::string_view data)
 
static size_t isListMarker (std::string_view data)
 
static bool isEndOfList (std::string_view data)
 
static bool isFencedCodeBlock (std::string_view data, size_t refIndent, QCString &lang, size_t &start, size_t &end, size_t &offset)
 
static bool isCodeBlock (std::string_view data, size_t offset, size_t &indent)
 
static size_t findTableColumns (std::string_view data, size_t &start, size_t &end, size_t &columns)
 Finds the location of the table's contains in the string data.
 
static bool isTableBlock (std::string_view data)
 Returns TRUE iff data points to the start of a table block.
 
static bool hasLineBreak (std::string_view data)
 
bool skipOverFileAndLineCommands (std::string_view data, size_t indent, size_t &offset, std::string &location)
 
static ExplicitPageResult isExplicitPage (const QCString &docs)
 
QCString markdownFileNameToId (const QCString &fileName)
 processes string s and converts markdown into doxygen/html commands.
 

Variables

const char * g_utf8_nbsp = "\xc2\xa0"
 
const char * g_doxy_nbsp = "&_doxy_nbsp;"
 
const size_t codeBlockIndent = 4
 
static const std::unordered_map< std::string, std::string > g_quotationHeaderMap
 

Macro Definition Documentation

◆ AUTO_TRACE

#define AUTO_TRACE ( ...)
Value:
(void)0

Definition at line 61 of file markdown.cpp.

Referenced by escapeDoubleQuotes(), escapeSpecialChars(), and getFilteredImageAttributes().

◆ AUTO_TRACE_ADD

#define AUTO_TRACE_ADD ( ...)
Value:
(void)0

Definition at line 62 of file markdown.cpp.

◆ AUTO_TRACE_EXIT

#define AUTO_TRACE_EXIT ( ...)
Value:
(void)0

Definition at line 63 of file markdown.cpp.

Referenced by escapeDoubleQuotes(), escapeSpecialChars(), and getFilteredImageAttributes().

◆ extraChar

#define extraChar ( c)
Value:
(c=='-' || c=='+' || c=='!' || \
c=='?' || c=='$' || c=='@' || \
c=='&' || c=='*' || c=='%' || \
c=='[' || c=='(' || c=='.' || \
c=='>' || c==':' || c==',' || \
c==';' || c=='\'' || c=='"' || c=='`')

Definition at line 84 of file markdown.cpp.

84#define extraChar(c) \
85 (c=='-' || c=='+' || c=='!' || \
86 c=='?' || c=='$' || c=='@' || \
87 c=='&' || c=='*' || c=='%' || \
88 c=='[' || c=='(' || c=='.' || \
89 c=='>' || c==':' || c==',' || \
90 c==';' || c=='\'' || c=='"' || c=='`')

Referenced by Markdown::Private::processEmphasis().

◆ ignoreCloseEmphChar

#define ignoreCloseEmphChar ( c,
cn )
Value:
(c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || \
c=='\\' || \
c=='@')

Definition at line 100 of file markdown.cpp.

100#define ignoreCloseEmphChar(c,cn) \
101 (c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || \
102 c=='\\' || \
103 c=='@')

Referenced by Markdown::Private::findEmphasisChar().

◆ isIdChar

#define isIdChar ( c)
Value:
((c>='a' && c<='z') || \
(c>='A' && c<='Z') || \
(c>='0' && c<='9') || \
(static_cast<unsigned char>(c)>=0x80))

Definition at line 77 of file markdown.cpp.

77#define isIdChar(c) \
78 ((c>='a' && c<='z') || \
79 (c>='A' && c<='Z') || \
80 (c>='0' && c<='9') || \
81 (static_cast<unsigned char>(c)>=0x80)) // unicode characters

Referenced by Markdown::Private::findEmphasisChar(), reg::Ex::Private::matchAt(), Markdown::Private::processCodeSpan(), Markdown::Private::processEmphasis(), and Markdown::Private::processHtmlTagWrite().

◆ isLiTag

#define isLiTag ( i)
Value:
(data[(i)]=='<' && \
(data[(i)+1]=='l' || data[(i)+1]=='L') && \
(data[(i)+2]=='i' || data[(i)+2]=='I') && \
(data[(i)+3]=='>'))

Definition at line 2072 of file markdown.cpp.

2072#define isLiTag(i) \
2073 (data[(i)]=='<' && \
2074 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2075 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2076 (data[(i)+3]=='>'))

Referenced by computeIndentExcludingListMarkers().

◆ isOpenEmphChar

#define isOpenEmphChar ( c)
Value:
(c=='\n' || c==' ' || c=='\'' || c=='<' || \
c=='>' || c=='{' || c=='(' || c=='[' || \
c==',' || c==':' || c==';')

Definition at line 93 of file markdown.cpp.

93#define isOpenEmphChar(c) \
94 (c=='\n' || c==' ' || c=='\'' || c=='<' || \
95 c=='>' || c=='{' || c=='(' || c=='[' || \
96 c==',' || c==':' || c==';')

Referenced by Markdown::Private::processEmphasis().

Enumeration Type Documentation

◆ Alignment

enum Alignment
Enumerator
AlignNone 
AlignLeft 
AlignCenter 
AlignRight 

Definition at line 194 of file markdown.cpp.

@ AlignLeft
Definition markdown.cpp:194
@ AlignNone
Definition markdown.cpp:194
@ AlignRight
Definition markdown.cpp:194
@ AlignCenter
Definition markdown.cpp:194

◆ ExplicitPageResult

enum class ExplicitPageResult
strong
Enumerator
explicitPage 

docs start with a page command

explicitMainPage 

docs start with a mainpage command

explicitDirPage 

docs start with a dir command

notExplicit 

docs doesn't start with either page or mainpage

Definition at line 66 of file markdown.cpp.

67{
68 explicitPage, /**< docs start with a page command */
69 explicitMainPage, /**< docs start with a mainpage command */
70 explicitDirPage, /**< docs start with a dir command */
71 notExplicit /**< docs doesn't start with either page or mainpage */
72};
@ explicitDirPage
docs start with a dir command
Definition markdown.cpp:70
@ explicitMainPage
docs start with a mainpage command
Definition markdown.cpp:69
@ explicitPage
docs start with a page command
Definition markdown.cpp:68
@ notExplicit
docs doesn't start with either page or mainpage
Definition markdown.cpp:71

Function Documentation

◆ computeIndentExcludingListMarkers()

static size_t computeIndentExcludingListMarkers ( std::string_view data)
static

Definition at line 2080 of file markdown.cpp.

2081{
2082 AUTO_TRACE("data='{}'",Trace::trunc(data));
2083 size_t i=0;
2084 const size_t size=data.size();
2085 size_t indent=0;
2086 bool isDigit=FALSE;
2087 bool isLi=FALSE;
2088 bool listMarkerSkipped=FALSE;
2089 while (i<size &&
2090 (data[i]==' ' || // space
2091 (!listMarkerSkipped && // first list marker
2092 (data[i]=='+' || data[i]=='-' || data[i]=='*' || // unordered list char
2093 (data[i]=='#' && i>0 && data[i-1]=='-') || // -# item
2094 (isDigit=(data[i]>='1' && data[i]<='9')) || // ordered list marker?
2095 (isLi=(size>=3 && i<size-3 && isLiTag(i))) // <li> tag
2096 )
2097 )
2098 )
2099 )
2100 {
2101 if (isDigit) // skip over ordered list marker '10. '
2102 {
2103 size_t j=i+1;
2104 while (j<size && ((data[j]>='0' && data[j]<='9') || data[j]=='.'))
2105 {
2106 if (data[j]=='.') // should be end of the list marker
2107 {
2108 if (j<size-1 && data[j+1]==' ') // valid list marker
2109 {
2110 listMarkerSkipped=TRUE;
2111 indent+=j+1-i;
2112 i=j+1;
2113 break;
2114 }
2115 else // not a list marker
2116 {
2117 break;
2118 }
2119 }
2120 j++;
2121 }
2122 }
2123 else if (isLi)
2124 {
2125 i+=3; // skip over <li>
2126 indent+=3;
2127 listMarkerSkipped=TRUE;
2128 }
2129 else if (data[i]=='-' && size>=2 && i<size-2 && data[i+1]=='#' && data[i+2]==' ')
2130 { // case "-# "
2131 listMarkerSkipped=TRUE; // only a single list marker is accepted
2132 i++; // skip over #
2133 indent++;
2134 }
2135 else if (data[i]!=' ' && i<size-1 && data[i+1]==' ')
2136 { // case "- " or "+ " or "* "
2137 listMarkerSkipped=TRUE; // only a single list marker is accepted
2138 }
2139 if (data[i]!=' ' && !listMarkerSkipped)
2140 { // end of indent
2141 break;
2142 }
2143 indent++,i++;
2144 }
2145 AUTO_TRACE_EXIT("result={}",indent);
2146 return indent;
2147}
#define AUTO_TRACE(...)
Definition markdown.cpp:61
#define AUTO_TRACE_EXIT(...)
Definition markdown.cpp:63
#define isLiTag(i)
QCString trunc(const QCString &s, size_t numChars=15)
Definition trace.h:56
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34

References AUTO_TRACE, AUTO_TRACE_EXIT, FALSE, isLiTag, TRUE, and Trace::trunc().

Referenced by isCodeBlock(), and isListMarker().

◆ escapeDoubleQuotes()

static QCString escapeDoubleQuotes ( const QCString & s)
static

Definition at line 217 of file markdown.cpp.

218{
219 AUTO_TRACE("s={}",Trace::trunc(s));
220 if (s.isEmpty()) return s;
221 QCString result;
222 const char *p=s.data();
223 char c=0, pc='\0';
224 while ((c=*p++))
225 {
226 if (c=='"' && pc!='\\') result+='\\';
227 result+=c;
228 pc=c;
229 }
230 AUTO_TRACE_EXIT("result={}",result);
231 return result;
232}
This is an alternative implementation of QCString.
Definition qcstring.h:101
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
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:159

References AUTO_TRACE, AUTO_TRACE_EXIT, QCString::data(), QCString::isEmpty(), and Trace::trunc().

Referenced by Markdown::Private::writeMarkdownImage().

◆ escapeSpecialChars()

static QCString escapeSpecialChars ( const QCString & s)
static

Definition at line 235 of file markdown.cpp.

236{
237 AUTO_TRACE("s={}",Trace::trunc(s));
238 if (s.isEmpty()) return s;
239 bool insideQuote=FALSE;
240 QCString result;
241 const char *p=s.data();
242 char c=0, pc='\0';
243 while ((c=*p++))
244 {
245 switch (c)
246 {
247 case '"':
248 if (pc!='\\') { insideQuote=!insideQuote; }
249 result+=c;
250 break;
251 case '<':
252 // fall through
253 case '>':
254 if (!insideQuote)
255 {
256 result+='\\';
257 result+=c;
258 if ((p[0]==':') && (p[1]==':'))
259 {
260 result+='\\';
261 result+=':';
262 p++;
263 }
264 }
265 else
266 {
267 result+=c;
268 }
269 break;
270 case '\\': if (!insideQuote) { result+='\\'; } result+='\\'; break;
271 case '@': if (!insideQuote) { result+='\\'; } result+='@'; break;
272 // commented out next line due to regression when using % to suppress a link
273 //case '%': if (!insideQuote) { result+='\\'; } result+='%'; break;
274 case '#': if (!insideQuote) { result+='\\'; } result+='#'; break;
275 case '$': if (!insideQuote) { result+='\\'; } result+='$'; break;
276 case '&': if (!insideQuote) { result+='\\'; } result+='&'; break;
277 default:
278 result+=c; break;
279 }
280 pc=c;
281 }
282 AUTO_TRACE_EXIT("result={}",result);
283 return result;
284}

References AUTO_TRACE, AUTO_TRACE_EXIT, QCString::data(), FALSE, QCString::isEmpty(), and Trace::trunc().

Referenced by Markdown::Private::processCodeSpan().

◆ findTableColumns()

static size_t findTableColumns ( std::string_view data,
size_t & start,
size_t & end,
size_t & columns )
static

Finds the location of the table's contains in the string data.

Only one line will be inspected.

Parameters
[in]datapointer to the string buffer.
[out]startoffset of the first character of the table content
[out]endoffset of the last character of the table content
[out]columnsnumber of table columns found
Returns
The offset until the next line in the buffer.

Definition at line 2365 of file markdown.cpp.

2366{
2367 AUTO_TRACE("data='{}'",Trace::trunc(data));
2368 const size_t size = data.size();
2369 size_t i=0,n=0;
2370 // find start character of the table line
2371 while (i<size && data[i]==' ') i++;
2372 if (i<size && data[i]=='|' && data[i]!='\n') i++,n++; // leading | does not count
2373 start = i;
2374
2375 // find end character of the table line
2376 size_t j = 0;
2377 while (i<size && (j = isNewline(data.substr(i)))==0) i++;
2378 size_t eol=i+j;
2379
2380 if (j>0 && i>0) i--; // move i to point before newline
2381 while (i>0 && data[i]==' ') i--;
2382 if (i>0 && data[i-1]!='\\' && data[i]=='|') i--,n++; // trailing or escaped | does not count
2383 end = i;
2384
2385 // count columns between start and end
2386 columns=0;
2387 if (end>start)
2388 {
2389 i=start;
2390 while (i<=end) // look for more column markers
2391 {
2392 if (data[i]=='|' && (i==0 || data[i-1]!='\\')) columns++;
2393 if (columns==1) columns++; // first | make a non-table into a two column table
2394 i++;
2395 }
2396 }
2397 if (n==2 && columns==0) // table row has | ... |
2398 {
2399 columns++;
2400 }
2401 AUTO_TRACE_EXIT("eol={} start={} end={} columns={}",eol,start,end,columns);
2402 return eol;
2403}
#define eol
The end of line string for this machine.
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
size_t isNewline(std::string_view data)
Definition markdown.cpp:207

References AUTO_TRACE, AUTO_TRACE_EXIT, end(), eol, isNewline(), and Trace::trunc().

Referenced by isTableBlock(), and Markdown::Private::writeTableBlock().

◆ getFilteredImageAttributes()

static QCString getFilteredImageAttributes ( std::string_view fmt,
const QCString & attrs )
static

parse the image attributes and return attributes for given format

Definition at line 310 of file markdown.cpp.

311{
312 AUTO_TRACE("fmt={} attrs={}",fmt,attrs);
313 StringVector attrList = split(attrs.str(),",");
314 for (const auto &attr_ : attrList)
315 {
316 QCString attr = QCString(attr_).stripWhiteSpace();
317 int i = attr.find(':');
318 if (i>0) // has format
319 {
320 QCString format = attr.left(i).stripWhiteSpace().lower();
321 if (format == fmt) // matching format
322 {
323 AUTO_TRACE_EXIT("result={}",attr.mid(i+1));
324 return attr.mid(i+1); // keep part after :
325 }
326 }
327 else // option that applies to all formats
328 {
329 AUTO_TRACE_EXIT("result={}",attr);
330 return attr;
331 }
332 }
333 return QCString();
334}
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
QCString lower() const
Definition qcstring.h:234
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:245
const std::string & str() const
Definition qcstring.h:537
QCString left(size_t len) const
Definition qcstring.h:214
std::vector< std::string > StringVector
Definition containers.h:33
Definition trace.h:153
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:6946

References AUTO_TRACE, AUTO_TRACE_EXIT, QCString::find(), QCString::left(), QCString::lower(), QCString::mid(), split(), QCString::str(), and QCString::stripWhiteSpace().

Referenced by Markdown::Private::writeMarkdownImage().

◆ hasLineBreak()

static bool hasLineBreak ( std::string_view data)
static

Definition at line 2646 of file markdown.cpp.

2647{
2648 AUTO_TRACE("data='{}'",Trace::trunc(data));
2649 size_t i=0;
2650 size_t j=0;
2651 // search for end of line and also check if it is not a completely blank
2652 while (i<data.size() && data[i]!='\n')
2653 {
2654 if (data[i]!=' ' && data[i]!='\t') j++; // some non whitespace
2655 i++;
2656 }
2657 if (i>=data.size()) { return 0; } // empty line
2658 if (i<2) { return 0; } // not long enough
2659 bool res = (j>0 && data[i-1]==' ' && data[i-2]==' '); // non blank line with at two spaces at the end
2660 AUTO_TRACE_EXIT("result={}",res);
2661 return res;
2662}

References AUTO_TRACE, AUTO_TRACE_EXIT, and Trace::trunc().

Referenced by Markdown::Private::writeOneLineHeaderOrRuler().

◆ isBlockQuote()

static bool isBlockQuote ( std::string_view data,
size_t indent )
static

returns true if this line starts a block quote

Definition at line 1809 of file markdown.cpp.

1810{
1811 AUTO_TRACE("data='{}' indent={}",Trace::trunc(data),indent);
1812 size_t i = 0;
1813 const size_t size = data.size();
1814 while (i<size && data[i]==' ') i++;
1815 if (i<indent+codeBlockIndent) // could be a quotation
1816 {
1817 // count >'s and skip spaces
1818 int level=0;
1819 while (i<size && (data[i]=='>' || data[i]==' '))
1820 {
1821 if (data[i]=='>') level++;
1822 i++;
1823 }
1824 // last characters should be a space or newline,
1825 // so a line starting with >= does not match, but only when level equals 1
1826 bool res = (level>0 && i<size && ((data[i-1]==' ') || data[i]=='\n')) || (level > 1);
1827 AUTO_TRACE_EXIT("result={}",res);
1828 return res;
1829 }
1830 else // too much indentation -> code block
1831 {
1832 AUTO_TRACE_EXIT("result=false: too much indentation");
1833 return false;
1834 }
1835}
const size_t codeBlockIndent
Definition markdown.cpp:201

References AUTO_TRACE, AUTO_TRACE_EXIT, codeBlockIndent, and Trace::trunc().

Referenced by Markdown::Private::processQuotations().

◆ isCodeBlock()

static bool isCodeBlock ( std::string_view data,
size_t offset,
size_t & indent )
static

Definition at line 2272 of file markdown.cpp.

2273{
2274 AUTO_TRACE("data='{}' offset={}",Trace::trunc(data),offset);
2275 //printf("<isCodeBlock(offset=%d,size=%d,indent=%d)\n",offset,size,indent);
2276 // determine the indent of this line
2277 size_t i=0;
2278 size_t indent0=0;
2279 const size_t size = data.size();
2280 while (i<size && data[i]==' ') indent0++,i++;
2281
2282 if (indent0<codeBlockIndent)
2283 {
2284 AUTO_TRACE_EXIT("result={}: line is not indented enough {}<4",false,indent0);
2285 return false;
2286 }
2287 if (indent0>=size || data[indent0]=='\n') // empty line does not start a code block
2288 {
2289 AUTO_TRACE_EXIT("result={}: only spaces at the end of a comment block",false);
2290 return false;
2291 }
2292
2293 i=offset;
2294 int nl=0;
2295 int nl_pos[3];
2296 int offset_i = static_cast<int>(offset);
2297 // search back 3 lines and remember the start of lines -1 and -2
2298 while (i>0 && nl<3) // i counts down from offset to 1
2299 {
2300 int j = static_cast<int>(i)-offset_i-1; // j counts from -1 to -offset
2301 // since j can be negative we need to rewrap data in a std::string_view
2302 size_t nl_size = isNewline(std::string_view(data.data()+j,data.size()-j));
2303 if (nl_size>0)
2304 {
2305 nl_pos[nl++]=j+static_cast<int>(nl_size);
2306 }
2307 i--;
2308 }
2309
2310 // if there are only 2 preceding lines, then line -2 starts at -offset
2311 if (i==0 && nl==2) nl_pos[nl++]=-offset_i;
2312
2313 if (nl==3) // we have at least 2 preceding lines
2314 {
2315 //printf(" positions: nl_pos=[%d,%d,%d] line[-2]='%s' line[-1]='%s'\n",
2316 // nl_pos[0],nl_pos[1],nl_pos[2],
2317 // qPrint(QCString(data+nl_pos[1]).left(nl_pos[0]-nl_pos[1]-1)),
2318 // qPrint(QCString(data+nl_pos[2]).left(nl_pos[1]-nl_pos[2]-1)));
2319
2320 // check that line -1 is empty
2321 // Note that the offset is negative so we need to rewrap the string view
2322 if (!isEmptyLine(std::string_view(data.data()+nl_pos[1],nl_pos[0]-nl_pos[1]-1)))
2323 {
2324 AUTO_TRACE_EXIT("result={}",FALSE);
2325 return FALSE;
2326 }
2327
2328 // determine the indent of line -2
2329 // Note that the offset is negative so we need to rewrap the string view
2330 indent=std::max(indent,computeIndentExcludingListMarkers(
2331 std::string_view(data.data()+nl_pos[2],nl_pos[1]-nl_pos[2])));
2332
2333 //printf(">isCodeBlock local_indent %d>=%d+%d=%d\n",
2334 // indent0,indent,codeBlockIndent,indent0>=indent+codeBlockIndent);
2335 // if the difference is >4 spaces -> code block
2336 bool res = indent0>=indent+codeBlockIndent;
2337 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2338 return res;
2339 }
2340 else // not enough lines to determine the relative indent, use global indent
2341 {
2342 // check that line -1 is empty
2343 // Note that the offset is negative so we need to rewrap the string view
2344 if (nl==1 && !isEmptyLine(std::string_view(data.data()-offset,offset-1)))
2345 {
2346 AUTO_TRACE_EXIT("result=false");
2347 return FALSE;
2348 }
2349 //printf(">isCodeBlock global indent %d>=%d+4=%d nl=%d\n",
2350 // indent0,indent,indent0>=indent+4,nl);
2351 bool res = indent0>=indent+codeBlockIndent;
2352 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2353 return res;
2354 }
2355}
static size_t computeIndentExcludingListMarkers(std::string_view data)
static bool isEmptyLine(std::string_view data)

References AUTO_TRACE, AUTO_TRACE_EXIT, codeBlockIndent, computeIndentExcludingListMarkers(), FALSE, isEmptyLine(), isNewline(), and Trace::trunc().

Referenced by Markdown::Private::processBlocks().

◆ isEmptyLine()

static bool isEmptyLine ( std::string_view data)
static

Definition at line 2058 of file markdown.cpp.

2059{
2060 AUTO_TRACE("data='{}'",Trace::trunc(data));
2061 size_t i=0;
2062 while (i<data.size())
2063 {
2064 if (data[i]=='\n') { AUTO_TRACE_EXIT("true"); return true; }
2065 if (data[i]!=' ') { AUTO_TRACE_EXIT("false"); return false; }
2066 i++;
2067 }
2068 AUTO_TRACE_EXIT("true");
2069 return true;
2070}

References AUTO_TRACE, AUTO_TRACE_EXIT, and Trace::trunc().

Referenced by isCodeBlock(), Markdown::Private::processBlocks(), and Markdown::Private::processQuotations().

◆ isEndOfList()

static bool isEndOfList ( std::string_view data)
static

Definition at line 2160 of file markdown.cpp.

2161{
2162 AUTO_TRACE("data='{}'",Trace::trunc(data));
2163 int dots=0;
2164 size_t i=0;
2165 // end of list marker is an otherwise empty line with a dot.
2166 while (i<data.size())
2167 {
2168 if (data[i]=='.')
2169 {
2170 dots++;
2171 }
2172 else if (data[i]=='\n')
2173 {
2174 break;
2175 }
2176 else if (data[i]!=' ' && data[i]!='\t') // bail out if the line is not empty
2177 {
2178 AUTO_TRACE_EXIT("result=false");
2179 return false;
2180 }
2181 i++;
2182 }
2183 AUTO_TRACE_EXIT("result={}",dots==1);
2184 return dots==1;
2185}

References AUTO_TRACE, AUTO_TRACE_EXIT, and Trace::trunc().

Referenced by Markdown::Private::processBlocks(), and Markdown::Private::processQuotations().

◆ isExplicitPage()

static ExplicitPageResult isExplicitPage ( const QCString & docs)
static

Definition at line 3405 of file markdown.cpp.

3406{
3407 AUTO_TRACE("docs={}",Trace::trunc(docs));
3408 size_t i=0;
3409 std::string_view data(docs.str());
3410 const size_t size = data.size();
3411 if (!data.empty())
3412 {
3413 while (i<size && (data[i]==' ' || data[i]=='\n'))
3414 {
3415 i++;
3416 }
3417 if (i<size-5 && data[i]=='<' && qstrncmp(&data[i],"<!--!",5)==0) // skip over <!--! marker
3418 {
3419 i+=5;
3420 while (i<size && (data[i]==' ' || data[i]=='\n')) // skip over spaces after the <!--! marker
3421 {
3422 i++;
3423 }
3424 }
3425 if (i<size-1 &&
3426 (data[i]=='\\' || data[i]=='@') &&
3427 (qstrncmp(&data[i+1],"page ",5)==0 || qstrncmp(&data[i+1],"mainpage",8)==0)
3428 )
3429 {
3430 if (qstrncmp(&data[i+1],"page ",5)==0)
3431 {
3432 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitPage");
3434 }
3435 else
3436 {
3437 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitMainPage");
3439 }
3440 }
3441 else if (i<size-1 &&
3442 (data[i]=='\\' || data[i]=='@') &&
3443 (qstrncmp(&data[i+1],"dir\n",4)==0 || qstrncmp(&data[i+1],"dir ",4)==0)
3444 )
3445 {
3446 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitDirPage");
3448 }
3449 }
3450 AUTO_TRACE_EXIT("result=ExplicitPageResult::notExplicit");
3452}
int qstrncmp(const char *str1, const char *str2, size_t len)
Definition qcstring.h:75

References AUTO_TRACE, AUTO_TRACE_EXIT, explicitDirPage, explicitMainPage, explicitPage, notExplicit, qstrncmp(), QCString::str(), and Trace::trunc().

Referenced by MarkdownOutlineParser::parseInput().

◆ isFencedCodeBlock()

static bool isFencedCodeBlock ( std::string_view data,
size_t refIndent,
QCString & lang,
size_t & start,
size_t & end,
size_t & offset )
static

extract python or .py from python... or .py...

Definition at line 2187 of file markdown.cpp.

2189{
2190 AUTO_TRACE("data='{}' refIndent={}",Trace::trunc(data),refIndent);
2191 const char dot = '.';
2192 auto isAlphaChar = [ ](char c) { return (c>='A' && c<='Z') || (c>='a' && c<='z'); };
2193 auto isAlphaNChar = [ ](char c) { return (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9'); };
2194 auto isLangChar = [&](char c) { return c==dot || isAlphaChar(c); };
2195 // rules: at least 3 ~~~, end of the block same amount of ~~~'s, otherwise
2196 // return FALSE
2197 size_t i=0;
2198 size_t indent=0;
2199 int startTildes=0;
2200 const size_t size = data.size();
2201 while (i<size && data[i]==' ') indent++,i++;
2202 if (indent>=refIndent+4)
2203 {
2204 AUTO_TRACE_EXIT("result=false: content is part of code block indent={} refIndent={}",indent,refIndent);
2205 return FALSE;
2206 } // part of code block
2207 char tildaChar='~';
2208 if (i<size && data[i]=='`') tildaChar='`';
2209 while (i<size && data[i]==tildaChar) startTildes++,i++;
2210 if (startTildes<3)
2211 {
2212 AUTO_TRACE_EXIT("result=false: no fence marker found #tildes={}",startTildes);
2213 return FALSE;
2214 } // not enough tildes
2215 if (i<size && data[i]=='{') // extract .py from ```{.py} ... ```
2216 {
2217 i++; // skip over {
2218 if (data[i] == dot) i++; // skip over initial dot
2219 size_t startLang=i;
2220 while (i<size && (data[i]!='\n' && data[i]!='}')) i++; // find matching }
2221 if (i<size && data[i]=='}')
2222 {
2223 lang = data.substr(startLang,i-startLang);
2224 i++;
2225 }
2226 else // missing closing bracket, treat `{` as part of the content
2227 {
2228 i=startLang-1;
2229 lang="";
2230 }
2231 }
2232 else if (i<size && isLangChar(data[i])) /// extract python or .py from ```python...``` or ```.py...```
2233 {
2234 if (data[i] == dot) i++; // skip over initial dot
2235 size_t startLang=i;
2236 if (i<size && isAlphaChar(data[i])) //check first character of language specifier
2237 {
2238 i++;
2239 while (i<size && isAlphaNChar(data[i])) i++; // find end of language specifier
2240 }
2241 lang = data.substr(startLang,i-startLang);
2242 }
2243 else // no language specified
2244 {
2245 lang="";
2246 }
2247
2248 start=i;
2249 while (i<size)
2250 {
2251 if (data[i]==tildaChar)
2252 {
2253 end=i;
2254 int endTildes=0;
2255 while (i<size && data[i]==tildaChar) endTildes++,i++;
2256 while (i<size && data[i]==' ') i++;
2257 {
2258 if (endTildes==startTildes)
2259 {
2260 offset=i;
2261 AUTO_TRACE_EXIT("result=true: found end marker at offset {} lang='{}'",offset,lang);
2262 return true;
2263 }
2264 }
2265 }
2266 i++;
2267 }
2268 AUTO_TRACE_EXIT("result=false: no end marker found lang={}'",lang);
2269 return false;
2270}

References AUTO_TRACE, AUTO_TRACE_EXIT, end(), FALSE, and Trace::trunc().

Referenced by Markdown::Private::processBlocks(), and Markdown::Private::processQuotations().

◆ isHRuler()

static bool isHRuler ( std::string_view data)
static

Definition at line 1927 of file markdown.cpp.

1928{
1929 AUTO_TRACE("data='{}'",Trace::trunc(data));
1930 size_t i=0;
1931 size_t size = data.size();
1932 if (size>0 && data[size-1]=='\n') size--; // ignore newline character
1933 while (i<size && data[i]==' ') i++;
1934 if (i>=size) { AUTO_TRACE_EXIT("result=false: empty line"); return false; } // empty line
1935 char c=data[i];
1936 if (c!='*' && c!='-' && c!='_')
1937 {
1938 AUTO_TRACE_EXIT("result=false: {} is not a hrule character",c);
1939 return false; // not a hrule character
1940 }
1941 int n=0;
1942 while (i<size)
1943 {
1944 if (data[i]==c)
1945 {
1946 n++; // count rule character
1947 }
1948 else if (data[i]!=' ')
1949 {
1950 AUTO_TRACE_EXIT("result=false: line contains non hruler characters");
1951 return false; // line contains non hruler characters
1952 }
1953 i++;
1954 }
1955 AUTO_TRACE_EXIT("result={}",n>=3);
1956 return n>=3; // at least 3 characters needed for a hruler
1957}

References AUTO_TRACE, AUTO_TRACE_EXIT, and Trace::trunc().

Referenced by Markdown::Private::writeOneLineHeaderOrRuler().

◆ isLinkRef()

static size_t isLinkRef ( std::string_view data,
QCString & refid,
QCString & link,
QCString & title )
static

returns end of the link ref if this is indeed a link reference.

Definition at line 1838 of file markdown.cpp.

1839{
1840 AUTO_TRACE("data='{}'",Trace::trunc(data));
1841 const size_t size = data.size();
1842 // format: start with [some text]:
1843 size_t i = 0;
1844 while (i<size && data[i]==' ') i++;
1845 if (i>=size || data[i]!='[') { return 0; }
1846 i++;
1847 size_t refIdStart=i;
1848 while (i<size && data[i]!='\n' && data[i]!=']') i++;
1849 if (i>=size || data[i]!=']') { return 0; }
1850 refid = data.substr(refIdStart,i-refIdStart);
1851 if (refid.isEmpty()) { return 0; }
1852 AUTO_TRACE_ADD("refid found {}",refid);
1853 //printf(" isLinkRef: found refid='%s'\n",qPrint(refid));
1854 i++;
1855 if (i>=size || data[i]!=':') { return 0; }
1856 i++;
1857
1858 // format: whitespace* \n? whitespace* (<url> | url)
1859 while (i<size && data[i]==' ') i++;
1860 if (i<size && data[i]=='\n')
1861 {
1862 i++;
1863 while (i<size && data[i]==' ') i++;
1864 }
1865 if (i>=size) { return 0; }
1866
1867 if (i<size && data[i]=='<') i++;
1868 size_t linkStart=i;
1869 while (i<size && data[i]!=' ' && data[i]!='\n') i++;
1870 size_t linkEnd=i;
1871 if (i<size && data[i]=='>') i++;
1872 if (linkStart==linkEnd) { return 0; } // empty link
1873 link = data.substr(linkStart,linkEnd-linkStart);
1874 AUTO_TRACE_ADD("link found {}",Trace::trunc(link));
1875 if (link=="@ref" || link=="\\ref")
1876 {
1877 size_t argStart=i;
1878 while (i<size && data[i]!='\n' && data[i]!='"') i++;
1879 link+=data.substr(argStart,i-argStart);
1880 }
1881
1882 title.clear();
1883
1884 // format: (whitespace* \n? whitespace* ( 'title' | "title" | (title) ))?
1885 size_t eol=0;
1886 while (i<size && data[i]==' ') i++;
1887 if (i<size && data[i]=='\n')
1888 {
1889 eol=i;
1890 i++;
1891 while (i<size && data[i]==' ') i++;
1892 }
1893 if (i>=size)
1894 {
1895 AUTO_TRACE_EXIT("result={}: end of isLinkRef while looking for title",i);
1896 return i; // end of buffer while looking for the optional title
1897 }
1898
1899 char c = data[i];
1900 if (c=='\'' || c=='"' || c=='(') // optional title present?
1901 {
1902 //printf(" start of title found! char='%c'\n",c);
1903 i++;
1904 if (c=='(') c=')'; // replace c by end character
1905 size_t titleStart=i;
1906 // search for end of the line
1907 while (i<size && data[i]!='\n') i++;
1908 eol = i;
1909
1910 // search back to matching character
1911 size_t end=i-1;
1912 while (end>titleStart && data[end]!=c) end--;
1913 if (end>titleStart)
1914 {
1915 title = data.substr(titleStart,end-titleStart);
1916 }
1917 AUTO_TRACE_ADD("title found {}",Trace::trunc(title));
1918 }
1919 while (i<size && data[i]==' ') i++;
1920 //printf("end of isLinkRef: i=%d size=%d data[i]='%c' eol=%d\n",
1921 // i,size,data[i],eol);
1922 if (i>=size) { AUTO_TRACE_EXIT("result={}",i); return i; } // end of buffer while ref id was found
1923 else if (eol>0) { AUTO_TRACE_EXIT("result={}",eol); return eol; } // end of line while ref id was found
1924 return 0; // invalid link ref
1925}
void clear()
Definition qcstring.h:169
#define AUTO_TRACE_ADD(...)
Definition markdown.cpp:62

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, QCString::clear(), end(), eol, QCString::isEmpty(), and Trace::trunc().

Referenced by Markdown::Private::processBlocks().

◆ isListMarker()

static size_t isListMarker ( std::string_view data)
static

Definition at line 2149 of file markdown.cpp.

2150{
2151 AUTO_TRACE("data='{}'",Trace::trunc(data));
2152 size_t normalIndent = 0;
2153 while (normalIndent<data.size() && data[normalIndent]==' ') normalIndent++;
2154 size_t listIndent = computeIndentExcludingListMarkers(data);
2155 size_t result = listIndent>normalIndent ? listIndent : 0;
2156 AUTO_TRACE_EXIT("result={}",result);
2157 return result;
2158}

References AUTO_TRACE, AUTO_TRACE_EXIT, computeIndentExcludingListMarkers(), and Trace::trunc().

Referenced by Markdown::Private::processBlocks(), and Markdown::Private::processQuotations().

◆ isNewline()

size_t isNewline ( std::string_view data)
inline

Definition at line 207 of file markdown.cpp.

208{
209 // normal newline
210 if (data[0] == '\n') return 1;
211 // artificial new line from ^^ in ALIASES
212 if (data[0] == '\\' && qstrncmp(data.data()+1,"ilinebr ",7)==0) return data[8]==' ' ? 9 : 8;
213 return 0;
214}

References qstrncmp().

Referenced by Markdown::Private::findEndOfLine(), findTableColumns(), and isCodeBlock().

◆ isTableBlock()

static bool isTableBlock ( std::string_view data)
static

Returns TRUE iff data points to the start of a table block.

Definition at line 2406 of file markdown.cpp.

2407{
2408 AUTO_TRACE("data='{}'",Trace::trunc(data));
2409 size_t cc0=0, start=0, end=0;
2410
2411 // the first line should have at least two columns separated by '|'
2412 size_t i = findTableColumns(data,start,end,cc0);
2413 if (i>=data.size() || cc0<1)
2414 {
2415 AUTO_TRACE_EXIT("result=false: no |'s in the header");
2416 return FALSE;
2417 }
2418
2419 size_t cc1 = 0;
2420 size_t ret = findTableColumns(data.substr(i),start,end,cc1);
2421 size_t j=i+start;
2422 // separator line should consist of |, - and : and spaces only
2423 while (j<=end+i)
2424 {
2425 if (data[j]!=':' && data[j]!='-' && data[j]!='|' && data[j]!=' ')
2426 {
2427 AUTO_TRACE_EXIT("result=false: invalid character '{}'",data[j]);
2428 return FALSE; // invalid characters in table separator
2429 }
2430 j++;
2431 }
2432 if (cc1!=cc0) // number of columns should be same as previous line
2433 {
2434 AUTO_TRACE_EXIT("result=false: different number of columns as previous line {}!={}",cc1,cc0);
2435 return FALSE;
2436 }
2437
2438 i+=ret; // goto next line
2439 size_t cc2 = 0;
2440 findTableColumns(data.substr(i),start,end,cc2);
2441
2442 AUTO_TRACE_EXIT("result={}",cc1==cc2);
2443 return cc1==cc2;
2444}
static size_t findTableColumns(std::string_view data, size_t &start, size_t &end, size_t &columns)
Finds the location of the table's contains in the string data.

References AUTO_TRACE, AUTO_TRACE_EXIT, end(), FALSE, findTableColumns(), and Trace::trunc().

Referenced by Markdown::Private::processBlocks().

◆ markdownFileNameToId()

QCString markdownFileNameToId ( const QCString & fileName)

processes string s and converts markdown into doxygen/html commands.

Definition at line 3558 of file markdown.cpp.

3559{
3560 AUTO_TRACE("fileName={}",fileName);
3561 std::string absFileName = FileInfo(fileName.str()).absFilePath();
3562 QCString baseFn = stripFromPath(absFileName.c_str());
3563 int i = baseFn.findRev('.');
3564 if (i!=-1) baseFn = baseFn.left(i);
3565 QCString baseName = escapeCharsInString(baseFn,false,false);
3566 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3567 QCString res = "md_"+baseName;
3568 AUTO_TRACE_EXIT("result={}",res);
3569 return res;
3570}
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
std::string absFilePath() const
Definition fileinfo.cpp:101
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:91
QCString escapeCharsInString(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3684
static QCString stripFromPath(const QCString &p, const StringVector &l)
Definition util.cpp:309

References FileInfo::absFilePath(), AUTO_TRACE, AUTO_TRACE_EXIT, escapeCharsInString(), QCString::findRev(), QCString::left(), QCString::str(), and stripFromPath().

Referenced by DocRef::DocRef(), DocSecRefItem::parse(), and MarkdownOutlineParser::parseInput().

◆ markersToAlignment()

static Alignment markersToAlignment ( bool leftMarker,
bool rightMarker )
static

helper function to convert presence of left and/or right alignment markers to a alignment value

Definition at line 289 of file markdown.cpp.

290{
291 if (leftMarker && rightMarker)
292 {
293 return AlignCenter;
294 }
295 else if (leftMarker)
296 {
297 return AlignLeft;
298 }
299 else if (rightMarker)
300 {
301 return AlignRight;
302 }
303 else
304 {
305 return AlignNone;
306 }
307}

References AlignCenter, AlignLeft, AlignNone, and AlignRight.

Referenced by Markdown::Private::writeTableBlock().

◆ skipOverFileAndLineCommands()

bool skipOverFileAndLineCommands ( std::string_view data,
size_t indent,
size_t & offset,
std::string & location )

Definition at line 2843 of file markdown.cpp.

2844{
2845 size_t i = offset;
2846 size_t size = data.size();
2847 while (i<data.size() && data[i]==' ') i++;
2848 if (i<size+8 && data[i]=='\\' && qstrncmp(&data[i+1],"ifile \"",7)==0)
2849 {
2850 size_t locStart = i;
2851 if (i>offset) locStart--; // include the space before \ifile
2852 i+=8;
2853 bool found=false;
2854 while (i<size-9 && data[i]!='\n')
2855 {
2856 if (data[i]=='\\' && qstrncmp(&data[i+1],"ilinebr ",8)==0)
2857 {
2858 found=true;
2859 break;
2860 }
2861 i++;
2862 }
2863 if (found)
2864 {
2865 i+=9;
2866 location=data.substr(locStart,i-locStart);
2867 location+='\n';
2868 while (indent>0 && i<size && data[i]==' ') i++,indent--;
2869 if (i<size && data[i]=='\n') i++;
2870 offset = i;
2871 return true;
2872 }
2873 }
2874 return false;
2875}
bool found
Definition util.cpp:984

References found, and qstrncmp().

Referenced by Markdown::Private::writeCodeBlock().

Variable Documentation

◆ codeBlockIndent

const size_t codeBlockIndent = 4

◆ g_doxy_nbsp

const char* g_doxy_nbsp = "&_doxy_nbsp;"

Definition at line 200 of file markdown.cpp.

Referenced by Markdown::Private::addStrEscapeUtf8Nbsp(), and Markdown::process().

◆ g_quotationHeaderMap

const std::unordered_map<std::string,std::string> g_quotationHeaderMap
static
Initial value:
= {
{ "[!note]", "\\note" },
{ "[!warning]", "\\warning" },
{ "[!tip]", "\\remark" },
{ "[!caution]", "\\attention" },
{ "[!important]", "\\important" }
}

Definition at line 2716 of file markdown.cpp.

2716 {
2717 // GitHub style Doxygen command
2718 { "[!note]", "\\note" },
2719 { "[!warning]", "\\warning" },
2720 { "[!tip]", "\\remark" },
2721 { "[!caution]", "\\attention" },
2722 { "[!important]", "\\important" }
2723};

Referenced by Markdown::Private::writeBlockQuote().

◆ g_utf8_nbsp

const char* g_utf8_nbsp = "\xc2\xa0"

Definition at line 199 of file markdown.cpp.

Referenced by Markdown::Private::addStrEscapeUtf8Nbsp().