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

2241#define isLiTag(i) \
2242 (data[(i)]=='<' && \
2243 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2244 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2245 (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 2249 of file markdown.cpp.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3790{
3791 AUTO_TRACE("fileName={}",fileName);
3792 QCString absFileName = FileInfo(fileName.str()).absFilePath();
3793 QCString baseFn = stripFromPath(absFileName);
3794 int i = baseFn.findRev('.');
3795 if (i!=-1) baseFn = baseFn.left(i);
3796 QCString baseName = escapeCharsInString(baseFn,false,false);
3797 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3798 QCString res = "md_"+baseName;
3799 AUTO_TRACE_EXIT("result={}",res);
3800 return res;
3801}
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 3041 of file markdown.cpp.

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

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

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

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