Doxygen
Loading...
Searching...
No Matches
markdown.cpp File Reference
#include "markdown.h"
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "anchor.h"
#include "cmdmapper.h"
#include "commentscan.h"
#include "config.h"
#include "debug.h"
#include "doxygen.h"
#include "entry.h"
#include "filedef.h"
#include "fileinfo.h"
#include "filename.h"
#include "message.h"
#include "plantuml.h"
#include "portable.h"
#include "regex.h"
#include "section.h"
#include "stringutil.h"
#include "trace.h"
#include "util.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 isLiTag(i)
#define OPC(x)

Enumerations

enum class  ExplicitPageResult { explicitPage , explicitMainPage , explicitOtherPage , notExplicit }
enum class  Alignment { None , Left , Center , Right }

Functions

static constexpr bool isIdChar (char c)
static constexpr bool extraChar (char c)
static constexpr bool isOpenEmphChar (char c)
static constexpr bool isUtf8Nbsp (char c1, char c2)
static constexpr bool isAllowedEmphStr (const std::string_view &data, size_t offset)
static constexpr bool ignoreCloseEmphChar (char c, char cn)
size_t isNewline (std::string_view data)
static DString escapeDoubleQuotes (const DString &s)
static DString escapeSpecialChars (const DString &s)
static constexpr Alignment markersToAlignment (bool leftMarker, bool rightMarker)
 helper function to convert presence of left and/or right alignment markers to an alignment value
static DString getFilteredImageAttributes (std::string_view fmt, const DString &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, DString &refid, DString &link, DString &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, DString &lang, size_t &start, size_t &end, size_t &offset, DString &fileName, int lineNr)
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 bool isOtherPage (std::string_view data)
static ExplicitPageResult isExplicitPage (const DString &docs)
DString markdownFileNameToId (const DString &fileName)
 processes string s and converts markdown into doxygen/html commands.

Variables

static const char * g_utf8_nbsp = "\xc2\xa0"
static const char * g_doxy_nbsp = "&_doxy_nbsp;"
static 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 68 of file markdown.cpp.

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

◆ AUTO_TRACE_ADD

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

Definition at line 69 of file markdown.cpp.

◆ AUTO_TRACE_EXIT

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

Definition at line 70 of file markdown.cpp.

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

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

Referenced by computeIndentExcludingListMarkers().

◆ OPC

#define OPC ( x)
Value:
if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
bool literal_at(const char *data, const char(&str)[N])
returns true iff data points to a substring that matches string literal str
Definition stringutil.h:101

Referenced by isOtherPage().

Enumeration Type Documentation

◆ Alignment

enum class Alignment
strong
Enumerator
None 
Left 
Center 
Right 

Definition at line 219 of file markdown.cpp.

◆ ExplicitPageResult

enum class ExplicitPageResult
strong
Enumerator
explicitPage 

docs start with a page command

explicitMainPage 

docs start with a mainpage command

explicitOtherPage 

docs start with a dir / defgroup / addtogroup command

notExplicit 

docs doesn't start with either page or mainpage

Definition at line 73 of file markdown.cpp.

74{
75 explicitPage, /**< docs start with a page command */
76 explicitMainPage, /**< docs start with a mainpage command */
77 explicitOtherPage, /**< docs start with a dir / defgroup / addtogroup command */
78 notExplicit /**< docs doesn't start with either page or mainpage */
79};
@ explicitMainPage
docs start with a mainpage command
Definition markdown.cpp:76
@ explicitPage
docs start with a page command
Definition markdown.cpp:75
@ notExplicit
docs doesn't start with either page or mainpage
Definition markdown.cpp:78
@ explicitOtherPage
docs start with a dir / defgroup / addtogroup command
Definition markdown.cpp:77

Function Documentation

◆ computeIndentExcludingListMarkers()

size_t computeIndentExcludingListMarkers ( std::string_view data)
static

Definition at line 2259 of file markdown.cpp.

2260{
2261 AUTO_TRACE("data='{}'",Trace::trunc(data));
2262 size_t i=0;
2263 const size_t size=data.size();
2264 size_t indent=0;
2265 bool isDigit=false;
2266 bool isLi=false;
2267 bool listMarkerSkipped=false;
2268 while (i<size &&
2269 (data[i]==' ' || // space
2270 (!listMarkerSkipped && // first list marker
2271 (data[i]=='+' || data[i]=='-' || data[i]=='*' || // unordered list char
2272 (data[i]=='#' && i>0 && data[i-1]=='-') || // -# item
2273 (isDigit=(data[i]>='1' && data[i]<='9')) || // ordered list marker?
2274 (isLi=(size>=3 && i+3<size && isLiTag(i))) // <li> tag
2275 )
2276 )
2277 )
2278 )
2279 {
2280 if (isDigit) // skip over ordered list marker '10. '
2281 {
2282 size_t j=i+1;
2283 while (j<size && ((data[j]>='0' && data[j]<='9') || data[j]=='.'))
2284 {
2285 if (data[j]=='.') // should be end of the list marker
2286 {
2287 if (j+1<size && data[j+1]==' ') // valid list marker
2288 {
2289 listMarkerSkipped=true;
2290 indent+=j+1-i;
2291 i=j+1;
2292 break;
2293 }
2294 else // not a list marker
2295 {
2296 break;
2297 }
2298 }
2299 j++;
2300 }
2301 }
2302 else if (isLi)
2303 {
2304 i+=3; // skip over <li>
2305 indent+=3;
2306 listMarkerSkipped=true;
2307 }
2308 else if (data[i]=='-' && size>=2 && i+2<size && data[i+1]=='#' && data[i+2]==' ')
2309 { // case "-# "
2310 listMarkerSkipped=true; // only a single list marker is accepted
2311 i++; // skip over #
2312 indent++;
2313 }
2314 else if (data[i]!=' ' && i+1<size && data[i+1]==' ')
2315 { // case "- " or "+ " or "* "
2316 listMarkerSkipped=true; // only a single list marker is accepted
2317 }
2318 if (data[i]!=' ' && !listMarkerSkipped)
2319 { // end of indent
2320 break;
2321 }
2322 indent++;
2323 i++;
2324 }
2325 AUTO_TRACE_EXIT("result={}",indent);
2326 return indent;
2327}
#define AUTO_TRACE(...)
Definition markdown.cpp:68
#define AUTO_TRACE_EXIT(...)
Definition markdown.cpp:70
#define isLiTag(i)
DString trunc(const DString &s, size_t numChars=15)
Definition trace.h:56

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

Referenced by isCodeBlock(), and isListMarker().

◆ escapeDoubleQuotes()

DString escapeDoubleQuotes ( const DString & s)
static

Definition at line 245 of file markdown.cpp.

246{
247 AUTO_TRACE("s={}",Trace::trunc(s));
248 if (s.empty()) return s;
249 DString result;
250 const char *p=s.data();
251 char c=0, pc='\0';
252 while ((c=*p++))
253 {
254 if (c=='"' && pc!='\\') result+='\\';
255 result+=c;
256 pc=c;
257 }
258 AUTO_TRACE_EXIT("result={}",result);
259 return result;
260}
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:157

References AUTO_TRACE, AUTO_TRACE_EXIT, DString::data(), DString::empty(), and Trace::trunc().

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

◆ escapeSpecialChars()

DString escapeSpecialChars ( const DString & s)
static

Definition at line 263 of file markdown.cpp.

264{
265 AUTO_TRACE("s={}",Trace::trunc(s));
266 if (s.empty()) return s;
267 bool insideQuote=false;
268 DString result;
269 const char *p=s.data();
270 char c=0, pc='\0';
271 while ((c=*p++))
272 {
273 switch (c)
274 {
275 case '"':
276 if (pc!='\\')
277 {
278 if (Config_getBool(MARKDOWN_STRICT))
279 {
280 result+='\\';
281 }
282 else // For Doxygen's markup style a quoted text is left untouched
283 {
284 insideQuote=!insideQuote;
285 }
286 }
287 result+=c;
288 break;
289 case '<':
290 // fall through
291 case '>':
292 if (!insideQuote)
293 {
294 result+='\\';
295 result+=c;
296 if ((p[0]==':') && (p[1]==':'))
297 {
298 result+='\\';
299 result+=':';
300 p++;
301 }
302 }
303 else
304 {
305 result+=c;
306 }
307 break;
308 case '\\': if (!insideQuote) { result+='\\'; } result+='\\'; break;
309 case '@': if (!insideQuote) { result+='\\'; } result+='@'; break;
310 // commented out next line due to regression when using % to suppress a link
311 //case '%': if (!insideQuote) { result+='\\'; } result+='%'; break;
312 case '#': if (!insideQuote) { result+='\\'; } result+='#'; break;
313 case '$': if (!insideQuote) { result+='\\'; } result+='$'; break;
314 case '&': if (!insideQuote) { result+='\\'; } result+='&'; break;
315 default:
316 result+=c; break;
317 }
318 pc=c;
319 }
320 AUTO_TRACE_EXIT("result={}",result);
321 return result;
322}
#define Config_getBool(name)
Definition config.h:33

References AUTO_TRACE, AUTO_TRACE_EXIT, Config_getBool, DString::data(), DString::empty(), and Trace::trunc().

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

◆ extraChar()

constexpr bool extraChar ( char c)
staticconstexpr

Definition at line 93 of file markdown.cpp.

94{
95 return c=='-' || c=='+' || c=='!' || c=='?' || c=='$' || c=='@' ||
96 c=='&' || c=='*' || c=='_' || c=='%' || c=='[' || c=='(' ||
97 c=='.' || c=='>' || c==':' || c==',' || c==';' || c=='\'' ||
98 c=='"' || c=='`' || c=='\\';
99}

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

◆ 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]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 2565 of file markdown.cpp.

2566{
2567 AUTO_TRACE("data='{}'",Trace::trunc(data));
2568 const size_t size = data.size();
2569 size_t i=0,n=0;
2570 // find start character of the table line
2571 while (i<size && data[i]==' ') i++;
2572 if (i < size && data[i] == '|' && data[i] != '\n')
2573 {
2574 i++;
2575 n++; // leading | does not count
2576 }
2577 start = i;
2578
2579 // find end character of the table line
2580 size_t j = 0;
2581 while (i<size && (j = isNewline(data.substr(i)))==0) i++;
2582 size_t eol=i+j;
2583
2584 if (j>0 && i>0) i--; // move i to point before newline
2585 while (i>0 && data[i]==' ') i--;
2586 if (i > 0 && data[i - 1] != '\\' && data[i] == '|')
2587 {
2588 i--;
2589 n++; // trailing or escaped | does not count
2590 }
2591 end = i;
2592
2593 // count columns between start and end
2594 columns=0;
2595 if (end>start)
2596 {
2597 i=start;
2598 while (i<=end) // look for more column markers
2599 {
2600 if (data[i]=='|' && (i==0 || data[i-1]!='\\')) columns++;
2601 if (columns==1) columns++; // first | make a non-table into a two column table
2602 i++;
2603 }
2604 }
2605 if (n==2 && columns==0) // table row has | ... |
2606 {
2607 columns++;
2608 }
2609 AUTO_TRACE_EXIT("eol={} start={} end={} columns={}",eol,start,end,columns);
2610 return eol;
2611}
#define eol
The end of line string for this machine.
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:181
size_t isNewline(std::string_view data)
Definition markdown.cpp:232

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

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

◆ getFilteredImageAttributes()

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

parse the image attributes and return attributes for given format

Definition at line 348 of file markdown.cpp.

349{
350 AUTO_TRACE("fmt={} attrs={}",fmt,attrs);
351 StringVector attrList = split(attrs.str(),",");
352 for (const auto &attr_ : attrList)
353 {
354 DString attr = DString(attr_).stripWhiteSpace();
355 if (size_t i = attr.find(':'); i!=DString::npos && i>0) // has format
356 {
357 DString format = attr.left(i).stripWhiteSpace().lower();
358 if (format == fmt) // matching format
359 {
360 AUTO_TRACE_EXIT("result={}",attr.mid(i+1));
361 return attr.mid(i+1); // keep part after :
362 }
363 }
364 else // option that applies to all formats
365 {
366 AUTO_TRACE_EXIT("result={}",attr);
367 return attr;
368 }
369 }
370 return DString();
371}
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
DString lower() const
Definition dstring.h:326
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:178
size_t find(char c, size_t pos=0) const
Definition dstring.h:239
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition dstring.h:337
DString left(size_t len) const
Definition dstring.h:306
const std::string & str() const
Definition dstring.h:645
std::vector< std::string > StringVector
Definition containers.h:33
Definition message.h:146
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition stringutil.h:117

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

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

◆ hasLineBreak()

bool hasLineBreak ( std::string_view data)
static

Definition at line 2854 of file markdown.cpp.

2855{
2856 AUTO_TRACE("data='{}'",Trace::trunc(data));
2857 size_t i=0;
2858 size_t j=0;
2859 // search for end of line and also check if it is not a completely blank
2860 while (i<data.size() && data[i]!='\n')
2861 {
2862 if (data[i]!=' ' && data[i]!='\t') j++; // some non whitespace
2863 i++;
2864 }
2865 if (i>=data.size()) { return 0; } // empty line
2866 if (i<2) { return 0; } // not long enough
2867 bool res = (j>0 && data[i-1]==' ' && data[i-2]==' '); // non blank line with at two spaces at the end
2868 AUTO_TRACE_EXIT("result={}",res);
2869 return res;
2870}

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

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

◆ ignoreCloseEmphChar()

constexpr bool ignoreCloseEmphChar ( char c,
char cn )
staticconstexpr

Definition at line 123 of file markdown.cpp.

124{
125 return c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || c=='\\' || c=='@';
126}

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

◆ isAllowedEmphStr()

constexpr bool isAllowedEmphStr ( const std::string_view & data,
size_t offset )
staticconstexpr

Definition at line 115 of file markdown.cpp.

116{
117 return ((offset>0 && !isOpenEmphChar(data.data()[-1])) &&
118 (offset>1 && !isUtf8Nbsp(data.data()[-2],data.data()[-1])));
119}
static constexpr bool isOpenEmphChar(char c)
Definition markdown.cpp:102
static constexpr bool isUtf8Nbsp(char c1, char c2)
Definition markdown.cpp:110

References isOpenEmphChar(), and isUtf8Nbsp().

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

◆ isBlockQuote()

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

returns true if this line starts a block quote

Definition at line 1980 of file markdown.cpp.

1981{
1982 AUTO_TRACE("data='{}' indent={}",Trace::trunc(data),indent);
1983 size_t i = 0;
1984 const size_t size = data.size();
1985 while (i<size && data[i]==' ') i++;
1986 if (i<indent+codeBlockIndent) // could be a quotation
1987 {
1988 // count >'s and skip spaces
1989 int level=0;
1990 while (i<size && (data[i]=='>' || data[i]==' '))
1991 {
1992 if (data[i]=='>') level++;
1993 i++;
1994 }
1995 // last characters should be a space or newline,
1996 // so a line starting with >= does not match, but only when level equals 1
1997 bool res = (level>0 && i<size && ((data[i-1]==' ') || data[i]=='\n')) || (level > 1);
1998 AUTO_TRACE_EXIT("result={}",res);
1999 return res;
2000 }
2001 else // too much indentation -> code block
2002 {
2003 AUTO_TRACE_EXIT("result=false: too much indentation");
2004 return false;
2005 }
2006}
static const size_t codeBlockIndent
Definition markdown.cpp:226

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

2469{
2470 AUTO_TRACE("data='{}' offset={}",Trace::trunc(data),offset);
2471 //printf("<isCodeBlock(offset=%d,size=%d,indent=%d)\n",offset,size,indent);
2472 // determine the indent of this line
2473 size_t i=0;
2474 size_t indent0=0;
2475 const size_t size = data.size();
2476 while (i < size && data[i] == ' ')
2477 {
2478 indent0++;
2479 i++;
2480 }
2481
2482 if (indent0<codeBlockIndent)
2483 {
2484 AUTO_TRACE_EXIT("result={}: line is not indented enough {}<4",false,indent0);
2485 return false;
2486 }
2487 if (indent0>=size || data[indent0]=='\n') // empty line does not start a code block
2488 {
2489 AUTO_TRACE_EXIT("result={}: only spaces at the end of a comment block",false);
2490 return false;
2491 }
2492
2493 i=offset;
2494 int nl=0;
2495 int nl_pos[3];
2496 int offset_i = static_cast<int>(offset);
2497 // search back 3 lines and remember the start of lines -1 and -2
2498 while (i>0 && nl<3) // i counts down from offset to 1
2499 {
2500 int j = static_cast<int>(i)-offset_i-1; // j counts from -1 to -offset
2501 // since j can be negative we need to rewrap data in a std::string_view
2502 size_t nl_size = isNewline(std::string_view(data.data()+j,data.size()-j));
2503 if (nl_size>0)
2504 {
2505 nl_pos[nl++]=j+static_cast<int>(nl_size);
2506 }
2507 i--;
2508 }
2509
2510 // if there are only 2 preceding lines, then line -2 starts at -offset
2511 if (i==0 && nl==2) nl_pos[nl++]=-offset_i;
2512
2513 if (nl==3) // we have at least 2 preceding lines
2514 {
2515 //printf(" positions: nl_pos=[%d,%d,%d] line[-2]='%s' line[-1]='%s'\n",
2516 // nl_pos[0],nl_pos[1],nl_pos[2],
2517 // qPrint(DString(data+nl_pos[1]).left(nl_pos[0]-nl_pos[1]-1)),
2518 // qPrint(DString(data+nl_pos[2]).left(nl_pos[1]-nl_pos[2]-1)));
2519
2520 // check that line -1 is empty
2521 // Note that the offset is negative so we need to rewrap the string view
2522 if (!isEmptyLine(std::string_view(data.data()+nl_pos[1],nl_pos[0]-nl_pos[1]-1)))
2523 {
2524 AUTO_TRACE_EXIT("result={}",false);
2525 return false;
2526 }
2527
2528 // determine the indent of line -2
2529 // Note that the offset is negative so we need to rewrap the string view
2530 indent=std::max(indent,computeIndentExcludingListMarkers(
2531 std::string_view(data.data()+nl_pos[2],nl_pos[1]-nl_pos[2])));
2532
2533 //printf(">isCodeBlock local_indent %d>=%d+%d=%d\n",
2534 // indent0,indent,codeBlockIndent,indent0>=indent+codeBlockIndent);
2535 // if the difference is >4 spaces -> code block
2536 bool res = indent0>=indent+codeBlockIndent;
2537 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2538 return res;
2539 }
2540 else // not enough lines to determine the relative indent, use global indent
2541 {
2542 // check that line -1 is empty
2543 // Note that the offset is negative so we need to rewrap the string view
2544 if (nl==1 && !isEmptyLine(std::string_view(data.data()-offset,offset-1)))
2545 {
2546 AUTO_TRACE_EXIT("result=false");
2547 return false;
2548 }
2549 //printf(">isCodeBlock global indent %d>=%d+4=%d nl=%d\n",
2550 // indent0,indent,indent0>=indent+4,nl);
2551 bool res = indent0>=indent+codeBlockIndent;
2552 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2553 return res;
2554 }
2555}
static size_t computeIndentExcludingListMarkers(std::string_view data)
static bool isEmptyLine(std::string_view data)

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

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

◆ isEmptyLine()

bool isEmptyLine ( std::string_view data)
static

Definition at line 2237 of file markdown.cpp.

2238{
2239 AUTO_TRACE("data='{}'",Trace::trunc(data));
2240 size_t i=0;
2241 while (i<data.size())
2242 {
2243 if (data[i]=='\n') { AUTO_TRACE_EXIT("true"); return true; }
2244 if (data[i]!=' ') { AUTO_TRACE_EXIT("false"); return false; }
2245 i++;
2246 }
2247 AUTO_TRACE_EXIT("true");
2248 return true;
2249}

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

2341{
2342 AUTO_TRACE("data='{}'",Trace::trunc(data));
2343 int dots=0;
2344 size_t i=0;
2345 // end of list marker is an otherwise empty line with a dot.
2346 while (i<data.size())
2347 {
2348 if (data[i]=='.')
2349 {
2350 dots++;
2351 }
2352 else if (data[i]=='\n')
2353 {
2354 break;
2355 }
2356 else if (data[i]!=' ' && data[i]!='\t') // bail out if the line is not empty
2357 {
2358 AUTO_TRACE_EXIT("result=false");
2359 return false;
2360 }
2361 i++;
2362 }
2363 AUTO_TRACE_EXIT("result={}",dots==1);
2364 return dots==1;
2365}

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

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

◆ isExplicitPage()

ExplicitPageResult isExplicitPage ( const DString & docs)
static

Definition at line 3650 of file markdown.cpp.

3651{
3652 AUTO_TRACE("docs={}",Trace::trunc(docs));
3653 size_t i=0;
3654 std::string_view data(docs.str());
3655 const size_t size = data.size();
3656 if (!data.empty())
3657 {
3658 while (i<size && (data[i]==' ' || data[i]=='\n'))
3659 {
3660 i++;
3661 }
3662 if (literal_at(data.substr(i),"<!--!")) // skip over <!--! marker
3663 {
3664 i+=5;
3665 while (i<size && (data[i]==' ' || data[i]=='\n')) // skip over spaces after the <!--! marker
3666 {
3667 i++;
3668 }
3669 }
3670 if (i+1<size &&
3671 (data[i]=='\\' || data[i]=='@') &&
3672 (literal_at(data.substr(i+1),"page ") || literal_at(data.substr(i+1),"mainpage"))
3673 )
3674 {
3675 if (literal_at(data.substr(i+1),"page "))
3676 {
3677 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitPage");
3679 }
3680 else
3681 {
3682 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitMainPage");
3684 }
3685 }
3686 else if (i+1<size && (data[i]=='\\' || data[i]=='@') && isOtherPage(data.substr(i+1)))
3687 {
3688 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitOtherPage");
3690 }
3691 }
3692 AUTO_TRACE_EXIT("result=ExplicitPageResult::notExplicit");
3694}
static bool isOtherPage(std::string_view data)

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

Referenced by MarkdownOutlineParser::parseInput().

◆ isFencedCodeBlock()

bool isFencedCodeBlock ( std::string_view data,
size_t refIndent,
DString & lang,
size_t & start,
size_t & end,
size_t & offset,
DString & fileName,
int lineNr )
static

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

Definition at line 2367 of file markdown.cpp.

2370{
2371 AUTO_TRACE("data='{}' refIndent={}",Trace::trunc(data),refIndent);
2372 const char dot = '.';
2373 auto isAlphaChar = [ ](char c) { return (c>='A' && c<='Z') || (c>='a' && c<='z'); };
2374 auto isAlphaNChar = [ ](char c) { return (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || (c=='+'); };
2375 auto isLangChar = [&](char c) { return c==dot || isAlphaChar(c); };
2376 // rules: at least 3 ~~~, end of the block same amount of ~~~'s, otherwise
2377 // return false
2378 size_t i=0;
2379 size_t indent=0;
2380 int startTildes=0;
2381 const size_t size = data.size();
2382 while (i < size && data[i] == ' ')
2383 {
2384 indent++;
2385 i++;
2386 }
2387 if (indent>=refIndent+4)
2388 {
2389 AUTO_TRACE_EXIT("result=false: content is part of code block indent={} refIndent={}",indent,refIndent);
2390 return false;
2391 } // part of code block
2392 char tildaChar='~';
2393 if (i<size && data[i]=='`') tildaChar='`';
2394 while (i < size && data[i] == tildaChar)
2395 {
2396 startTildes++;
2397 i++;
2398 }
2399 if (startTildes<3)
2400 {
2401 AUTO_TRACE_EXIT("result=false: no fence marker found #tildes={}",startTildes);
2402 return false;
2403 } // not enough tildes
2404 // skip whitespace
2405 while (i<size && data[i]==' ') { i++; }
2406 if (i<size && data[i]=='{') // extract .py from ```{.py} ... ```
2407 {
2408 i++; // skip over {
2409 if (data[i] == dot) i++; // skip over initial dot
2410 size_t startLang=i;
2411 while (i<size && (data[i]!='\n' && data[i]!='}')) i++; // find matching }
2412 if (i<size && data[i]=='}')
2413 {
2414 lang = data.substr(startLang,i-startLang);
2415 i++;
2416 }
2417 else // missing closing bracket, treat `{` as part of the content
2418 {
2419 i=startLang-1;
2420 lang="";
2421 }
2422 }
2423 else if (i<size && isLangChar(data[i])) /// extract python or .py from ```python...``` or ```.py...```
2424 {
2425 if (data[i] == dot) i++; // skip over initial dot
2426 size_t startLang=i;
2427 if (i<size && isAlphaChar(data[i])) //check first character of language specifier
2428 {
2429 i++;
2430 while (i<size && isAlphaNChar(data[i])) i++; // find end of language specifier
2431 }
2432 lang = data.substr(startLang,i-startLang);
2433 }
2434 else // no language specified
2435 {
2436 lang="";
2437 }
2438
2439 start=i;
2440 while (i<size)
2441 {
2442 if (data[i]==tildaChar)
2443 {
2444 end=i;
2445 int endTildes=0;
2446 while (i < size && data[i] == tildaChar)
2447 {
2448 endTildes++;
2449 i++;
2450 }
2451 while (i<size && data[i]==' ') i++;
2452 {
2453 if (endTildes==startTildes)
2454 {
2455 offset=i;
2456 AUTO_TRACE_EXIT("result=true: found end marker at offset {} lang='{}'",offset,lang);
2457 return true;
2458 }
2459 }
2460 }
2461 i++;
2462 }
2463 warn(fileName, lineNr, "Ending Inside a fenced code block. Maybe the end marker for the block is missing?");
2464 AUTO_TRACE_EXIT("result=false: no end marker found lang={}'",lang);
2465 return false;
2466}
DString substr(size_t pos=0, size_t count=npos) const
Returns a substring of length count starting at pos.
Definition dstring.h:223
#define warn(file, line, fmt,...)
Definition message.h:97

References AUTO_TRACE, AUTO_TRACE_EXIT, end(), DString::substr(), Trace::trunc(), and warn.

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

◆ isHRuler()

bool isHRuler ( std::string_view data)
static

Definition at line 2098 of file markdown.cpp.

2099{
2100 AUTO_TRACE("data='{}'",Trace::trunc(data));
2101 size_t i=0;
2102 size_t size = data.size();
2103 if (size>0 && data[size-1]=='\n') size--; // ignore newline character
2104 while (i<size && data[i]==' ') i++;
2105 if (i>=size) { AUTO_TRACE_EXIT("result=false: empty line"); return false; } // empty line
2106 char c=data[i];
2107 if (c!='*' && c!='-' && c!='_')
2108 {
2109 AUTO_TRACE_EXIT("result=false: {} is not a hrule character",c);
2110 return false; // not a hrule character
2111 }
2112 int n=0;
2113 while (i<size)
2114 {
2115 if (data[i]==c)
2116 {
2117 n++; // count rule character
2118 }
2119 else if (data[i]!=' ')
2120 {
2121 AUTO_TRACE_EXIT("result=false: line contains non hruler characters");
2122 return false; // line contains non hruler characters
2123 }
2124 i++;
2125 }
2126 AUTO_TRACE_EXIT("result={}",n>=3);
2127 return n>=3; // at least 3 characters needed for a hruler
2128}

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

Referenced by Markdown::Private::writeBlockQuote(), and Markdown::Private::writeOneLineHeaderOrRuler().

◆ isIdChar()

constexpr bool isIdChar ( char c)
staticconstexpr

Definition at line 84 of file markdown.cpp.

85{
86 return (c>='a' && c<='z') ||
87 (c>='A' && c<='Z') ||
88 (c>='0' && c<='9') ||
89 (static_cast<unsigned char>(c)>=0x80); // unicode characters
90}

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

◆ isLinkRef()

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

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

Definition at line 2009 of file markdown.cpp.

2010{
2011 AUTO_TRACE("data='{}'",Trace::trunc(data));
2012 const size_t size = data.size();
2013 // format: start with [some text]:
2014 size_t i = 0;
2015 while (i<size && data[i]==' ') i++;
2016 if (i>=size || data[i]!='[') { return 0; }
2017 i++;
2018 size_t refIdStart=i;
2019 while (i<size && data[i]!='\n' && data[i]!=']') i++;
2020 if (i>=size || data[i]!=']') { return 0; }
2021 refid = data.substr(refIdStart,i-refIdStart);
2022 if (refid.empty()) { return 0; }
2023 AUTO_TRACE_ADD("refid found {}",refid);
2024 //printf(" isLinkRef: found refid='%s'\n",qPrint(refid));
2025 i++;
2026 if (i>=size || data[i]!=':') { return 0; }
2027 i++;
2028
2029 // format: whitespace* \n? whitespace* (<url> | url)
2030 while (i<size && data[i]==' ') i++;
2031 if (i<size && data[i]=='\n')
2032 {
2033 i++;
2034 while (i<size && data[i]==' ') i++;
2035 }
2036 if (i>=size) { return 0; }
2037
2038 if (i<size && data[i]=='<') i++;
2039 size_t linkStart=i;
2040 while (i<size && data[i]!=' ' && data[i]!='\n') i++;
2041 size_t linkEnd=i;
2042 if (i<size && data[i]=='>') i++;
2043 if (linkStart==linkEnd) { return 0; } // empty link
2044 link = data.substr(linkStart,linkEnd-linkStart);
2045 AUTO_TRACE_ADD("link found {}",Trace::trunc(link));
2046 if (link=="@ref" || link=="\\ref")
2047 {
2048 size_t argStart=i;
2049 while (i<size && data[i]!='\n' && data[i]!='"') i++;
2050 link+=data.substr(argStart,i-argStart);
2051 }
2052
2053 title.clear();
2054
2055 // format: (whitespace* \n? whitespace* ( 'title' | "title" | (title) ))?
2056 size_t eol=0;
2057 while (i<size && data[i]==' ') i++;
2058 if (i<size && data[i]=='\n')
2059 {
2060 eol=i;
2061 i++;
2062 while (i<size && data[i]==' ') i++;
2063 }
2064 if (i>=size)
2065 {
2066 AUTO_TRACE_EXIT("result={}: end of isLinkRef while looking for title",i);
2067 return i; // end of buffer while looking for the optional title
2068 }
2069
2070 char c = data[i];
2071 if (c=='\'' || c=='"' || c=='(') // optional title present?
2072 {
2073 //printf(" start of title found! char='%c'\n",c);
2074 i++;
2075 if (c=='(') c=')'; // replace c by end character
2076 size_t titleStart=i;
2077 // search for end of the line
2078 while (i<size && data[i]!='\n') i++;
2079 eol = i;
2080
2081 // search back to matching character
2082 size_t end=i-1;
2083 while (end>titleStart && data[end]!=c) end--;
2084 if (end>titleStart)
2085 {
2086 title = data.substr(titleStart,end-titleStart);
2087 }
2088 AUTO_TRACE_ADD("title found {}",Trace::trunc(title));
2089 }
2090 while (i<size && data[i]==' ') i++;
2091 //printf("end of isLinkRef: i=%d size=%d data[i]='%c' eol=%d\n",
2092 // i,size,data[i],eol);
2093 if (i>=size) { AUTO_TRACE_EXIT("result={}",i); return i; } // end of buffer while ref id was found
2094 else if (eol>0) { AUTO_TRACE_EXIT("result={}",eol); return eol; } // end of line while ref id was found
2095 return 0; // invalid link ref
2096}
void clear()
Definition dstring.h:214
#define AUTO_TRACE_ADD(...)
Definition markdown.cpp:69

References AUTO_TRACE, AUTO_TRACE_ADD, AUTO_TRACE_EXIT, DString::clear(), DString::empty(), end(), eol, DString::substr(), and Trace::trunc().

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

◆ isListMarker()

size_t isListMarker ( std::string_view data)
static

Definition at line 2329 of file markdown.cpp.

2330{
2331 AUTO_TRACE("data='{}'",Trace::trunc(data));
2332 size_t normalIndent = 0;
2333 while (normalIndent<data.size() && data[normalIndent]==' ') normalIndent++;
2334 size_t listIndent = computeIndentExcludingListMarkers(data);
2335 size_t result = listIndent>normalIndent ? listIndent : 0;
2336 AUTO_TRACE_EXIT("result={}",result);
2337 return result;
2338}

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

233{
234 // normal newline
235 if (data[0] == '\n') return 1;
236 // artificial new line from ^^ in ALIASES
237 if (literal_at(data,"\\ilinebr"))
238 {
239 return (data.size()>8 && data[8]==' ') ? 9 : 8; // also count space after \ilinebr if present
240 }
241 return 0;
242}

References literal_at().

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

◆ isOpenEmphChar()

constexpr bool isOpenEmphChar ( char c)
staticconstexpr

Definition at line 102 of file markdown.cpp.

103{
104 return c=='\n' || c==' ' || c=='\'' || c=='<' ||
105 c=='>' || c=='{' || c=='(' || c=='[' ||
106 c==',' || c==':' || c==';';
107}

Referenced by isAllowedEmphStr().

◆ isOtherPage()

bool isOtherPage ( std::string_view data)
static

Definition at line 3637 of file markdown.cpp.

3638{
3639#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3640 OPC(dir); OPC(defgroup); OPC(addtogroup); OPC(weakgroup); OPC(ingroup);
3641 OPC(fn); OPC(property); OPC(typedef); OPC(var); OPC(def);
3642 OPC(enum); OPC(namespace); OPC(class); OPC(concept); OPC(module);
3643 OPC(protocol); OPC(category); OPC(union); OPC(struct); OPC(interface);
3644 OPC(idlexcept); OPC(file);
3645#undef OPC
3646
3647 return false;
3648}
#define OPC(x)

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

2615{
2616 AUTO_TRACE("data='{}'",Trace::trunc(data));
2617 size_t cc0=0, start=0, end=0;
2618
2619 // the first line should have at least two columns separated by '|'
2620 size_t i = findTableColumns(data,start,end,cc0);
2621 if (i>=data.size() || cc0<1)
2622 {
2623 AUTO_TRACE_EXIT("result=false: no |'s in the header");
2624 return false;
2625 }
2626
2627 size_t cc1 = 0;
2628 size_t ret = findTableColumns(data.substr(i),start,end,cc1);
2629 size_t j=i+start;
2630 // separator line should consist of |, - and : and spaces only
2631 while (j<=end+i)
2632 {
2633 if (data[j]!=':' && data[j]!='-' && data[j]!='|' && data[j]!=' ')
2634 {
2635 AUTO_TRACE_EXIT("result=false: invalid character '{}'",data[j]);
2636 return false; // invalid characters in table separator
2637 }
2638 j++;
2639 }
2640 if (cc1!=cc0) // number of columns should be same as previous line
2641 {
2642 AUTO_TRACE_EXIT("result=false: different number of columns as previous line {}!={}",cc1,cc0);
2643 return false;
2644 }
2645
2646 i+=ret; // goto next line
2647 size_t cc2 = 0;
2648 findTableColumns(data.substr(i),start,end,cc2);
2649
2650 AUTO_TRACE_EXIT("result={}",cc1==cc2);
2651 return cc1==cc2;
2652}
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(), findTableColumns(), and Trace::trunc().

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

◆ isUtf8Nbsp()

constexpr bool isUtf8Nbsp ( char c1,
char c2 )
staticconstexpr

Definition at line 110 of file markdown.cpp.

111{
112 return c1==static_cast<char>(0xc2) && c2==static_cast<char>(0xa0);
113}

Referenced by isAllowedEmphStr().

◆ markdownFileNameToId()

DString markdownFileNameToId ( const DString & fileName)

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

Definition at line 3800 of file markdown.cpp.

3801{
3802 AUTO_TRACE("fileName={}",fileName);
3803 DString absFileName = FileInfo(fileName.str()).absFilePath();
3804 DString baseFn = stripFromPath(absFileName);
3805 if (size_t i = baseFn.rfind('.'); i!=DString::npos) baseFn = baseFn.left(i);
3806 DString baseName = escapeCharsInString(baseFn,false,false);
3807 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3808 DString res = "md_"+baseName;
3809 AUTO_TRACE_EXIT("result={}",res);
3810 return res;
3811}
size_t rfind(char c, size_t pos=npos) const
Definition dstring.h:244
Minimal replacement for QFileInfo.
Definition fileinfo.h:26
std::string absFilePath() const
Definition fileinfo.cpp:105
DString escapeCharsInString(const DString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:2688
DString stripFromPath(const DString &path)
Definition util.cpp:219

References FileInfo::absFilePath(), AUTO_TRACE, AUTO_TRACE_EXIT, escapeCharsInString(), DString::left(), DString::npos, DString::rfind(), DString::str(), and stripFromPath().

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

◆ markersToAlignment()

constexpr Alignment markersToAlignment ( bool leftMarker,
bool rightMarker )
staticconstexpr

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

Definition at line 327 of file markdown.cpp.

328{
329 if (leftMarker && rightMarker)
330 {
331 return Alignment::Center;
332 }
333 else if (leftMarker)
334 {
335 return Alignment::Left;
336 }
337 else if (rightMarker)
338 {
339 return Alignment::Right;
340 }
341 else
342 {
343 return Alignment::None;
344 }
345}

References Center, Left, None, and Right.

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

◆ skipOverFileAndLineCommands()

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

Definition at line 3051 of file markdown.cpp.

3052{
3053 size_t i = offset;
3054 size_t size = data.size();
3055 while (i<data.size() && data[i]==' ') i++;
3056 if (literal_at(data.substr(i),"\\ifile \""))
3057 {
3058 size_t locStart = i;
3059 if (i>offset) locStart--; // include the space before \ifile
3060 i+=8;
3061 bool found=false;
3062 while (i+9<size && data[i]!='\n')
3063 {
3064 if (literal_at(data.substr(i),"\\ilinebr "))
3065 {
3066 found=true;
3067 break;
3068 }
3069 i++;
3070 }
3071 if (found)
3072 {
3073 i+=9;
3074 location=data.substr(locStart,i-locStart);
3075 location+='\n';
3076 while (indent > 0 && i < size && data[i] == ' ')
3077 {
3078 i++;
3079 indent--;
3080 }
3081 if (i<size && data[i]=='\n') i++;
3082 offset = i;
3083 return true;
3084 }
3085 }
3086 return false;
3087}

References literal_at().

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

Variable Documentation

◆ codeBlockIndent

const size_t codeBlockIndent = 4
static

◆ g_doxy_nbsp

const char* g_doxy_nbsp = "&_doxy_nbsp;"
static

Definition at line 225 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 2924 of file markdown.cpp.

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

◆ g_utf8_nbsp

const char* g_utf8_nbsp = "\xc2\xa0"
static

Definition at line 224 of file markdown.cpp.

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