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

2236#define isLiTag(i) \
2237 (data[(i)]=='<' && \
2238 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2239 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2240 (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 2244 of file markdown.cpp.

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

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

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

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

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

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

2223{
2224 AUTO_TRACE("data='{}'",Trace::trunc(data));
2225 size_t i=0;
2226 while (i<data.size())
2227 {
2228 if (data[i]=='\n') { AUTO_TRACE_EXIT("true"); return true; }
2229 if (data[i]!=' ') { AUTO_TRACE_EXIT("false"); return false; }
2230 i++;
2231 }
2232 AUTO_TRACE_EXIT("true");
2233 return true;
2234}

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

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

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

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

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

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

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

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

2315{
2316 AUTO_TRACE("data='{}'",Trace::trunc(data));
2317 size_t normalIndent = 0;
2318 while (normalIndent<data.size() && data[normalIndent]==' ') normalIndent++;
2319 size_t listIndent = computeIndentExcludingListMarkers(data);
2320 size_t result = listIndent>normalIndent ? listIndent : 0;
2321 AUTO_TRACE_EXIT("result={}",result);
2322 return result;
2323}

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

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

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

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

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

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

2909 {
2910 // GitHub style Doxygen command
2911 { "[!note]", "\\note" },
2912 { "[!warning]", "\\warning" },
2913 { "[!tip]", "\\remark" },
2914 { "[!caution]", "\\attention" },
2915 { "[!important]", "\\important" }
2916};

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