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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 2329 of file markdown.cpp.

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

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

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

◆ isHRuler()

bool isHRuler ( std::string_view data)
static

Definition at line 2060 of file markdown.cpp.

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

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

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

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

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

3587{
3588#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3589 OPC(dir); OPC(defgroup); OPC(addtogroup); OPC(weakgroup); OPC(ingroup);
3590 OPC(fn); OPC(property); OPC(typedef); OPC(var); OPC(def);
3591 OPC(enum); OPC(namespace); OPC(class); OPC(concept); OPC(module);
3592 OPC(protocol); OPC(category); OPC(union); OPC(struct); OPC(interface);
3593 OPC(idlexcept); OPC(file);
3594#undef OPC
3595
3596 return false;
3597}
#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 2572 of file markdown.cpp.

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

3750{
3751 AUTO_TRACE("fileName={}",fileName);
3752 QCString absFileName = FileInfo(fileName.str()).absFilePath();
3753 QCString baseFn = stripFromPath(absFileName);
3754 int i = baseFn.findRev('.');
3755 if (i!=-1) baseFn = baseFn.left(i);
3756 QCString baseName = escapeCharsInString(baseFn,false,false);
3757 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3758 QCString res = "md_"+baseName;
3759 AUTO_TRACE_EXIT("result={}",res);
3760 return res;
3761}
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:3272
static QCString stripFromPath(const QCString &p, const StringVector &l)
Definition util.cpp:300

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

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

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

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

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