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 "commentcnv.h"
#include "cmdmapper.h"
#include "config.h"
#include "message.h"
#include "portable.h"
#include "regex.h"
#include "filedef.h"
#include "fileinfo.h"
#include "trace.h"
#include "anchor.h"
#include "stringutil.h"
#include "filename.h"
#include "section.h"
#include "plantuml.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 67 of file markdown.cpp.

◆ AUTO_TRACE_ADD

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

Definition at line 68 of file markdown.cpp.

◆ AUTO_TRACE_EXIT

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

Definition at line 69 of file markdown.cpp.

◆ 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 2250 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 218 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 72 of file markdown.cpp.

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

Function Documentation

◆ computeIndentExcludingListMarkers()

size_t computeIndentExcludingListMarkers ( std::string_view data)
static

Definition at line 2258 of file markdown.cpp.

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

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

Referenced by computeIndentExcludingListMarkers(), isCodeBlock(), and isListMarker().

◆ escapeDoubleQuotes()

DString escapeDoubleQuotes ( const DString & s)
static

Definition at line 244 of file markdown.cpp.

245{
246 AUTO_TRACE("s={}",Trace::trunc(s));
247 if (s.empty()) return s;
248 DString result;
249 const char *p=s.data();
250 char c=0, pc='\0';
251 while ((c=*p++))
252 {
253 if (c=='"' && pc!='\\') result+='\\';
254 result+=c;
255 pc=c;
256 }
257 AUTO_TRACE_EXIT("result={}",result);
258 return result;
259}
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:89
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:153
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:162

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

Referenced by escapeDoubleQuotes(), and Markdown::Private::writeMarkdownImage().

◆ escapeSpecialChars()

DString escapeSpecialChars ( const DString & s)
static

Definition at line 262 of file markdown.cpp.

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

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

Referenced by escapeSpecialChars(), and Markdown::Private::processCodeSpan().

◆ extraChar()

constexpr bool extraChar ( char c)
staticconstexpr

Definition at line 92 of file markdown.cpp.

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

References extraChar().

Referenced by extraChar(), and 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 2564 of file markdown.cpp.

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

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

Referenced by findTableColumns(), 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 347 of file markdown.cpp.

348{
349 AUTO_TRACE("fmt={} attrs={}",fmt,attrs);
350 StringVector attrList = split(attrs.str(),",");
351 for (const auto &attr_ : attrList)
352 {
353 DString attr = DString(attr_).stripWhiteSpace();
354 if (size_t i = attr.find(':'); i!=DString::npos && i>0) // has format
355 {
356 DString format = attr.left(i).stripWhiteSpace().lower();
357 if (format == fmt) // matching format
358 {
359 AUTO_TRACE_EXIT("result={}",attr.mid(i+1));
360 return attr.mid(i+1); // keep part after :
361 }
362 }
363 else // option that applies to all formats
364 {
365 AUTO_TRACE_EXIT("result={}",attr);
366 return attr;
367 }
368 }
369 return DString();
370}
DString()=default
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:323
DString lower() const
Definition dstring.h:331
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:183
size_t find(char c, size_t pos=0) const
Definition dstring.h:244
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition dstring.h:342
DString left(size_t len) const
Definition dstring.h:311
const std::string & str() const
Definition dstring.h:650
std::vector< std::string > StringVector
Definition containers.h:33
Definition message.h:144
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::DString(), DString::find(), getFilteredImageAttributes(), DString::left(), DString::lower(), DString::mid(), DString::npos, split(), DString::str(), and DString::stripWhiteSpace().

Referenced by getFilteredImageAttributes(), and Markdown::Private::writeMarkdownImage().

◆ hasLineBreak()

bool hasLineBreak ( std::string_view data)
static

Definition at line 2853 of file markdown.cpp.

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

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

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

◆ ignoreCloseEmphChar()

constexpr bool ignoreCloseEmphChar ( char c,
char cn )
staticconstexpr

Definition at line 122 of file markdown.cpp.

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

References ignoreCloseEmphChar().

Referenced by Markdown::Private::findEmphasisChar(), and ignoreCloseEmphChar().

◆ isAllowedEmphStr()

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

Definition at line 114 of file markdown.cpp.

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

References isAllowedEmphStr(), isOpenEmphChar(), and isUtf8Nbsp().

Referenced by isAllowedEmphStr(), and 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 1979 of file markdown.cpp.

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

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

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

◆ isCodeBlock()

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

Definition at line 2467 of file markdown.cpp.

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

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

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

◆ isEmptyLine()

bool isEmptyLine ( std::string_view data)
static

Definition at line 2236 of file markdown.cpp.

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

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

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

◆ isEndOfList()

bool isEndOfList ( std::string_view data)
static

Definition at line 2339 of file markdown.cpp.

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

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

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

◆ isExplicitPage()

ExplicitPageResult isExplicitPage ( const DString & docs)
static

Definition at line 3649 of file markdown.cpp.

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

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

Referenced by isExplicitPage(), and 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 2366 of file markdown.cpp.

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

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

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

◆ isHRuler()

bool isHRuler ( std::string_view data)
static

Definition at line 2097 of file markdown.cpp.

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

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

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

◆ isIdChar()

constexpr bool isIdChar ( char c)
staticconstexpr

Definition at line 83 of file markdown.cpp.

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

References isIdChar().

Referenced by Markdown::Private::findEmphasisChar(), isIdChar(), 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 2008 of file markdown.cpp.

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

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

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

◆ isListMarker()

size_t isListMarker ( std::string_view data)
static

Definition at line 2328 of file markdown.cpp.

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

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

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

◆ isNewline()

size_t isNewline ( std::string_view data)
inline

Definition at line 231 of file markdown.cpp.

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

References isNewline(), and literal_at().

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

◆ isOpenEmphChar()

constexpr bool isOpenEmphChar ( char c)
staticconstexpr

Definition at line 101 of file markdown.cpp.

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

References isOpenEmphChar().

Referenced by isAllowedEmphStr(), and isOpenEmphChar().

◆ isOtherPage()

bool isOtherPage ( std::string_view data)
static

Definition at line 3636 of file markdown.cpp.

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

References isOtherPage(), and OPC.

Referenced by isExplicitPage(), and isOtherPage().

◆ isTableBlock()

bool isTableBlock ( std::string_view data)
static

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

Definition at line 2613 of file markdown.cpp.

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

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

◆ isUtf8Nbsp()

constexpr bool isUtf8Nbsp ( char c1,
char c2 )
staticconstexpr

Definition at line 109 of file markdown.cpp.

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

References isUtf8Nbsp().

Referenced by isAllowedEmphStr(), and isUtf8Nbsp().

◆ markdownFileNameToId()

DString markdownFileNameToId ( const DString & fileName)

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

Definition at line 3799 of file markdown.cpp.

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

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

Referenced by DocRef::DocRef(), markdownFileNameToId(), 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 326 of file markdown.cpp.

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

References Center, Left, markersToAlignment(), None, and Right.

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

◆ skipOverFileAndLineCommands()

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

Definition at line 3050 of file markdown.cpp.

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

References literal_at(), and skipOverFileAndLineCommands().

Referenced by skipOverFileAndLineCommands(), and 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 224 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 2923 of file markdown.cpp.

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

◆ g_utf8_nbsp

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

Definition at line 223 of file markdown.cpp.

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