Skip to main content

The markdown.cpp File Reference

Included Headers

#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"

Classes Index

structTableCell
structPrivate
structLinkRef
structPrivate

Enumerations Index

enum classExplicitPageResult { ... }
enumAlignment { ... }

Functions Index

size_tisNewline (std::string_view data)
static QCStringescapeDoubleQuotes (const QCString &s)
static QCStringescapeSpecialChars (const QCString &s)
static AlignmentmarkersToAlignment (bool leftMarker, bool rightMarker)

helper function to convert presence of left and/or right alignment markers to an alignment value More...

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

parse the image attributes and return attributes for given format More...

static boolisBlockQuote (std::string_view data, size_t indent)

returns true if this line starts a block quote More...

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

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

static boolisHRuler (std::string_view data)
static boolisEmptyLine (std::string_view data)
static size_tcomputeIndentExcludingListMarkers (std::string_view data)
static size_tisListMarker (std::string_view data)
static boolisEndOfList (std::string_view data)
static boolisFencedCodeBlock (std::string_view data, size_t refIndent, QCString &lang, size_t &start, size_t &end, size_t &offset)
static boolisCodeBlock (std::string_view data, size_t offset, size_t &indent)
static size_tfindTableColumns (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. More...

static boolisTableBlock (std::string_view data)

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

static boolhasLineBreak (std::string_view data)
boolskipOverFileAndLineCommands (std::string_view data, size_t indent, size_t &offset, std::string &location)
static boolisOtherPage (std::string_view data)
static ExplicitPageResultisExplicitPage (const QCString &docs)
QCStringmarkdownFileNameToId (const QCString &fileName)

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

Variables Index

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

Macro Definitions Index

#defineAUTO_TRACE(...)   (void)0
#defineAUTO_TRACE_ADD(...)   (void)0
#defineAUTO_TRACE_EXIT(...)   (void)0
#defineisIdChar(c)   ...
#defineextraChar(c)   ...
#defineisOpenEmphChar(c)   ...
#defineignoreCloseEmphChar(c, cn)   ...
#defineisLiTag(i)   ...
#defineOPC(x)   if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true

Enumerations

Alignment

enum Alignment
Enumeration values
AlignNone
AlignLeft
AlignCenter
AlignRight

Definition at line 194 of file markdown.cpp.

ExplicitPageResult

enum class ExplicitPageResult
strong
Enumeration values
explicitPagedocs start with a page command
explicitMainPagedocs start with a mainpage command
explicitOtherPagedocs start with a dir / defgroup / addtogroup command
notExplicitdocs 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 explicitOtherPage, /**< docs start with a dir / defgroup / addtogroup command */
71 notExplicit /**< docs doesn't start with either page or mainpage */
72};

Functions

computeIndentExcludingListMarkers()

size_t computeIndentExcludingListMarkers (std::string_view data)
static

Definition at line 2113 of file markdown.cpp.

2113static size_t computeIndentExcludingListMarkers(std::string_view data)
2114{
2115 AUTO_TRACE("data='{}'",Trace::trunc(data));
2116 size_t i=0;
2117 const size_t size=data.size();
2118 size_t indent=0;
2119 bool isDigit=FALSE;
2120 bool isLi=FALSE;
2121 bool listMarkerSkipped=FALSE;
2122 while (i<size &&
2123 (data[i]==' ' || // space
2124 (!listMarkerSkipped && // first list marker
2125 (data[i]=='+' || data[i]=='-' || data[i]=='*' || // unordered list char
2126 (data[i]=='#' && i>0 && data[i-1]=='-') || // -# item
2127 (isDigit=(data[i]>='1' && data[i]<='9')) || // ordered list marker?
2128 (isLi=(size>=3 && i+3<size && isLiTag(i))) // <li> tag
2129 )
2130 )
2131 )
2132 )
2133 {
2134 if (isDigit) // skip over ordered list marker '10. '
2135 {
2136 size_t j=i+1;
2137 while (j<size && ((data[j]>='0' && data[j]<='9') || data[j]=='.'))
2138 {
2139 if (data[j]=='.') // should be end of the list marker
2140 {
2141 if (j+1<size && data[j+1]==' ') // valid list marker
2142 {
2143 listMarkerSkipped=TRUE;
2144 indent+=j+1-i;
2145 i=j+1;
2146 break;
2147 }
2148 else // not a list marker
2149 {
2150 break;
2151 }
2152 }
2153 j++;
2154 }
2155 }
2156 else if (isLi)
2157 {
2158 i+=3; // skip over <li>
2159 indent+=3;
2160 listMarkerSkipped=TRUE;
2161 }
2162 else if (data[i]=='-' && size>=2 && i+2<size && data[i+1]=='#' && data[i+2]==' ')
2163 { // case "-# "
2164 listMarkerSkipped=TRUE; // only a single list marker is accepted
2165 i++; // skip over #
2166 indent++;
2167 }
2168 else if (data[i]!=' ' && i+1<size && data[i+1]==' ')
2169 { // case "- " or "+ " or "* "
2170 listMarkerSkipped=TRUE; // only a single list marker is accepted
2171 }
2172 if (data[i]!=' ' && !listMarkerSkipped)
2173 { // end of indent
2174 break;
2175 }
2176 indent++,i++;
2177 }
2178 AUTO_TRACE_EXIT("result={}",indent);
2179 return indent;
2180}

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

Referenced by isCodeBlock and isListMarker.

escapeDoubleQuotes()

QCString escapeDoubleQuotes (const QCString & s)
static

Definition at line 220 of file markdown.cpp.

221{
222 AUTO_TRACE("s={}",Trace::trunc(s));
223 if (s.isEmpty()) return s;
224 QCString result;
225 const char *p=s.data();
226 char c=0, pc='\0';
227 while ((c=*p++))
228 {
229 if (c=='"' && pc!='\\') result+='\\';
230 result+=c;
231 pc=c;
232 }
233 AUTO_TRACE_EXIT("result={}",result);
234 return result;
235}

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

Referenced by Markdown::Private::writeMarkdownImage.

escapeSpecialChars()

QCString escapeSpecialChars (const QCString & s)
static

Definition at line 238 of file markdown.cpp.

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

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

Referenced by Markdown::Private::processCodeSpan.

findTableColumns()

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] data

pointer to the string buffer.

[out] start

offset of the first character of the table content

[out] end

offset of the last character of the table content

[out] columns

number of table columns found

Returns

The offset until the next line in the buffer.

Definition at line 2398 of file markdown.cpp.

2398static size_t findTableColumns(std::string_view data,size_t &start,size_t &end,size_t &columns)
2399{
2400 AUTO_TRACE("data='{}'",Trace::trunc(data));
2401 const size_t size = data.size();
2402 size_t i=0,n=0;
2403 // find start character of the table line
2404 while (i<size && data[i]==' ') i++;
2405 if (i<size && data[i]=='|' && data[i]!='\n') i++,n++; // leading | does not count
2406 start = i;
2407
2408 // find end character of the table line
2409 size_t j = 0;
2410 while (i<size && (j = isNewline(data.substr(i)))==0) i++;
2411 size_t eol=i+j;
2412
2413 if (j>0 && i>0) i--; // move i to point before newline
2414 while (i>0 && data[i]==' ') i--;
2415 if (i>0 && data[i-1]!='\\' && data[i]=='|') i--,n++; // trailing or escaped | does not count
2416 end = i;
2417
2418 // count columns between start and end
2419 columns=0;
2420 if (end>start)
2421 {
2422 i=start;
2423 while (i<=end) // look for more column markers
2424 {
2425 if (data[i]=='|' && (i==0 || data[i-1]!='\\')) columns++;
2426 if (columns==1) columns++; // first | make a non-table into a two column table
2427 i++;
2428 }
2429 }
2430 if (n==2 && columns==0) // table row has | ... |
2431 {
2432 columns++;
2433 }
2434 AUTO_TRACE_EXIT("eol={} start={} end={} columns={}",eol,start,end,columns);
2435 return eol;
2436}

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

Referenced by isTableBlock and Markdown::Private::writeTableBlock.

getFilteredImageAttributes()

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

parse the image attributes and return attributes for given format

Definition at line 313 of file markdown.cpp.

313static QCString getFilteredImageAttributes(std::string_view fmt, const QCString &attrs)
314{
315 AUTO_TRACE("fmt={} attrs={}",fmt,attrs);
316 StringVector attrList = split(attrs.str(),",");
317 for (const auto &attr_ : attrList)
318 {
319 QCString attr = QCString(attr_).stripWhiteSpace();
320 int i = attr.find(':');
321 if (i>0) // has format
322 {
323 QCString format = attr.left(i).stripWhiteSpace().lower();
324 if (format == fmt) // matching format
325 {
326 AUTO_TRACE_EXIT("result={}",attr.mid(i+1));
327 return attr.mid(i+1); // keep part after :
328 }
329 }
330 else // option that applies to all formats
331 {
332 AUTO_TRACE_EXIT("result={}",attr);
333 return attr;
334 }
335 }
336 return QCString();
337}

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()

bool hasLineBreak (std::string_view data)
static

Definition at line 2679 of file markdown.cpp.

2679static bool hasLineBreak(std::string_view data)
2680{
2681 AUTO_TRACE("data='{}'",Trace::trunc(data));
2682 size_t i=0;
2683 size_t j=0;
2684 // search for end of line and also check if it is not a completely blank
2685 while (i<data.size() && data[i]!='\n')
2686 {
2687 if (data[i]!=' ' && data[i]!='\t') j++; // some non whitespace
2688 i++;
2689 }
2690 if (i>=data.size()) { return 0; } // empty line
2691 if (i<2) { return 0; } // not long enough
2692 bool res = (j>0 && data[i-1]==' ' && data[i-2]==' '); // non blank line with at two spaces at the end
2693 AUTO_TRACE_EXIT("result={}",res);
2694 return res;
2695}

References AUTO_TRACE, AUTO_TRACE_EXIT and Trace::trunc.

Referenced by Markdown::Private::writeOneLineHeaderOrRuler.

isBlockQuote()

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

returns true if this line starts a block quote

Definition at line 1842 of file markdown.cpp.

1842static bool isBlockQuote(std::string_view data,size_t indent)
1843{
1844 AUTO_TRACE("data='{}' indent={}",Trace::trunc(data),indent);
1845 size_t i = 0;
1846 const size_t size = data.size();
1847 while (i<size && data[i]==' ') i++;
1848 if (i<indent+codeBlockIndent) // could be a quotation
1849 {
1850 // count >'s and skip spaces
1851 int level=0;
1852 while (i<size && (data[i]=='>' || data[i]==' '))
1853 {
1854 if (data[i]=='>') level++;
1855 i++;
1856 }
1857 // last characters should be a space or newline,
1858 // so a line starting with >= does not match, but only when level equals 1
1859 bool res = (level>0 && i<size && ((data[i-1]==' ') || data[i]=='\n')) || (level > 1);
1860 AUTO_TRACE_EXIT("result={}",res);
1861 return res;
1862 }
1863 else // too much indentation -> code block
1864 {
1865 AUTO_TRACE_EXIT("result=false: too much indentation");
1866 return false;
1867 }
1868}

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

Referenced by Markdown::Private::processQuotations.

isCodeBlock()

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

Definition at line 2305 of file markdown.cpp.

2305static bool isCodeBlock(std::string_view data, size_t offset,size_t &indent)
2306{
2307 AUTO_TRACE("data='{}' offset={}",Trace::trunc(data),offset);
2308 //printf("<isCodeBlock(offset=%d,size=%d,indent=%d)\n",offset,size,indent);
2309 // determine the indent of this line
2310 size_t i=0;
2311 size_t indent0=0;
2312 const size_t size = data.size();
2313 while (i<size && data[i]==' ') indent0++,i++;
2314
2315 if (indent0<codeBlockIndent)
2316 {
2317 AUTO_TRACE_EXIT("result={}: line is not indented enough {}<4",false,indent0);
2318 return false;
2319 }
2320 if (indent0>=size || data[indent0]=='\n') // empty line does not start a code block
2321 {
2322 AUTO_TRACE_EXIT("result={}: only spaces at the end of a comment block",false);
2323 return false;
2324 }
2325
2326 i=offset;
2327 int nl=0;
2328 int nl_pos[3];
2329 int offset_i = static_cast<int>(offset);
2330 // search back 3 lines and remember the start of lines -1 and -2
2331 while (i>0 && nl<3) // i counts down from offset to 1
2332 {
2333 int j = static_cast<int>(i)-offset_i-1; // j counts from -1 to -offset
2334 // since j can be negative we need to rewrap data in a std::string_view
2335 size_t nl_size = isNewline(std::string_view(data.data()+j,data.size()-j));
2336 if (nl_size>0)
2337 {
2338 nl_pos[nl++]=j+static_cast<int>(nl_size);
2339 }
2340 i--;
2341 }
2342
2343 // if there are only 2 preceding lines, then line -2 starts at -offset
2344 if (i==0 && nl==2) nl_pos[nl++]=-offset_i;
2345
2346 if (nl==3) // we have at least 2 preceding lines
2347 {
2348 //printf(" positions: nl_pos=[%d,%d,%d] line[-2]='%s' line[-1]='%s'\n",
2349 // nl_pos[0],nl_pos[1],nl_pos[2],
2350 // qPrint(QCString(data+nl_pos[1]).left(nl_pos[0]-nl_pos[1]-1)),
2351 // qPrint(QCString(data+nl_pos[2]).left(nl_pos[1]-nl_pos[2]-1)));
2352
2353 // check that line -1 is empty
2354 // Note that the offset is negative so we need to rewrap the string view
2355 if (!isEmptyLine(std::string_view(data.data()+nl_pos[1],nl_pos[0]-nl_pos[1]-1)))
2356 {
2357 AUTO_TRACE_EXIT("result={}",FALSE);
2358 return FALSE;
2359 }
2360
2361 // determine the indent of line -2
2362 // Note that the offset is negative so we need to rewrap the string view
2363 indent=std::max(indent,computeIndentExcludingListMarkers(
2364 std::string_view(data.data()+nl_pos[2],nl_pos[1]-nl_pos[2])));
2365
2366 //printf(">isCodeBlock local_indent %d>=%d+%d=%d\n",
2367 // indent0,indent,codeBlockIndent,indent0>=indent+codeBlockIndent);
2368 // if the difference is >4 spaces -> code block
2369 bool res = indent0>=indent+codeBlockIndent;
2370 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2371 return res;
2372 }
2373 else // not enough lines to determine the relative indent, use global indent
2374 {
2375 // check that line -1 is empty
2376 // Note that the offset is negative so we need to rewrap the string view
2377 if (nl==1 && !isEmptyLine(std::string_view(data.data()-offset,offset-1)))
2378 {
2379 AUTO_TRACE_EXIT("result=false");
2380 return FALSE;
2381 }
2382 //printf(">isCodeBlock global indent %d>=%d+4=%d nl=%d\n",
2383 // indent0,indent,indent0>=indent+4,nl);
2384 bool res = indent0>=indent+codeBlockIndent;
2385 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2386 return res;
2387 }
2388}

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

Referenced by Markdown::Private::processBlocks.

isEmptyLine()

bool isEmptyLine (std::string_view data)
static

Definition at line 2091 of file markdown.cpp.

2091static bool isEmptyLine(std::string_view data)
2092{
2093 AUTO_TRACE("data='{}'",Trace::trunc(data));
2094 size_t i=0;
2095 while (i<data.size())
2096 {
2097 if (data[i]=='\n') { AUTO_TRACE_EXIT("true"); return true; }
2098 if (data[i]!=' ') { AUTO_TRACE_EXIT("false"); return false; }
2099 i++;
2100 }
2101 AUTO_TRACE_EXIT("true");
2102 return true;
2103}

References AUTO_TRACE, AUTO_TRACE_EXIT and Trace::trunc.

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

isEndOfList()

bool isEndOfList (std::string_view data)
static

Definition at line 2193 of file markdown.cpp.

2193static bool isEndOfList(std::string_view data)
2194{
2195 AUTO_TRACE("data='{}'",Trace::trunc(data));
2196 int dots=0;
2197 size_t i=0;
2198 // end of list marker is an otherwise empty line with a dot.
2199 while (i<data.size())
2200 {
2201 if (data[i]=='.')
2202 {
2203 dots++;
2204 }
2205 else if (data[i]=='\n')
2206 {
2207 break;
2208 }
2209 else if (data[i]!=' ' && data[i]!='\t') // bail out if the line is not empty
2210 {
2211 AUTO_TRACE_EXIT("result=false");
2212 return false;
2213 }
2214 i++;
2215 }
2216 AUTO_TRACE_EXIT("result={}",dots==1);
2217 return dots==1;
2218}

References AUTO_TRACE, AUTO_TRACE_EXIT and Trace::trunc.

Referenced by Markdown::Private::processBlocks and Markdown::Private::processQuotations.

isExplicitPage()

ExplicitPageResult isExplicitPage (const QCString & docs)
static

Definition at line 3450 of file markdown.cpp.

3451{
3452 AUTO_TRACE("docs={}",Trace::trunc(docs));
3453 size_t i=0;
3454 std::string_view data(docs.str());
3455 const size_t size = data.size();
3456 if (!data.empty())
3457 {
3458 while (i<size && (data[i]==' ' || data[i]=='\n'))
3459 {
3460 i++;
3461 }
3462 if (literal_at(data.substr(i),"<!--!")) // skip over <!--! marker
3463 {
3464 i+=5;
3465 while (i<size && (data[i]==' ' || data[i]=='\n')) // skip over spaces after the <!--! marker
3466 {
3467 i++;
3468 }
3469 }
3470 if (i+1<size &&
3471 (data[i]=='\\' || data[i]=='@') &&
3472 (literal_at(data.substr(i+1),"page ") || literal_at(data.substr(i+1),"mainpage"))
3473 )
3474 {
3475 if (literal_at(data.substr(i+1),"page "))
3476 {
3477 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitPage");
3479 }
3480 else
3481 {
3482 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitMainPage");
3484 }
3485 }
3486 else if (i+1<size && (data[i]=='\\' || data[i]=='@') && isOtherPage(data.substr(i+1)))
3487 {
3488 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitOtherPage");
3490 }
3491 }
3492 AUTO_TRACE_EXIT("result=ExplicitPageResult::notExplicit");
3494}

References AUTO_TRACE, AUTO_TRACE_EXIT, explicitMainPage, explicitOtherPage, explicitPage, isOtherPage, literal_at, notExplicit, QCString::str and Trace::trunc.

Referenced by MarkdownOutlineParser::parseInput.

isFencedCodeBlock()

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

Definition at line 2220 of file markdown.cpp.

2220static bool isFencedCodeBlock(std::string_view data,size_t refIndent,
2221 QCString &lang,size_t &start,size_t &end,size_t &offset)
2222{
2223 AUTO_TRACE("data='{}' refIndent={}",Trace::trunc(data),refIndent);
2224 const char dot = '.';
2225 auto isAlphaChar = [ ](char c) { return (c>='A' && c<='Z') || (c>='a' && c<='z'); };
2226 auto isAlphaNChar = [ ](char c) { return (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || (c=='+'); };
2227 auto isLangChar = [&](char c) { return c==dot || isAlphaChar(c); };
2228 // rules: at least 3 ~~~, end of the block same amount of ~~~'s, otherwise
2229 // return FALSE
2230 size_t i=0;
2231 size_t indent=0;
2232 int startTildes=0;
2233 const size_t size = data.size();
2234 while (i<size && data[i]==' ') indent++,i++;
2235 if (indent>=refIndent+4)
2236 {
2237 AUTO_TRACE_EXIT("result=false: content is part of code block indent={} refIndent={}",indent,refIndent);
2238 return FALSE;
2239 } // part of code block
2240 char tildaChar='~';
2241 if (i<size && data[i]=='`') tildaChar='`';
2242 while (i<size && data[i]==tildaChar) startTildes++,i++;
2243 if (startTildes<3)
2244 {
2245 AUTO_TRACE_EXIT("result=false: no fence marker found #tildes={}",startTildes);
2246 return FALSE;
2247 } // not enough tildes
2248 if (i<size && data[i]=='{') // extract .py from ```{.py} ... ```
2249 {
2250 i++; // skip over {
2251 if (data[i] == dot) i++; // skip over initial dot
2252 size_t startLang=i;
2253 while (i<size && (data[i]!='\n' && data[i]!='}')) i++; // find matching }
2254 if (i<size && data[i]=='}')
2255 {
2256 lang = data.substr(startLang,i-startLang);
2257 i++;
2258 }
2259 else // missing closing bracket, treat `{` as part of the content
2260 {
2261 i=startLang-1;
2262 lang="";
2263 }
2264 }
2265 else if (i<size && isLangChar(data[i])) /// extract python or .py from ```python...``` or ```.py...```
2266 {
2267 if (data[i] == dot) i++; // skip over initial dot
2268 size_t startLang=i;
2269 if (i<size && isAlphaChar(data[i])) //check first character of language specifier
2270 {
2271 i++;
2272 while (i<size && isAlphaNChar(data[i])) i++; // find end of language specifier
2273 }
2274 lang = data.substr(startLang,i-startLang);
2275 }
2276 else // no language specified
2277 {
2278 lang="";
2279 }
2280
2281 start=i;
2282 while (i<size)
2283 {
2284 if (data[i]==tildaChar)
2285 {
2286 end=i;
2287 int endTildes=0;
2288 while (i<size && data[i]==tildaChar) endTildes++,i++;
2289 while (i<size && data[i]==' ') i++;
2290 {
2291 if (endTildes==startTildes)
2292 {
2293 offset=i;
2294 AUTO_TRACE_EXIT("result=true: found end marker at offset {} lang='{}'",offset,lang);
2295 return true;
2296 }
2297 }
2298 }
2299 i++;
2300 }
2301 AUTO_TRACE_EXIT("result=false: no end marker found lang={}'",lang);
2302 return false;
2303}

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

Referenced by Markdown::Private::processBlocks and Markdown::Private::processQuotations.

isHRuler()

bool isHRuler (std::string_view data)
static

Definition at line 1960 of file markdown.cpp.

1960static bool isHRuler(std::string_view data)
1961{
1962 AUTO_TRACE("data='{}'",Trace::trunc(data));
1963 size_t i=0;
1964 size_t size = data.size();
1965 if (size>0 && data[size-1]=='\n') size--; // ignore newline character
1966 while (i<size && data[i]==' ') i++;
1967 if (i>=size) { AUTO_TRACE_EXIT("result=false: empty line"); return false; } // empty line
1968 char c=data[i];
1969 if (c!='*' && c!='-' && c!='_')
1970 {
1971 AUTO_TRACE_EXIT("result=false: {} is not a hrule character",c);
1972 return false; // not a hrule character
1973 }
1974 int n=0;
1975 while (i<size)
1976 {
1977 if (data[i]==c)
1978 {
1979 n++; // count rule character
1980 }
1981 else if (data[i]!=' ')
1982 {
1983 AUTO_TRACE_EXIT("result=false: line contains non hruler characters");
1984 return false; // line contains non hruler characters
1985 }
1986 i++;
1987 }
1988 AUTO_TRACE_EXIT("result={}",n>=3);
1989 return n>=3; // at least 3 characters needed for a hruler
1990}

References AUTO_TRACE, AUTO_TRACE_EXIT and Trace::trunc.

Referenced by Markdown::Private::writeBlockQuote and Markdown::Private::writeOneLineHeaderOrRuler.

isLinkRef()

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 1871 of file markdown.cpp.

1871static size_t isLinkRef(std::string_view data, QCString &refid, QCString &link, QCString &title)
1872{
1873 AUTO_TRACE("data='{}'",Trace::trunc(data));
1874 const size_t size = data.size();
1875 // format: start with [some text]:
1876 size_t i = 0;
1877 while (i<size && data[i]==' ') i++;
1878 if (i>=size || data[i]!='[') { return 0; }
1879 i++;
1880 size_t refIdStart=i;
1881 while (i<size && data[i]!='\n' && data[i]!=']') i++;
1882 if (i>=size || data[i]!=']') { return 0; }
1883 refid = data.substr(refIdStart,i-refIdStart);
1884 if (refid.isEmpty()) { return 0; }
1885 AUTO_TRACE_ADD("refid found {}",refid);
1886 //printf(" isLinkRef: found refid='%s'\n",qPrint(refid));
1887 i++;
1888 if (i>=size || data[i]!=':') { return 0; }
1889 i++;
1890
1891 // format: whitespace* \n? whitespace* (<url> | url)
1892 while (i<size && data[i]==' ') i++;
1893 if (i<size && data[i]=='\n')
1894 {
1895 i++;
1896 while (i<size && data[i]==' ') i++;
1897 }
1898 if (i>=size) { return 0; }
1899
1900 if (i<size && data[i]=='<') i++;
1901 size_t linkStart=i;
1902 while (i<size && data[i]!=' ' && data[i]!='\n') i++;
1903 size_t linkEnd=i;
1904 if (i<size && data[i]=='>') i++;
1905 if (linkStart==linkEnd) { return 0; } // empty link
1906 link = data.substr(linkStart,linkEnd-linkStart);
1907 AUTO_TRACE_ADD("link found {}",Trace::trunc(link));
1908 if (link=="@ref" || link=="\\ref")
1909 {
1910 size_t argStart=i;
1911 while (i<size && data[i]!='\n' && data[i]!='"') i++;
1912 link+=data.substr(argStart,i-argStart);
1913 }
1914
1915 title.clear();
1916
1917 // format: (whitespace* \n? whitespace* ( 'title' | "title" | (title) ))?
1918 size_t eol=0;
1919 while (i<size && data[i]==' ') i++;
1920 if (i<size && data[i]=='\n')
1921 {
1922 eol=i;
1923 i++;
1924 while (i<size && data[i]==' ') i++;
1925 }
1926 if (i>=size)
1927 {
1928 AUTO_TRACE_EXIT("result={}: end of isLinkRef while looking for title",i);
1929 return i; // end of buffer while looking for the optional title
1930 }
1931
1932 char c = data[i];
1933 if (c=='\'' || c=='"' || c=='(') // optional title present?
1934 {
1935 //printf(" start of title found! char='%c'\n",c);
1936 i++;
1937 if (c=='(') c=')'; // replace c by end character
1938 size_t titleStart=i;
1939 // search for end of the line
1940 while (i<size && data[i]!='\n') i++;
1941 eol = i;
1942
1943 // search back to matching character
1944 size_t end=i-1;
1945 while (end>titleStart && data[end]!=c) end--;
1946 if (end>titleStart)
1947 {
1948 title = data.substr(titleStart,end-titleStart);
1949 }
1950 AUTO_TRACE_ADD("title found {}",Trace::trunc(title));
1951 }
1952 while (i<size && data[i]==' ') i++;
1953 //printf("end of isLinkRef: i=%d size=%d data[i]='%c' eol=%d\n",
1954 // i,size,data[i],eol);
1955 if (i>=size) { AUTO_TRACE_EXIT("result={}",i); return i; } // end of buffer while ref id was found
1956 else if (eol>0) { AUTO_TRACE_EXIT("result={}",eol); return eol; } // end of line while ref id was found
1957 return 0; // invalid link ref
1958}

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

Referenced by Markdown::Private::processBlocks.

isListMarker()

size_t isListMarker (std::string_view data)
static

Definition at line 2182 of file markdown.cpp.

2182static size_t isListMarker(std::string_view data)
2183{
2184 AUTO_TRACE("data='{}'",Trace::trunc(data));
2185 size_t normalIndent = 0;
2186 while (normalIndent<data.size() && data[normalIndent]==' ') normalIndent++;
2187 size_t listIndent = computeIndentExcludingListMarkers(data);
2188 size_t result = listIndent>normalIndent ? listIndent : 0;
2189 AUTO_TRACE_EXIT("result={}",result);
2190 return result;
2191}

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

Referenced by Markdown::Private::processBlocks, Markdown::Private::processQuotations and Markdown::Private::writeBlockQuote.

isNewline()

size_t isNewline (std::string_view data)
inline

Definition at line 207 of file markdown.cpp.

207inline size_t isNewline(std::string_view data)
208{
209 // normal newline
210 if (data[0] == '\n') return 1;
211 // artificial new line from ^^ in ALIASES
212 if (literal_at(data,"\\ilinebr"))
213 {
214 return (data.size()>8 && data[8]==' ') ? 9 : 8; // also count space after \ilinebr if present
215 }
216 return 0;
217}

Reference literal_at.

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

isOtherPage()

bool isOtherPage (std::string_view data)
static

Definition at line 3437 of file markdown.cpp.

3437static bool isOtherPage(std::string_view data)
3438{
3439#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3440 OPC(dir); OPC(defgroup); OPC(addtogroup); OPC(weakgroup); OPC(ingroup);
3441 OPC(fn); OPC(property); OPC(typedef); OPC(var); OPC(def);
3442 OPC(enum); OPC(namespace); OPC(class); OPC(concept); OPC(module);
3443 OPC(protocol); OPC(category); OPC(union); OPC(struct); OPC(interface);
3444 OPC(idlexcept);
3445#undef OPC
3446
3447 return false;
3448}

Reference OPC.

Referenced by isExplicitPage.

isTableBlock()

bool isTableBlock (std::string_view data)
static

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

Definition at line 2439 of file markdown.cpp.

2439static bool isTableBlock(std::string_view data)
2440{
2441 AUTO_TRACE("data='{}'",Trace::trunc(data));
2442 size_t cc0=0, start=0, end=0;
2443
2444 // the first line should have at least two columns separated by '|'
2445 size_t i = findTableColumns(data,start,end,cc0);
2446 if (i>=data.size() || cc0<1)
2447 {
2448 AUTO_TRACE_EXIT("result=false: no |'s in the header");
2449 return FALSE;
2450 }
2451
2452 size_t cc1 = 0;
2453 size_t ret = findTableColumns(data.substr(i),start,end,cc1);
2454 size_t j=i+start;
2455 // separator line should consist of |, - and : and spaces only
2456 while (j<=end+i)
2457 {
2458 if (data[j]!=':' && data[j]!='-' && data[j]!='|' && data[j]!=' ')
2459 {
2460 AUTO_TRACE_EXIT("result=false: invalid character '{}'",data[j]);
2461 return FALSE; // invalid characters in table separator
2462 }
2463 j++;
2464 }
2465 if (cc1!=cc0) // number of columns should be same as previous line
2466 {
2467 AUTO_TRACE_EXIT("result=false: different number of columns as previous line {}!={}",cc1,cc0);
2468 return FALSE;
2469 }
2470
2471 i+=ret; // goto next line
2472 size_t cc2 = 0;
2473 findTableColumns(data.substr(i),start,end,cc2);
2474
2475 AUTO_TRACE_EXIT("result={}",cc1==cc2);
2476 return cc1==cc2;
2477}

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 3600 of file markdown.cpp.

3601{
3602 AUTO_TRACE("fileName={}",fileName);
3603 std::string absFileName = FileInfo(fileName.str()).absFilePath();
3604 QCString baseFn = stripFromPath(absFileName.c_str());
3605 int i = baseFn.findRev('.');
3606 if (i!=-1) baseFn = baseFn.left(i);
3607 QCString baseName = escapeCharsInString(baseFn,false,false);
3608 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3609 QCString res = "md_"+baseName;
3610 AUTO_TRACE_EXIT("result={}",res);
3611 return res;
3612}

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()

Alignment markersToAlignment (bool leftMarker, bool rightMarker)
static

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

Definition at line 292 of file markdown.cpp.

292static Alignment markersToAlignment(bool leftMarker,bool rightMarker)
293{
294 if (leftMarker && rightMarker)
295 {
296 return AlignCenter;
297 }
298 else if (leftMarker)
299 {
300 return AlignLeft;
301 }
302 else if (rightMarker)
303 {
304 return AlignRight;
305 }
306 else
307 {
308 return AlignNone;
309 }
310}

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 2876 of file markdown.cpp.

2876bool skipOverFileAndLineCommands(std::string_view data,size_t indent,size_t &offset,std::string &location)
2877{
2878 size_t i = offset;
2879 size_t size = data.size();
2880 while (i<data.size() && data[i]==' ') i++;
2881 if (literal_at(data.substr(i),"\\ifile \""))
2882 {
2883 size_t locStart = i;
2884 if (i>offset) locStart--; // include the space before \ifile
2885 i+=8;
2886 bool found=false;
2887 while (i+9<size && data[i]!='\n')
2888 {
2889 if (literal_at(data.substr(i),"\\ilinebr "))
2890 {
2891 found=true;
2892 break;
2893 }
2894 i++;
2895 }
2896 if (found)
2897 {
2898 i+=9;
2899 location=data.substr(locStart,i-locStart);
2900 location+='\n';
2901 while (indent>0 && i<size && data[i]==' ') i++,indent--;
2902 if (i<size && data[i]=='\n') i++;
2903 offset = i;
2904 return true;
2905 }
2906 }
2907 return false;
2908}

Reference literal_at.

Referenced by Markdown::Private::writeCodeBlock.

Variables

codeBlockIndent

const size_t codeBlockIndent = 4

g_doxy_nbsp

const char* g_doxy_nbsp = "&_doxy_nbsp;"

Definition at line 200 of file markdown.cpp.

200const char *g_doxy_nbsp = "&_doxy_nbsp;"; // doxygen escape command for UTF-8 nbsp

Referenced by Markdown::Private::addStrEscapeUtf8Nbsp and Markdown::process.

g_quotationHeaderMap

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

Definition at line 2749 of file markdown.cpp.

2749static const std::unordered_map<std::string,std::string> g_quotationHeaderMap = {
2750 // GitHub style Doxygen command
2751 { "[!note]", "\\note" },
2752 { "[!warning]", "\\warning" },
2753 { "[!tip]", "\\remark" },
2754 { "[!caution]", "\\attention" },
2755 { "[!important]", "\\important" }
2756};

Referenced by Markdown::Private::writeBlockQuote.

g_utf8_nbsp

const char* g_utf8_nbsp = "\xc2\xa0"

Definition at line 199 of file markdown.cpp.

199const char *g_utf8_nbsp = "\xc2\xa0"; // UTF-8 nbsp

Referenced by Markdown::Private::addStrEscapeUtf8Nbsp.

Macro Definitions

AUTO_TRACE

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

Definition at line 61 of file markdown.cpp.

61#define AUTO_TRACE(...) (void)0

Referenced by escapeDoubleQuotes, escapeSpecialChars and getFilteredImageAttributes.

AUTO_TRACE_ADD

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

Definition at line 62 of file markdown.cpp.

62#define AUTO_TRACE_ADD(...) (void)0

AUTO_TRACE_EXIT

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

Definition at line 63 of file markdown.cpp.

63#define AUTO_TRACE_EXIT(...) (void)0

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=='"' || 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=='_' || 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 2105 of file markdown.cpp.

2105#define isLiTag(i) \
2106 (data[(i)]=='<' && \
2107 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2108 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2109 (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.

OPC

#define OPC(x)   if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true

Definition at line 3439 of file markdown.cpp.

Referenced by isOtherPage.


Generated via doxygen2docusaurus by Doxygen 1.14.0.