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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3754{
3755 AUTO_TRACE("fileName={}",fileName);
3756 QCString absFileName = FileInfo(fileName.str()).absFilePath();
3757 QCString baseFn = stripFromPath(absFileName);
3758 int i = baseFn.findRev('.');
3759 if (i!=-1) baseFn = baseFn.left(i);
3760 QCString baseName = escapeCharsInString(baseFn,false,false);
3761 //printf("markdownFileNameToId(%s)=md_%s\n",qPrint(fileName),qPrint(baseName));
3762 QCString res = "md_"+baseName;
3763 AUTO_TRACE_EXIT("result={}",res);
3764 return res;
3765}
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:3271
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 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().