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

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

◆ AUTO_TRACE_ADD

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

Definition at line 62 of file markdown.cpp.

◆ AUTO_TRACE_EXIT

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

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

2214#define isLiTag(i) \
2215 (data[(i)]=='<' && \
2216 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2217 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2218 (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 212 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 66 of file markdown.cpp.

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

Function Documentation

◆ computeIndentExcludingListMarkers()

size_t computeIndentExcludingListMarkers ( 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 const size_t size=data.size();
2227 size_t indent=0;
2228 bool isDigit=FALSE;
2229 bool isLi=FALSE;
2230 bool listMarkerSkipped=FALSE;
2231 while (i<size &&
2232 (data[i]==' ' || // space
2233 (!listMarkerSkipped && // first list marker
2234 (data[i]=='+' || data[i]=='-' || data[i]=='*' || // unordered list char
2235 (data[i]=='#' && i>0 && data[i-1]=='-') || // -# item
2236 (isDigit=(data[i]>='1' && data[i]<='9')) || // ordered list marker?
2237 (isLi=(size>=3 && i+3<size && isLiTag(i))) // <li> tag
2238 )
2239 )
2240 )
2241 )
2242 {
2243 if (isDigit) // skip over ordered list marker '10. '
2244 {
2245 size_t j=i+1;
2246 while (j<size && ((data[j]>='0' && data[j]<='9') || data[j]=='.'))
2247 {
2248 if (data[j]=='.') // should be end of the list marker
2249 {
2250 if (j+1<size && data[j+1]==' ') // valid list marker
2251 {
2252 listMarkerSkipped=TRUE;
2253 indent+=j+1-i;
2254 i=j+1;
2255 break;
2256 }
2257 else // not a list marker
2258 {
2259 break;
2260 }
2261 }
2262 j++;
2263 }
2264 }
2265 else if (isLi)
2266 {
2267 i+=3; // skip over <li>
2268 indent+=3;
2269 listMarkerSkipped=TRUE;
2270 }
2271 else if (data[i]=='-' && size>=2 && i+2<size && data[i+1]=='#' && data[i+2]==' ')
2272 { // case "-# "
2273 listMarkerSkipped=TRUE; // only a single list marker is accepted
2274 i++; // skip over #
2275 indent++;
2276 }
2277 else if (data[i]!=' ' && i+1<size && data[i+1]==' ')
2278 { // case "- " or "+ " or "* "
2279 listMarkerSkipped=TRUE; // only a single list marker is accepted
2280 }
2281 if (data[i]!=' ' && !listMarkerSkipped)
2282 { // end of indent
2283 break;
2284 }
2285 indent++;
2286 i++;
2287 }
2288 AUTO_TRACE_EXIT("result={}",indent);
2289 return indent;
2290}
#define AUTO_TRACE(...)
Definition markdown.cpp:61
#define AUTO_TRACE_EXIT(...)
Definition markdown.cpp:63
#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 238 of file markdown.cpp.

239{
240 AUTO_TRACE("s={}",Trace::trunc(s));
241 if (s.isEmpty()) return s;
242 QCString result;
243 const char *p=s.data();
244 char c=0, pc='\0';
245 while ((c=*p++))
246 {
247 if (c=='"' && pc!='\\') result+='\\';
248 result+=c;
249 pc=c;
250 }
251 AUTO_TRACE_EXIT("result={}",result);
252 return result;
253}
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 256 of file markdown.cpp.

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

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

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

2527{
2528 AUTO_TRACE("data='{}'",Trace::trunc(data));
2529 const size_t size = data.size();
2530 size_t i=0,n=0;
2531 // find start character of the table line
2532 while (i<size && data[i]==' ') i++;
2533 if (i < size && data[i] == '|' && data[i] != '\n')
2534 {
2535 i++;
2536 n++; // leading | does not count
2537 }
2538 start = i;
2539
2540 // find end character of the table line
2541 size_t j = 0;
2542 while (i<size && (j = isNewline(data.substr(i)))==0) i++;
2543 size_t eol=i+j;
2544
2545 if (j>0 && i>0) i--; // move i to point before newline
2546 while (i>0 && data[i]==' ') i--;
2547 if (i > 0 && data[i - 1] != '\\' && data[i] == '|')
2548 {
2549 i--;
2550 n++; // trailing or escaped | does not count
2551 }
2552 end = i;
2553
2554 // count columns between start and end
2555 columns=0;
2556 if (end>start)
2557 {
2558 i=start;
2559 while (i<=end) // look for more column markers
2560 {
2561 if (data[i]=='|' && (i==0 || data[i-1]!='\\')) columns++;
2562 if (columns==1) columns++; // first | make a non-table into a two column table
2563 i++;
2564 }
2565 }
2566 if (n==2 && columns==0) // table row has | ... |
2567 {
2568 columns++;
2569 }
2570 AUTO_TRACE_EXIT("eol={} start={} end={} columns={}",eol,start,end,columns);
2571 return eol;
2572}
#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:225

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

342{
343 AUTO_TRACE("fmt={} attrs={}",fmt,attrs);
344 StringVector attrList = split(attrs.str(),",");
345 for (const auto &attr_ : attrList)
346 {
347 QCString attr = QCString(attr_).stripWhiteSpace();
348 int i = attr.find(':');
349 if (i>0) // has format
350 {
351 QCString format = attr.left(i).stripWhiteSpace().lower();
352 if (format == fmt) // matching format
353 {
354 AUTO_TRACE_EXIT("result={}",attr.mid(i+1));
355 return attr.mid(i+1); // keep part after :
356 }
357 }
358 else // option that applies to all formats
359 {
360 AUTO_TRACE_EXIT("result={}",attr);
361 return attr;
362 }
363 }
364 return QCString();
365}
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:6618

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

2816{
2817 AUTO_TRACE("data='{}'",Trace::trunc(data));
2818 size_t i=0;
2819 size_t j=0;
2820 // search for end of line and also check if it is not a completely blank
2821 while (i<data.size() && data[i]!='\n')
2822 {
2823 if (data[i]!=' ' && data[i]!='\t') j++; // some non whitespace
2824 i++;
2825 }
2826 if (i>=data.size()) { return 0; } // empty line
2827 if (i<2) { return 0; } // not long enough
2828 bool res = (j>0 && data[i-1]==' ' && data[i-2]==' '); // non blank line with at two spaces at the end
2829 AUTO_TRACE_EXIT("result={}",res);
2830 return res;
2831}

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

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

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

◆ isAllowedEmphStr()

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

Definition at line 108 of file markdown.cpp.

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

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

1944{
1945 AUTO_TRACE("data='{}' indent={}",Trace::trunc(data),indent);
1946 size_t i = 0;
1947 const size_t size = data.size();
1948 while (i<size && data[i]==' ') i++;
1949 if (i<indent+codeBlockIndent) // could be a quotation
1950 {
1951 // count >'s and skip spaces
1952 int level=0;
1953 while (i<size && (data[i]=='>' || data[i]==' '))
1954 {
1955 if (data[i]=='>') level++;
1956 i++;
1957 }
1958 // last characters should be a space or newline,
1959 // so a line starting with >= does not match, but only when level equals 1
1960 bool res = (level>0 && i<size && ((data[i-1]==' ') || data[i]=='\n')) || (level > 1);
1961 AUTO_TRACE_EXIT("result={}",res);
1962 return res;
1963 }
1964 else // too much indentation -> code block
1965 {
1966 AUTO_TRACE_EXIT("result=false: too much indentation");
1967 return false;
1968 }
1969}
static const size_t codeBlockIndent
Definition markdown.cpp:219

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

2430{
2431 AUTO_TRACE("data='{}' offset={}",Trace::trunc(data),offset);
2432 //printf("<isCodeBlock(offset=%d,size=%d,indent=%d)\n",offset,size,indent);
2433 // determine the indent of this line
2434 size_t i=0;
2435 size_t indent0=0;
2436 const size_t size = data.size();
2437 while (i < size && data[i] == ' ')
2438 {
2439 indent0++;
2440 i++;
2441 }
2442
2443 if (indent0<codeBlockIndent)
2444 {
2445 AUTO_TRACE_EXIT("result={}: line is not indented enough {}<4",false,indent0);
2446 return false;
2447 }
2448 if (indent0>=size || data[indent0]=='\n') // empty line does not start a code block
2449 {
2450 AUTO_TRACE_EXIT("result={}: only spaces at the end of a comment block",false);
2451 return false;
2452 }
2453
2454 i=offset;
2455 int nl=0;
2456 int nl_pos[3];
2457 int offset_i = static_cast<int>(offset);
2458 // search back 3 lines and remember the start of lines -1 and -2
2459 while (i>0 && nl<3) // i counts down from offset to 1
2460 {
2461 int j = static_cast<int>(i)-offset_i-1; // j counts from -1 to -offset
2462 // since j can be negative we need to rewrap data in a std::string_view
2463 size_t nl_size = isNewline(std::string_view(data.data()+j,data.size()-j));
2464 if (nl_size>0)
2465 {
2466 nl_pos[nl++]=j+static_cast<int>(nl_size);
2467 }
2468 i--;
2469 }
2470
2471 // if there are only 2 preceding lines, then line -2 starts at -offset
2472 if (i==0 && nl==2) nl_pos[nl++]=-offset_i;
2473
2474 if (nl==3) // we have at least 2 preceding lines
2475 {
2476 //printf(" positions: nl_pos=[%d,%d,%d] line[-2]='%s' line[-1]='%s'\n",
2477 // nl_pos[0],nl_pos[1],nl_pos[2],
2478 // qPrint(QCString(data+nl_pos[1]).left(nl_pos[0]-nl_pos[1]-1)),
2479 // qPrint(QCString(data+nl_pos[2]).left(nl_pos[1]-nl_pos[2]-1)));
2480
2481 // check that line -1 is empty
2482 // Note that the offset is negative so we need to rewrap the string view
2483 if (!isEmptyLine(std::string_view(data.data()+nl_pos[1],nl_pos[0]-nl_pos[1]-1)))
2484 {
2485 AUTO_TRACE_EXIT("result={}",FALSE);
2486 return FALSE;
2487 }
2488
2489 // determine the indent of line -2
2490 // Note that the offset is negative so we need to rewrap the string view
2491 indent=std::max(indent,computeIndentExcludingListMarkers(
2492 std::string_view(data.data()+nl_pos[2],nl_pos[1]-nl_pos[2])));
2493
2494 //printf(">isCodeBlock local_indent %d>=%d+%d=%d\n",
2495 // indent0,indent,codeBlockIndent,indent0>=indent+codeBlockIndent);
2496 // if the difference is >4 spaces -> code block
2497 bool res = indent0>=indent+codeBlockIndent;
2498 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2499 return res;
2500 }
2501 else // not enough lines to determine the relative indent, use global indent
2502 {
2503 // check that line -1 is empty
2504 // Note that the offset is negative so we need to rewrap the string view
2505 if (nl==1 && !isEmptyLine(std::string_view(data.data()-offset,offset-1)))
2506 {
2507 AUTO_TRACE_EXIT("result=false");
2508 return FALSE;
2509 }
2510 //printf(">isCodeBlock global indent %d>=%d+4=%d nl=%d\n",
2511 // indent0,indent,indent0>=indent+4,nl);
2512 bool res = indent0>=indent+codeBlockIndent;
2513 AUTO_TRACE_EXIT("result={}: code block if indent difference >4 spaces",res);
2514 return res;
2515 }
2516}
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 2200 of file markdown.cpp.

2201{
2202 AUTO_TRACE("data='{}'",Trace::trunc(data));
2203 size_t i=0;
2204 while (i<data.size())
2205 {
2206 if (data[i]=='\n') { AUTO_TRACE_EXIT("true"); return true; }
2207 if (data[i]!=' ') { AUTO_TRACE_EXIT("false"); return false; }
2208 i++;
2209 }
2210 AUTO_TRACE_EXIT("true");
2211 return true;
2212}

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

2304{
2305 AUTO_TRACE("data='{}'",Trace::trunc(data));
2306 int dots=0;
2307 size_t i=0;
2308 // end of list marker is an otherwise empty line with a dot.
2309 while (i<data.size())
2310 {
2311 if (data[i]=='.')
2312 {
2313 dots++;
2314 }
2315 else if (data[i]=='\n')
2316 {
2317 break;
2318 }
2319 else if (data[i]!=' ' && data[i]!='\t') // bail out if the line is not empty
2320 {
2321 AUTO_TRACE_EXIT("result=false");
2322 return false;
2323 }
2324 i++;
2325 }
2326 AUTO_TRACE_EXIT("result={}",dots==1);
2327 return dots==1;
2328}

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

3607{
3608 AUTO_TRACE("docs={}",Trace::trunc(docs));
3609 size_t i=0;
3610 std::string_view data(docs.str());
3611 const size_t size = data.size();
3612 if (!data.empty())
3613 {
3614 while (i<size && (data[i]==' ' || data[i]=='\n'))
3615 {
3616 i++;
3617 }
3618 if (literal_at(data.substr(i),"<!--!")) // skip over <!--! marker
3619 {
3620 i+=5;
3621 while (i<size && (data[i]==' ' || data[i]=='\n')) // skip over spaces after the <!--! marker
3622 {
3623 i++;
3624 }
3625 }
3626 if (i+1<size &&
3627 (data[i]=='\\' || data[i]=='@') &&
3628 (literal_at(data.substr(i+1),"page ") || literal_at(data.substr(i+1),"mainpage"))
3629 )
3630 {
3631 if (literal_at(data.substr(i+1),"page "))
3632 {
3633 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitPage");
3635 }
3636 else
3637 {
3638 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitMainPage");
3640 }
3641 }
3642 else if (i+1<size && (data[i]=='\\' || data[i]=='@') && isOtherPage(data.substr(i+1)))
3643 {
3644 AUTO_TRACE_EXIT("result=ExplicitPageResult::explicitOtherPage");
3646 }
3647 }
3648 AUTO_TRACE_EXIT("result=ExplicitPageResult::notExplicit");
3650}
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 2330 of file markdown.cpp.

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

2062{
2063 AUTO_TRACE("data='{}'",Trace::trunc(data));
2064 size_t i=0;
2065 size_t size = data.size();
2066 if (size>0 && data[size-1]=='\n') size--; // ignore newline character
2067 while (i<size && data[i]==' ') i++;
2068 if (i>=size) { AUTO_TRACE_EXIT("result=false: empty line"); return false; } // empty line
2069 char c=data[i];
2070 if (c!='*' && c!='-' && c!='_')
2071 {
2072 AUTO_TRACE_EXIT("result=false: {} is not a hrule character",c);
2073 return false; // not a hrule character
2074 }
2075 int n=0;
2076 while (i<size)
2077 {
2078 if (data[i]==c)
2079 {
2080 n++; // count rule character
2081 }
2082 else if (data[i]!=' ')
2083 {
2084 AUTO_TRACE_EXIT("result=false: line contains non hruler characters");
2085 return false; // line contains non hruler characters
2086 }
2087 i++;
2088 }
2089 AUTO_TRACE_EXIT("result={}",n>=3);
2090 return n>=3; // at least 3 characters needed for a hruler
2091}

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

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

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

1973{
1974 AUTO_TRACE("data='{}'",Trace::trunc(data));
1975 const size_t size = data.size();
1976 // format: start with [some text]:
1977 size_t i = 0;
1978 while (i<size && data[i]==' ') i++;
1979 if (i>=size || data[i]!='[') { return 0; }
1980 i++;
1981 size_t refIdStart=i;
1982 while (i<size && data[i]!='\n' && data[i]!=']') i++;
1983 if (i>=size || data[i]!=']') { return 0; }
1984 refid = data.substr(refIdStart,i-refIdStart);
1985 if (refid.isEmpty()) { return 0; }
1986 AUTO_TRACE_ADD("refid found {}",refid);
1987 //printf(" isLinkRef: found refid='%s'\n",qPrint(refid));
1988 i++;
1989 if (i>=size || data[i]!=':') { return 0; }
1990 i++;
1991
1992 // format: whitespace* \n? whitespace* (<url> | url)
1993 while (i<size && data[i]==' ') i++;
1994 if (i<size && data[i]=='\n')
1995 {
1996 i++;
1997 while (i<size && data[i]==' ') i++;
1998 }
1999 if (i>=size) { return 0; }
2000
2001 if (i<size && data[i]=='<') i++;
2002 size_t linkStart=i;
2003 while (i<size && data[i]!=' ' && data[i]!='\n') i++;
2004 size_t linkEnd=i;
2005 if (i<size && data[i]=='>') i++;
2006 if (linkStart==linkEnd) { return 0; } // empty link
2007 link = data.substr(linkStart,linkEnd-linkStart);
2008 AUTO_TRACE_ADD("link found {}",Trace::trunc(link));
2009 if (link=="@ref" || link=="\\ref")
2010 {
2011 size_t argStart=i;
2012 while (i<size && data[i]!='\n' && data[i]!='"') i++;
2013 link+=data.substr(argStart,i-argStart);
2014 }
2015
2016 title.clear();
2017
2018 // format: (whitespace* \n? whitespace* ( 'title' | "title" | (title) ))?
2019 size_t eol=0;
2020 while (i<size && data[i]==' ') i++;
2021 if (i<size && data[i]=='\n')
2022 {
2023 eol=i;
2024 i++;
2025 while (i<size && data[i]==' ') i++;
2026 }
2027 if (i>=size)
2028 {
2029 AUTO_TRACE_EXIT("result={}: end of isLinkRef while looking for title",i);
2030 return i; // end of buffer while looking for the optional title
2031 }
2032
2033 char c = data[i];
2034 if (c=='\'' || c=='"' || c=='(') // optional title present?
2035 {
2036 //printf(" start of title found! char='%c'\n",c);
2037 i++;
2038 if (c=='(') c=')'; // replace c by end character
2039 size_t titleStart=i;
2040 // search for end of the line
2041 while (i<size && data[i]!='\n') i++;
2042 eol = i;
2043
2044 // search back to matching character
2045 size_t end=i-1;
2046 while (end>titleStart && data[end]!=c) end--;
2047 if (end>titleStart)
2048 {
2049 title = data.substr(titleStart,end-titleStart);
2050 }
2051 AUTO_TRACE_ADD("title found {}",Trace::trunc(title));
2052 }
2053 while (i<size && data[i]==' ') i++;
2054 //printf("end of isLinkRef: i=%d size=%d data[i]='%c' eol=%d\n",
2055 // i,size,data[i],eol);
2056 if (i>=size) { AUTO_TRACE_EXIT("result={}",i); return i; } // end of buffer while ref id was found
2057 else if (eol>0) { AUTO_TRACE_EXIT("result={}",eol); return eol; } // end of line while ref id was found
2058 return 0; // invalid link ref
2059}
void clear()
Definition qcstring.h:182
#define AUTO_TRACE_ADD(...)
Definition markdown.cpp:62

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

2293{
2294 AUTO_TRACE("data='{}'",Trace::trunc(data));
2295 size_t normalIndent = 0;
2296 while (normalIndent<data.size() && data[normalIndent]==' ') normalIndent++;
2297 size_t listIndent = computeIndentExcludingListMarkers(data);
2298 size_t result = listIndent>normalIndent ? listIndent : 0;
2299 AUTO_TRACE_EXIT("result={}",result);
2300 return result;
2301}

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

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

References literal_at().

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

◆ isOpenEmphChar()

constexpr bool isOpenEmphChar ( char c)
staticconstexpr

Definition at line 95 of file markdown.cpp.

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

Referenced by isAllowedEmphStr().

◆ isOtherPage()

bool isOtherPage ( std::string_view data)
static

Definition at line 3593 of file markdown.cpp.

3594{
3595#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3596 OPC(dir); OPC(defgroup); OPC(addtogroup); OPC(weakgroup); OPC(ingroup);
3597 OPC(fn); OPC(property); OPC(typedef); OPC(var); OPC(def);
3598 OPC(enum); OPC(namespace); OPC(class); OPC(concept); OPC(module);
3599 OPC(protocol); OPC(category); OPC(union); OPC(struct); OPC(interface);
3600 OPC(idlexcept); OPC(file);
3601#undef OPC
3602
3603 return false;
3604}
#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 2575 of file markdown.cpp.

2576{
2577 AUTO_TRACE("data='{}'",Trace::trunc(data));
2578 size_t cc0=0, start=0, end=0;
2579
2580 // the first line should have at least two columns separated by '|'
2581 size_t i = findTableColumns(data,start,end,cc0);
2582 if (i>=data.size() || cc0<1)
2583 {
2584 AUTO_TRACE_EXIT("result=false: no |'s in the header");
2585 return FALSE;
2586 }
2587
2588 size_t cc1 = 0;
2589 size_t ret = findTableColumns(data.substr(i),start,end,cc1);
2590 size_t j=i+start;
2591 // separator line should consist of |, - and : and spaces only
2592 while (j<=end+i)
2593 {
2594 if (data[j]!=':' && data[j]!='-' && data[j]!='|' && data[j]!=' ')
2595 {
2596 AUTO_TRACE_EXIT("result=false: invalid character '{}'",data[j]);
2597 return FALSE; // invalid characters in table separator
2598 }
2599 j++;
2600 }
2601 if (cc1!=cc0) // number of columns should be same as previous line
2602 {
2603 AUTO_TRACE_EXIT("result=false: different number of columns as previous line {}!={}",cc1,cc0);
2604 return FALSE;
2605 }
2606
2607 i+=ret; // goto next line
2608 size_t cc2 = 0;
2609 findTableColumns(data.substr(i),start,end,cc2);
2610
2611 AUTO_TRACE_EXIT("result={}",cc1==cc2);
2612 return cc1==cc2;
2613}
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 103 of file markdown.cpp.

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

Referenced by isAllowedEmphStr().

◆ markdownFileNameToId()

QCString markdownFileNameToId ( const QCString & fileName)

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

Definition at line 3756 of file markdown.cpp.

3757{
3758 AUTO_TRACE("fileName={}",fileName);
3759 QCString absFileName = FileInfo(fileName.str()).absFilePath();
3760 QCString baseFn = stripFromPath(absFileName);
3761 int i = baseFn.findRev('.');
3762 if (i!=-1) baseFn = baseFn.left(i);
3763 QCString baseName = escapeCharsInString(baseFn,false,false);
3764 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3765 QCString res = "md_"+baseName;
3766 AUTO_TRACE_EXIT("result={}",res);
3767 return res;
3768}
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:3310
static QCString stripFromPath(const QCString &p, const StringVector &l)
Definition util.cpp:299

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

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

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

3013{
3014 size_t i = offset;
3015 size_t size = data.size();
3016 while (i<data.size() && data[i]==' ') i++;
3017 if (literal_at(data.substr(i),"\\ifile \""))
3018 {
3019 size_t locStart = i;
3020 if (i>offset) locStart--; // include the space before \ifile
3021 i+=8;
3022 bool found=false;
3023 while (i+9<size && data[i]!='\n')
3024 {
3025 if (literal_at(data.substr(i),"\\ilinebr "))
3026 {
3027 found=true;
3028 break;
3029 }
3030 i++;
3031 }
3032 if (found)
3033 {
3034 i+=9;
3035 location=data.substr(locStart,i-locStart);
3036 location+='\n';
3037 while (indent > 0 && i < size && data[i] == ' ')
3038 {
3039 i++;
3040 indent--;
3041 }
3042 if (i<size && data[i]=='\n') i++;
3043 offset = i;
3044 return true;
3045 }
3046 }
3047 return false;
3048}

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

2885 {
2886 // GitHub style Doxygen command
2887 { "[!note]", "\\note" },
2888 { "[!warning]", "\\warning" },
2889 { "[!tip]", "\\remark" },
2890 { "[!caution]", "\\attention" },
2891 { "[!important]", "\\important" }
2892};

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

◆ g_utf8_nbsp

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

Definition at line 217 of file markdown.cpp.

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