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 "fileinfo.h"
#include "trace.h"
#include "anchor.h"
#include "stringutil.h"
Include dependency graph for markdown.cpp:

Go to the source code of this file.

Classes

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

Macros

#define AUTO_TRACE(...)
#define AUTO_TRACE_ADD(...)
#define AUTO_TRACE_EXIT(...)
#define 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 QCString escapeDoubleQuotes (const QCString &s)
static QCString escapeSpecialChars (const QCString &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 QCString getFilteredImageAttributes (std::string_view fmt, const QCString &attrs)
 parse the image attributes and return attributes for given format
static bool isBlockQuote (std::string_view data, size_t indent)
 returns true if this line starts a block quote
static size_t isLinkRef (std::string_view data, QCString &refid, QCString &link, QCString &title)
 returns end of the link ref if this is indeed a link reference.
static bool isHRuler (std::string_view data)
static bool isEmptyLine (std::string_view data)
static size_t computeIndentExcludingListMarkers (std::string_view data)
static size_t isListMarker (std::string_view data)
static bool isEndOfList (std::string_view data)
static bool isFencedCodeBlock (std::string_view data, size_t refIndent, QCString &lang, size_t &start, size_t &end, size_t &offset, QCString &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 QCString &docs)
QCString markdownFileNameToId (const QCString &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 63 of file markdown.cpp.

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

◆ AUTO_TRACE_ADD

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

Definition at line 64 of file markdown.cpp.

◆ AUTO_TRACE_EXIT

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

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

2243#define isLiTag(i) \
2244 (data[(i)]=='<' && \
2245 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2246 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2247 (data[(i)+3]=='>'))

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:98

Referenced by isOtherPage().

Enumeration Type Documentation

◆ Alignment

enum class Alignment
strong
Enumerator
None 
Left 
Center 
Right 

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

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

Function Documentation

◆ computeIndentExcludingListMarkers()

size_t computeIndentExcludingListMarkers ( std::string_view data)
static

Definition at line 2251 of file markdown.cpp.

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

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

Referenced by isCodeBlock(), and isListMarker().

◆ escapeDoubleQuotes()

QCString escapeDoubleQuotes ( const QCString & s)
static

Definition at line 240 of file markdown.cpp.

241{
242 AUTO_TRACE("s={}",Trace::trunc(s));
243 if (s.isEmpty()) return s;
244 QCString result;
245 const char *p=s.data();
246 char c=0, pc='\0';
247 while ((c=*p++))
248 {
249 if (c=='"' && pc!='\\') result+='\\';
250 result+=c;
251 pc=c;
252 }
253 AUTO_TRACE_EXIT("result={}",result);
254 return result;
255}
This is an alternative implementation of QCString.
Definition qcstring.h:103
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:167
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:176

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

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

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

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

◆ extraChar()

constexpr bool extraChar ( char c)
staticconstexpr

Definition at line 88 of file markdown.cpp.

89{
90 return c=='-' || c=='+' || c=='!' || c=='?' || c=='$' || c=='@' ||
91 c=='&' || c=='*' || c=='_' || c=='%' || c=='[' || c=='(' ||
92 c=='.' || c=='>' || c==':' || c==',' || c==';' || c=='\'' ||
93 c=='"' || c=='`' || c=='\\';
94}

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

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

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

344{
345 AUTO_TRACE("fmt={} attrs={}",fmt,attrs);
346 StringVector attrList = split(attrs.str(),",");
347 for (const auto &attr_ : attrList)
348 {
349 QCString attr = QCString(attr_).stripWhiteSpace();
350 int i = attr.find(':');
351 if (i>0) // has format
352 {
353 QCString format = attr.left(i).stripWhiteSpace().lower();
354 if (format == fmt) // matching format
355 {
356 AUTO_TRACE_EXIT("result={}",attr.mid(i+1));
357 return attr.mid(i+1); // keep part after :
358 }
359 }
360 else // option that applies to all formats
361 {
362 AUTO_TRACE_EXIT("result={}",attr);
363 return attr;
364 }
365 }
366 return QCString();
367}
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:245
QCString lower() const
Definition qcstring.h:253
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:264
const std::string & str() const
Definition qcstring.h:556
QCString left(size_t len) const
Definition qcstring.h:233
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 util.cpp:6636

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

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

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

119{
120 return c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || c=='\\' || c=='@';
121}

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

◆ isAllowedEmphStr()

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

Definition at line 110 of file markdown.cpp.

111{
112 return ((offset>0 && !isOpenEmphChar(data.data()[-1])) &&
113 (offset>1 && !isUtf8Nbsp(data.data()[-2],data.data()[-1])));
114}
static constexpr bool isOpenEmphChar(char c)
Definition markdown.cpp:97
static constexpr bool isUtf8Nbsp(char c1, char c2)
Definition markdown.cpp:105

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

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

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

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

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

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

◆ isEmptyLine()

bool isEmptyLine ( std::string_view data)
static

Definition at line 2229 of file markdown.cpp.

2230{
2231 AUTO_TRACE("data='{}'",Trace::trunc(data));
2232 size_t i=0;
2233 while (i<data.size())
2234 {
2235 if (data[i]=='\n') { AUTO_TRACE_EXIT("true"); return true; }
2236 if (data[i]!=' ') { AUTO_TRACE_EXIT("false"); return false; }
2237 i++;
2238 }
2239 AUTO_TRACE_EXIT("true");
2240 return true;
2241}

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

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

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

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

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,
QCString & fileName,
int lineNr )
static

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

Definition at line 2359 of file markdown.cpp.

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

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

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

◆ isHRuler()

bool isHRuler ( std::string_view data)
static

Definition at line 2090 of file markdown.cpp.

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

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

80{
81 return (c>='a' && c<='z') ||
82 (c>='A' && c<='Z') ||
83 (c>='0' && c<='9') ||
84 (static_cast<unsigned char>(c)>=0x80); // unicode characters
85}

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

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

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

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

2322{
2323 AUTO_TRACE("data='{}'",Trace::trunc(data));
2324 size_t normalIndent = 0;
2325 while (normalIndent<data.size() && data[normalIndent]==' ') normalIndent++;
2326 size_t listIndent = computeIndentExcludingListMarkers(data);
2327 size_t result = listIndent>normalIndent ? listIndent : 0;
2328 AUTO_TRACE_EXIT("result={}",result);
2329 return result;
2330}

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

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

References literal_at().

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

◆ isOpenEmphChar()

constexpr bool isOpenEmphChar ( char c)
staticconstexpr

Definition at line 97 of file markdown.cpp.

98{
99 return c=='\n' || c==' ' || c=='\'' || c=='<' ||
100 c=='>' || c=='{' || c=='(' || c=='[' ||
101 c==',' || c==':' || c==';';
102}

Referenced by isAllowedEmphStr().

◆ isOtherPage()

bool isOtherPage ( std::string_view data)
static

Definition at line 3628 of file markdown.cpp.

3629{
3630#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3631 OPC(dir); OPC(defgroup); OPC(addtogroup); OPC(weakgroup); OPC(ingroup);
3632 OPC(fn); OPC(property); OPC(typedef); OPC(var); OPC(def);
3633 OPC(enum); OPC(namespace); OPC(class); OPC(concept); OPC(module);
3634 OPC(protocol); OPC(category); OPC(union); OPC(struct); OPC(interface);
3635 OPC(idlexcept); OPC(file);
3636#undef OPC
3637
3638 return false;
3639}
#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 2606 of file markdown.cpp.

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

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

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

◆ isUtf8Nbsp()

constexpr bool isUtf8Nbsp ( char c1,
char c2 )
staticconstexpr

Definition at line 105 of file markdown.cpp.

106{
107 return c1==static_cast<char>(0xc2) && c2==static_cast<char>(0xa0);
108}

Referenced by isAllowedEmphStr().

◆ markdownFileNameToId()

QCString markdownFileNameToId ( const QCString & fileName)

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

Definition at line 3791 of file markdown.cpp.

3792{
3793 AUTO_TRACE("fileName={}",fileName);
3794 QCString absFileName = FileInfo(fileName.str()).absFilePath();
3795 QCString baseFn = stripFromPath(absFileName);
3796 int i = baseFn.findRev('.');
3797 if (i!=-1) baseFn = baseFn.left(i);
3798 QCString baseName = escapeCharsInString(baseFn,false,false);
3799 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3800 QCString res = "md_"+baseName;
3801 AUTO_TRACE_EXIT("result={}",res);
3802 return res;
3803}
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
std::string absFilePath() const
Definition fileinfo.cpp:101
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:96
QCString escapeCharsInString(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3350
static QCString stripFromPath(const QCString &p, const StringVector &l)
Definition util.cpp:298

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

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

323{
324 if (leftMarker && rightMarker)
325 {
326 return Alignment::Center;
327 }
328 else if (leftMarker)
329 {
330 return Alignment::Left;
331 }
332 else if (rightMarker)
333 {
334 return Alignment::Right;
335 }
336 else
337 {
338 return Alignment::None;
339 }
340}

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

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

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

2916 {
2917 // GitHub style Doxygen command
2918 { "[!note]", "\\note" },
2919 { "[!warning]", "\\warning" },
2920 { "[!tip]", "\\remark" },
2921 { "[!caution]", "\\attention" },
2922 { "[!important]", "\\important" }
2923};

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

◆ g_utf8_nbsp

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

Definition at line 219 of file markdown.cpp.

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