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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3601{
3602#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3603 OPC(dir); OPC(defgroup); OPC(addtogroup); OPC(weakgroup); OPC(ingroup);
3604 OPC(fn); OPC(property); OPC(typedef); OPC(var); OPC(def);
3605 OPC(enum); OPC(namespace); OPC(class); OPC(concept); OPC(module);
3606 OPC(protocol); OPC(category); OPC(union); OPC(struct); OPC(interface);
3607 OPC(idlexcept); OPC(file);
3608#undef OPC
3609
3610 return false;
3611}
#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 2578 of file markdown.cpp.

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

3764{
3765 AUTO_TRACE("fileName={}",fileName);
3766 QCString absFileName = FileInfo(fileName.str()).absFilePath();
3767 QCString baseFn = stripFromPath(absFileName);
3768 int i = baseFn.findRev('.');
3769 if (i!=-1) baseFn = baseFn.left(i);
3770 QCString baseName = escapeCharsInString(baseFn,false,false);
3771 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3772 QCString res = "md_"+baseName;
3773 AUTO_TRACE_EXIT("result={}",res);
3774 return res;
3775}
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 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 3015 of file markdown.cpp.

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

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

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

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