Fossil SCM

Begin implementing a return code on wiki_convert() that can inform the caller about what markup is contained within the rendered wiki, and what kinds of errors were seen.

drh 2025-03-21 11:12 trunk
Commit 53b080b24509ffaba5e65f20530829a5903b369bf745b46b5af0d6ff0f0bce33
1 file changed +107 -30
+107 -30
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -23,23 +23,41 @@
2323
2424
#if INTERFACE
2525
/*
2626
** Allowed wiki transformation operations
2727
*/
28
-#define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */
29
-#define WIKI_INLINE 0x002 /* Do not surround with <p>..</p> */
30
-#define WIKI_NOBLOCK 0x004 /* No block markup of any kind */
31
-#define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */
32
-#define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */
33
-#define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */
34
-#define WIKI_NEWLINE 0x040 /* Honor \n - break lines at each \n */
35
-#define WIKI_MARKDOWNLINKS 0x080 /* Resolve hyperlinks as in markdown */
36
-#define WIKI_SAFE 0x100 /* Make the result safe for embedding */
37
-#define WIKI_TARGET_BLANK 0x200 /* Hyperlinks go to a new window */
38
-#define WIKI_NOBRACKET 0x400 /* Omit extra [..] around hyperlinks */
39
-#define WIKI_ADMIN 0x800 /* Ignore g.perm.Hyperlink */
40
-#endif
28
+#define WIKI_HTMLONLY 0x0001 /* HTML markup only. No wiki */
29
+#define WIKI_INLINE 0x0002 /* Do not surround with <p>..</p> */
30
+#define WIKI_NOBLOCK 0x0004 /* No block markup of any kind */
31
+#define WIKI_BUTTONS 0x0008 /* Allow sub-menu buttons */
32
+#define WIKI_NOBADLINKS 0x0010 /* Ignore broken hyperlinks */
33
+#define WIKI_LINKSONLY 0x0020 /* No markup. Only decorate links */
34
+#define WIKI_NEWLINE 0x0040 /* Honor \n - break lines at each \n */
35
+#define WIKI_MARKDOWNLINKS 0x0080 /* Resolve hyperlinks as in markdown */
36
+#define WIKI_SAFE 0x0100 /* Make the result safe for embedding */
37
+#define WIKI_TARGET_BLANK 0x0200 /* Hyperlinks go to a new window */
38
+#define WIKI_NOBRACKET 0x0400 /* Omit extra [..] around hyperlinks */
39
+#define WIKI_ADMIN 0x0800 /* Ignore g.perm.Hyperlink */
40
+
41
+/*
42
+** Return values from wiki_convert
43
+*/
44
+#define RENDER_LINK 0x0001 /* One or more hyperlinks rendered */
45
+#define RENDER_ENTITY 0x0002 /* One or more HTML entities (ex: &lt;) */
46
+#define RENDER_TAG 0x0004 /* One or more HTML tags */
47
+#define RENDER_BLOCKTAG 0x0008 /* One or more HTML block tags (ex: <p>) */
48
+#define RENDER_BLOCK 0x0010 /* Block wiki (paragraphs, etc.) */
49
+#define RENDER_BADLINK 0x0100 /* Bad hyperlink syntax seen */
50
+#define RENDER_BADTARGET 0x0200 /* Bad hyperlink target */
51
+#define RENDER_BADTAG 0x0400 /* Bad HTML tag or tag syntax */
52
+#define RENDER_BADENTITY 0x0800 /* Bad HTML entity syntax */
53
+#define RENDER_BADHTML 0x1000 /* Bad HTML seen */
54
+#define RENDER_ERROR 0x8000 /* Some other kind of error */
55
+/* Composite values: */
56
+#define RENDER_ANYERROR 0x9f00 /* Mask for any kind of error */
57
+
58
+#endif /* INTERFACE */
4159
4260
4361
/*
4462
** These are the only markup attributes allowed.
4563
*/
@@ -455,10 +473,11 @@
455473
*/
456474
typedef struct Renderer Renderer;
457475
struct Renderer {
458476
Blob *pOut; /* Output appended to this blob */
459477
int state; /* Flag that govern rendering */
478
+ int mRender; /* Mask of RENDER_* values to return */
460479
unsigned renderFlags; /* Flags from the client */
461480
int wikiList; /* Current wiki list type */
462481
int inVerbatim; /* True in <verbatim> mode */
463482
int preVerbState; /* Value of state prior to verbatim */
464483
int wantAutoParagraph; /* True if a <p> is desired */
@@ -680,21 +699,26 @@
680699
static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
681700
int n;
682701
if( z[0]=='<' ){
683702
n = html_tag_length(z);
684703
if( n>0 ){
704
+ p->mRender |= RENDER_TAG;
685705
*pTokenType = TOKEN_MARKUP;
686706
return n;
687707
}else{
708
+ p->mRender |= RENDER_BADTAG;
709
+ *pTokenType = TOKEN_CHARACTER;
710
+ return 1;
711
+ }
712
+ }
713
+ if( z[0]=='&' ){
714
+ p->mRender |= RENDER_ENTITY;
715
+ if( (p->inVerbatim || !isElement(z)) ){
688716
*pTokenType = TOKEN_CHARACTER;
689717
return 1;
690718
}
691719
}
692
- if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){
693
- *pTokenType = TOKEN_CHARACTER;
694
- return 1;
695
- }
696720
if( (p->state & ALLOW_WIKI)!=0 ){
697721
if( z[0]=='\n' ){
698722
n = paragraphBreakLength(z);
699723
if( n>0 ){
700724
*pTokenType = TOKEN_PARAGRAPH;
@@ -726,17 +750,25 @@
726750
if( n>0 ){
727751
*pTokenType = TOKEN_INDENT;
728752
return n;
729753
}
730754
}
731
- if( z[0]=='[' && (n = linkLength(z))>0 ){
755
+ if( z[0]=='[' ){
756
+ if( (n = linkLength(z))>0 ){
757
+ *pTokenType = TOKEN_LINK;
758
+ return n;
759
+ }else{
760
+ p->mRender |= RENDER_BADLINK;
761
+ }
762
+ }
763
+ }else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' ){
764
+ if( (n = linkLength(z))>0 ){
732765
*pTokenType = TOKEN_LINK;
733766
return n;
767
+ }else{
768
+ p->mRender |= RENDER_BADLINK;
734769
}
735
- }else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' && (n = linkLength(z))>0 ){
736
- *pTokenType = TOKEN_LINK;
737
- return n;
738770
}
739771
*pTokenType = TOKEN_TEXT;
740772
return 1 + textLength(z+1, p->state);
741773
}
742774
@@ -746,13 +778,17 @@
746778
** z points to the start of a token. Return the number of
747779
** characters in that token. Write the token type into *pTokenType.
748780
*/
749781
static int nextRawToken(const char *z, Renderer *p, int *pTokenType){
750782
int n;
751
- if( z[0]=='[' && (n = linkLength(z))>0 ){
752
- *pTokenType = TOKEN_LINK;
753
- return n;
783
+ if( z[0]=='[' ){
784
+ if( (n = linkLength(z))>0 ){
785
+ *pTokenType = TOKEN_LINK;
786
+ return n;
787
+ }else{
788
+ p->mRender |= RENDER_BADLINK;
789
+ }
754790
}
755791
*pTokenType = TOKEN_RAW;
756792
return 1 + textLength(z+1, p->state);
757793
}
758794
@@ -1249,12 +1285,16 @@
12491285
** [wiki:WikiPageName]
12501286
**
12511287
** [2010-02-27 07:13]
12521288
**
12531289
** [InterMap:Link] -> Interwiki link
1290
+**
1291
+** The return value is a mask of RENDER_* values indicating what happened.
1292
+** Probably the return value is 0 on success and RENDER_BADTARGET or
1293
+** RENDER_BADLINK if there are problems.
12541294
*/
1255
-void wiki_resolve_hyperlink(
1295
+int wiki_resolve_hyperlink(
12561296
Blob *pOut, /* Write the HTML output here */
12571297
int mFlags, /* Rendering option flags */
12581298
const char *zTarget, /* Hyperlink target; text within [...] */
12591299
char *zClose, /* Write hyperlink closing text here */
12601300
int nClose, /* Bytes available in zClose[] */
@@ -1264,10 +1304,11 @@
12641304
const char *zTerm = "</a>";
12651305
const char *z;
12661306
char *zExtra = 0;
12671307
const char *zExtraNS = 0;
12681308
char *zRemote = 0;
1309
+ int rc = 0;
12691310
12701311
if( zTitle ){
12711312
zExtra = mprintf(" title='%h'", zTitle);
12721313
zExtraNS = zExtra+1;
12731314
}else if( mFlags & WIKI_TARGET_BLANK ){
@@ -1321,10 +1362,11 @@
13211362
zTerm = "";
13221363
}else{
13231364
blob_appendf(pOut, "<span class=\"brokenlink\">%s", zLB);
13241365
zTerm = "]</span>";
13251366
}
1367
+ rc |= RENDER_BADTARGET;
13261368
}else if( g.perm.Hyperlink || (mFlags & WIKI_ADMIN)!=0 ){
13271369
blob_appendf(pOut, "%z%s",xhref(zExtraNS, "%R/info/%s", zTarget), zLB);
13281370
zTerm = "]</a>";
13291371
}else{
13301372
zTerm = "";
@@ -1341,11 +1383,11 @@
13411383
}else{
13421384
blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra);
13431385
}
13441386
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
13451387
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1346
- /* Dates or date-and-times in ISO8610 resolve to a link to the
1388
+ /* Dates or date-and-times in ISO8601 resolve to a link to the
13471389
** timeline for that date */
13481390
blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra);
13491391
}else if( mFlags & WIKI_MARKDOWNLINKS ){
13501392
/* If none of the above, and if rendering links for markdown, then
13511393
** create a link to the literal text of the target */
@@ -1357,17 +1399,20 @@
13571399
** hyperlink. Just ignore it. */
13581400
zTerm = "";
13591401
}else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){
13601402
/* Also ignore the link if various flags are set */
13611403
zTerm = "";
1404
+ rc |= RENDER_BADTARGET;
13621405
}else{
13631406
blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget);
13641407
zTerm = "</span>";
1408
+ rc |= RENDER_BADTARGET;
13651409
}
13661410
if( zExtra ) fossil_free(zExtra);
13671411
assert( (int)strlen(zTerm)<nClose );
13681412
sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1413
+ return rc;
13691414
}
13701415
13711416
/*
13721417
** Check zTarget to see if it looks like a valid hyperlink target.
13731418
** Return true if it does seem valid and false if not.
@@ -1508,10 +1553,11 @@
15081553
}
15091554
p->state |= AT_NEWLINE;
15101555
break;
15111556
}
15121557
case TOKEN_BUL_LI: {
1558
+ p->mRender |= RENDER_BLOCK;
15131559
if( inlineOnly ){
15141560
blob_append_string(p->pOut, " &bull; ");
15151561
}else{
15161562
if( p->wikiList!=MARKUP_UL ){
15171563
if( p->wikiList ){
@@ -1528,10 +1574,11 @@
15281574
blob_append_string(p->pOut, "<li>");
15291575
}
15301576
break;
15311577
}
15321578
case TOKEN_NUM_LI: {
1579
+ p->mRender |= RENDER_BLOCK;
15331580
if( inlineOnly ){
15341581
blob_append_string(p->pOut, " # ");
15351582
}else{
15361583
if( p->wikiList!=MARKUP_OL ){
15371584
if( p->wikiList ){
@@ -1548,10 +1595,11 @@
15481595
blob_append_string(p->pOut, "<li>");
15491596
}
15501597
break;
15511598
}
15521599
case TOKEN_ENUM: {
1600
+ p->mRender |= RENDER_BLOCK;
15531601
if( inlineOnly ){
15541602
blob_appendf(p->pOut, " (%d) ", atoi(z));
15551603
}else{
15561604
if( p->wikiList!=MARKUP_OL ){
15571605
if( p->wikiList ){
@@ -1568,10 +1616,11 @@
15681616
blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
15691617
}
15701618
break;
15711619
}
15721620
case TOKEN_INDENT: {
1621
+ p->mRender |= RENDER_BLOCK;
15731622
if( !inlineOnly ){
15741623
assert( p->wikiList==0 );
15751624
pushStack(p, MARKUP_BLOCKQUOTE);
15761625
blob_append_string(p->pOut, "<blockquote>");
15771626
p->wantAutoParagraph = 0;
@@ -1596,10 +1645,11 @@
15961645
char zClose[20];
15971646
char cS1 = 0;
15981647
int iS1 = 0;
15991648
16001649
startAutoParagraph(p);
1650
+ p->mRender |= RENDER_LINK;
16011651
zTarget = &z[1];
16021652
for(i=1; z[i] && z[i]!=']'; i++){
16031653
if( z[i]=='|' && zDisplay==0 ){
16041654
zDisplay = &z[i+1];
16051655
for(j=i; j>0 && fossil_isspace(z[j-1]); j--){}
@@ -1612,11 +1662,11 @@
16121662
if( zDisplay==0 ){
16131663
zDisplay = zTarget + interwiki_removable_prefix(zTarget);
16141664
}else{
16151665
while( fossil_isspace(*zDisplay) ) zDisplay++;
16161666
}
1617
- wiki_resolve_hyperlink(p->pOut, p->state,
1667
+ p->mRender |= wiki_resolve_hyperlink(p->pOut, p->state,
16181668
zTarget, zClose, sizeof(zClose), zOrig, 0);
16191669
if( linksOnly || zClose[0]==0 || p->inVerbatim ){
16201670
if( cS1 ) z[iS1] = cS1;
16211671
if( zClose[0]!=']' ){
16221672
blob_appendf(p->pOut, "[%h]%s", zTarget, zClose);
@@ -1702,10 +1752,11 @@
17021752
17031753
/* Render invalid markup literally. The markup appears in the
17041754
** final output as plain text.
17051755
*/
17061756
if( markup.iCode==MARKUP_INVALID ){
1757
+ p->mRender |= RENDER_BADTAG;
17071758
unparseMarkup(&markup);
17081759
startAutoParagraph(p);
17091760
blob_append_string(p->pOut, "&lt;");
17101761
n = 1;
17111762
}else
@@ -1814,10 +1865,11 @@
18141865
}else
18151866
{
18161867
if( markup.iType==MUTYPE_FONT ){
18171868
startAutoParagraph(p);
18181869
}else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){
1870
+ p->mRender |= RENDER_BLOCKTAG;
18191871
p->wantAutoParagraph = 0;
18201872
}
18211873
if( markup.iCode==MARKUP_HR
18221874
|| markup.iCode==MARKUP_H1
18231875
|| markup.iCode==MARKUP_H2
@@ -1844,12 +1896,14 @@
18441896
** Transform the text in the pIn blob. Write the results
18451897
** into the pOut blob. The pOut blob should already be
18461898
** initialized. The output is merely appended to pOut.
18471899
** If pOut is NULL, then the output is appended to the CGI
18481900
** reply.
1901
+**
1902
+** Return a mask of RENDER_ flags indicating what happened.
18491903
*/
1850
-void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1904
+int wiki_convert(Blob *pIn, Blob *pOut, int flags){
18511905
Renderer renderer;
18521906
18531907
memset(&renderer, 0, sizeof(renderer));
18541908
renderer.renderFlags = flags;
18551909
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
@@ -1873,10 +1927,11 @@
18731927
while( renderer.nStack ){
18741928
popStack(&renderer);
18751929
}
18761930
blob_append_char(renderer.pOut, '\n');
18771931
free(renderer.aStack);
1932
+ return renderer.mRender;
18781933
}
18791934
18801935
/*
18811936
** COMMAND: test-wiki-render
18821937
**
@@ -1892,15 +1947,18 @@
18921947
** --inline Set the WIKI_INLINE flag
18931948
** --linksonly Set the WIKI_LINKSONLY flag
18941949
** --nobadlinks Set the WIKI_NOBADLINKS flag
18951950
** --noblock Set the WIKI_NOBLOCK flag
18961951
** --text Run the output through html_to_plaintext().
1952
+** --type Break down the return code from wiki_convert().
18971953
*/
18981954
void test_wiki_render(void){
18991955
Blob in, out;
19001956
int flags = 0;
19011957
int bText;
1958
+ int showType = 0;
1959
+ int mType;
19021960
if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
19031961
if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
19041962
if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
19051963
if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
19061964
if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
@@ -1907,24 +1965,40 @@
19071965
if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK;
19081966
if( find_option("dark-pikchr",0,0)!=0 ){
19091967
pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE );
19101968
}
19111969
bText = find_option("text",0,0)!=0;
1970
+ showType = find_option("type",0,0)!=0;
19121971
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
19131972
verify_all_options();
19141973
if( g.argc!=3 ) usage("FILE");
19151974
blob_zero(&out);
19161975
blob_read_from_file(&in, g.argv[2], ExtFILE);
1917
- wiki_convert(&in, &out, flags);
1976
+ mType = wiki_convert(&in, &out, flags);
19181977
if( bText ){
19191978
Blob txt;
19201979
blob_init(&txt, 0, 0);
19211980
html_to_plaintext(blob_str(&out),&txt);
19221981
blob_reset(&out);
19231982
out = txt;
19241983
}
19251984
blob_write_to_file(&out, "-");
1985
+ if( showType ){
1986
+ fossil_print("%.*c\nResult Codes:", terminal_get_width(80)-1, '*');
1987
+ if( mType & RENDER_LINK ) fossil_print(" LINK");
1988
+ if( mType & RENDER_ENTITY ) fossil_print(" ENTITY");
1989
+ if( mType & RENDER_TAG ) fossil_print(" TAG");
1990
+ if( mType & RENDER_BLOCKTAG ) fossil_print(" BLOCKTAG");
1991
+ if( mType & RENDER_BLOCK ) fossil_print(" BLOCK");
1992
+ if( mType & RENDER_BADLINK ) fossil_print(" BADLINK");
1993
+ if( mType & RENDER_BADTARGET ) fossil_print(" BADTARGET");
1994
+ if( mType & RENDER_BADTAG ) fossil_print(" BADTAG");
1995
+ if( mType & RENDER_BADENTITY ) fossil_print(" BADENTITY");
1996
+ if( mType & RENDER_BADHTML ) fossil_print(" BADHTML");
1997
+ if( mType & RENDER_ERROR ) fossil_print(" ERROR");
1998
+ fossil_print("\n");
1999
+ }
19262000
}
19272001
19282002
/*
19292003
** COMMAND: test-markdown-render
19302004
**
@@ -2024,12 +2098,14 @@
20242098
** [target|...]
20252099
**
20262100
** Where "target" can be either an artifact ID prefix or a wiki page
20272101
** name. For each such hyperlink found, add an entry to the
20282102
** backlink table.
2103
+**
2104
+** The return value is a mask of RENDER_ flags.
20292105
*/
2030
-void wiki_extract_links(
2106
+int wiki_extract_links(
20312107
char *z, /* The wiki text from which to extract links */
20322108
Backlink *pBklnk, /* Backlink extraction context */
20332109
int flags /* wiki parsing flags */
20342110
){
20352111
Renderer renderer;
@@ -2175,10 +2251,11 @@
21752251
}
21762252
}
21772253
z += n;
21782254
}
21792255
free(renderer.aStack);
2256
+ return renderer.mRender;
21802257
}
21812258
21822259
/*
21832260
** Return the length, in bytes, of the HTML token that z is pointing to.
21842261
*/
21852262
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -23,23 +23,41 @@
23
24 #if INTERFACE
25 /*
26 ** Allowed wiki transformation operations
27 */
28 #define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */
29 #define WIKI_INLINE 0x002 /* Do not surround with <p>..</p> */
30 #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */
31 #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */
32 #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */
33 #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */
34 #define WIKI_NEWLINE 0x040 /* Honor \n - break lines at each \n */
35 #define WIKI_MARKDOWNLINKS 0x080 /* Resolve hyperlinks as in markdown */
36 #define WIKI_SAFE 0x100 /* Make the result safe for embedding */
37 #define WIKI_TARGET_BLANK 0x200 /* Hyperlinks go to a new window */
38 #define WIKI_NOBRACKET 0x400 /* Omit extra [..] around hyperlinks */
39 #define WIKI_ADMIN 0x800 /* Ignore g.perm.Hyperlink */
40 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
42
43 /*
44 ** These are the only markup attributes allowed.
45 */
@@ -455,10 +473,11 @@
455 */
456 typedef struct Renderer Renderer;
457 struct Renderer {
458 Blob *pOut; /* Output appended to this blob */
459 int state; /* Flag that govern rendering */
 
460 unsigned renderFlags; /* Flags from the client */
461 int wikiList; /* Current wiki list type */
462 int inVerbatim; /* True in <verbatim> mode */
463 int preVerbState; /* Value of state prior to verbatim */
464 int wantAutoParagraph; /* True if a <p> is desired */
@@ -680,21 +699,26 @@
680 static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
681 int n;
682 if( z[0]=='<' ){
683 n = html_tag_length(z);
684 if( n>0 ){
 
685 *pTokenType = TOKEN_MARKUP;
686 return n;
687 }else{
 
 
 
 
 
 
 
 
688 *pTokenType = TOKEN_CHARACTER;
689 return 1;
690 }
691 }
692 if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){
693 *pTokenType = TOKEN_CHARACTER;
694 return 1;
695 }
696 if( (p->state & ALLOW_WIKI)!=0 ){
697 if( z[0]=='\n' ){
698 n = paragraphBreakLength(z);
699 if( n>0 ){
700 *pTokenType = TOKEN_PARAGRAPH;
@@ -726,17 +750,25 @@
726 if( n>0 ){
727 *pTokenType = TOKEN_INDENT;
728 return n;
729 }
730 }
731 if( z[0]=='[' && (n = linkLength(z))>0 ){
 
 
 
 
 
 
 
 
 
732 *pTokenType = TOKEN_LINK;
733 return n;
 
 
734 }
735 }else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' && (n = linkLength(z))>0 ){
736 *pTokenType = TOKEN_LINK;
737 return n;
738 }
739 *pTokenType = TOKEN_TEXT;
740 return 1 + textLength(z+1, p->state);
741 }
742
@@ -746,13 +778,17 @@
746 ** z points to the start of a token. Return the number of
747 ** characters in that token. Write the token type into *pTokenType.
748 */
749 static int nextRawToken(const char *z, Renderer *p, int *pTokenType){
750 int n;
751 if( z[0]=='[' && (n = linkLength(z))>0 ){
752 *pTokenType = TOKEN_LINK;
753 return n;
 
 
 
 
754 }
755 *pTokenType = TOKEN_RAW;
756 return 1 + textLength(z+1, p->state);
757 }
758
@@ -1249,12 +1285,16 @@
1249 ** [wiki:WikiPageName]
1250 **
1251 ** [2010-02-27 07:13]
1252 **
1253 ** [InterMap:Link] -> Interwiki link
 
 
 
 
1254 */
1255 void wiki_resolve_hyperlink(
1256 Blob *pOut, /* Write the HTML output here */
1257 int mFlags, /* Rendering option flags */
1258 const char *zTarget, /* Hyperlink target; text within [...] */
1259 char *zClose, /* Write hyperlink closing text here */
1260 int nClose, /* Bytes available in zClose[] */
@@ -1264,10 +1304,11 @@
1264 const char *zTerm = "</a>";
1265 const char *z;
1266 char *zExtra = 0;
1267 const char *zExtraNS = 0;
1268 char *zRemote = 0;
 
1269
1270 if( zTitle ){
1271 zExtra = mprintf(" title='%h'", zTitle);
1272 zExtraNS = zExtra+1;
1273 }else if( mFlags & WIKI_TARGET_BLANK ){
@@ -1321,10 +1362,11 @@
1321 zTerm = "";
1322 }else{
1323 blob_appendf(pOut, "<span class=\"brokenlink\">%s", zLB);
1324 zTerm = "]</span>";
1325 }
 
1326 }else if( g.perm.Hyperlink || (mFlags & WIKI_ADMIN)!=0 ){
1327 blob_appendf(pOut, "%z%s",xhref(zExtraNS, "%R/info/%s", zTarget), zLB);
1328 zTerm = "]</a>";
1329 }else{
1330 zTerm = "";
@@ -1341,11 +1383,11 @@
1341 }else{
1342 blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra);
1343 }
1344 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1345 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1346 /* Dates or date-and-times in ISO8610 resolve to a link to the
1347 ** timeline for that date */
1348 blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra);
1349 }else if( mFlags & WIKI_MARKDOWNLINKS ){
1350 /* If none of the above, and if rendering links for markdown, then
1351 ** create a link to the literal text of the target */
@@ -1357,17 +1399,20 @@
1357 ** hyperlink. Just ignore it. */
1358 zTerm = "";
1359 }else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){
1360 /* Also ignore the link if various flags are set */
1361 zTerm = "";
 
1362 }else{
1363 blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget);
1364 zTerm = "</span>";
 
1365 }
1366 if( zExtra ) fossil_free(zExtra);
1367 assert( (int)strlen(zTerm)<nClose );
1368 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
 
1369 }
1370
1371 /*
1372 ** Check zTarget to see if it looks like a valid hyperlink target.
1373 ** Return true if it does seem valid and false if not.
@@ -1508,10 +1553,11 @@
1508 }
1509 p->state |= AT_NEWLINE;
1510 break;
1511 }
1512 case TOKEN_BUL_LI: {
 
1513 if( inlineOnly ){
1514 blob_append_string(p->pOut, " &bull; ");
1515 }else{
1516 if( p->wikiList!=MARKUP_UL ){
1517 if( p->wikiList ){
@@ -1528,10 +1574,11 @@
1528 blob_append_string(p->pOut, "<li>");
1529 }
1530 break;
1531 }
1532 case TOKEN_NUM_LI: {
 
1533 if( inlineOnly ){
1534 blob_append_string(p->pOut, " # ");
1535 }else{
1536 if( p->wikiList!=MARKUP_OL ){
1537 if( p->wikiList ){
@@ -1548,10 +1595,11 @@
1548 blob_append_string(p->pOut, "<li>");
1549 }
1550 break;
1551 }
1552 case TOKEN_ENUM: {
 
1553 if( inlineOnly ){
1554 blob_appendf(p->pOut, " (%d) ", atoi(z));
1555 }else{
1556 if( p->wikiList!=MARKUP_OL ){
1557 if( p->wikiList ){
@@ -1568,10 +1616,11 @@
1568 blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
1569 }
1570 break;
1571 }
1572 case TOKEN_INDENT: {
 
1573 if( !inlineOnly ){
1574 assert( p->wikiList==0 );
1575 pushStack(p, MARKUP_BLOCKQUOTE);
1576 blob_append_string(p->pOut, "<blockquote>");
1577 p->wantAutoParagraph = 0;
@@ -1596,10 +1645,11 @@
1596 char zClose[20];
1597 char cS1 = 0;
1598 int iS1 = 0;
1599
1600 startAutoParagraph(p);
 
1601 zTarget = &z[1];
1602 for(i=1; z[i] && z[i]!=']'; i++){
1603 if( z[i]=='|' && zDisplay==0 ){
1604 zDisplay = &z[i+1];
1605 for(j=i; j>0 && fossil_isspace(z[j-1]); j--){}
@@ -1612,11 +1662,11 @@
1612 if( zDisplay==0 ){
1613 zDisplay = zTarget + interwiki_removable_prefix(zTarget);
1614 }else{
1615 while( fossil_isspace(*zDisplay) ) zDisplay++;
1616 }
1617 wiki_resolve_hyperlink(p->pOut, p->state,
1618 zTarget, zClose, sizeof(zClose), zOrig, 0);
1619 if( linksOnly || zClose[0]==0 || p->inVerbatim ){
1620 if( cS1 ) z[iS1] = cS1;
1621 if( zClose[0]!=']' ){
1622 blob_appendf(p->pOut, "[%h]%s", zTarget, zClose);
@@ -1702,10 +1752,11 @@
1702
1703 /* Render invalid markup literally. The markup appears in the
1704 ** final output as plain text.
1705 */
1706 if( markup.iCode==MARKUP_INVALID ){
 
1707 unparseMarkup(&markup);
1708 startAutoParagraph(p);
1709 blob_append_string(p->pOut, "&lt;");
1710 n = 1;
1711 }else
@@ -1814,10 +1865,11 @@
1814 }else
1815 {
1816 if( markup.iType==MUTYPE_FONT ){
1817 startAutoParagraph(p);
1818 }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){
 
1819 p->wantAutoParagraph = 0;
1820 }
1821 if( markup.iCode==MARKUP_HR
1822 || markup.iCode==MARKUP_H1
1823 || markup.iCode==MARKUP_H2
@@ -1844,12 +1896,14 @@
1844 ** Transform the text in the pIn blob. Write the results
1845 ** into the pOut blob. The pOut blob should already be
1846 ** initialized. The output is merely appended to pOut.
1847 ** If pOut is NULL, then the output is appended to the CGI
1848 ** reply.
 
 
1849 */
1850 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1851 Renderer renderer;
1852
1853 memset(&renderer, 0, sizeof(renderer));
1854 renderer.renderFlags = flags;
1855 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
@@ -1873,10 +1927,11 @@
1873 while( renderer.nStack ){
1874 popStack(&renderer);
1875 }
1876 blob_append_char(renderer.pOut, '\n');
1877 free(renderer.aStack);
 
1878 }
1879
1880 /*
1881 ** COMMAND: test-wiki-render
1882 **
@@ -1892,15 +1947,18 @@
1892 ** --inline Set the WIKI_INLINE flag
1893 ** --linksonly Set the WIKI_LINKSONLY flag
1894 ** --nobadlinks Set the WIKI_NOBADLINKS flag
1895 ** --noblock Set the WIKI_NOBLOCK flag
1896 ** --text Run the output through html_to_plaintext().
 
1897 */
1898 void test_wiki_render(void){
1899 Blob in, out;
1900 int flags = 0;
1901 int bText;
 
 
1902 if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
1903 if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
1904 if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
1905 if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
1906 if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
@@ -1907,24 +1965,40 @@
1907 if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK;
1908 if( find_option("dark-pikchr",0,0)!=0 ){
1909 pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE );
1910 }
1911 bText = find_option("text",0,0)!=0;
 
1912 db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
1913 verify_all_options();
1914 if( g.argc!=3 ) usage("FILE");
1915 blob_zero(&out);
1916 blob_read_from_file(&in, g.argv[2], ExtFILE);
1917 wiki_convert(&in, &out, flags);
1918 if( bText ){
1919 Blob txt;
1920 blob_init(&txt, 0, 0);
1921 html_to_plaintext(blob_str(&out),&txt);
1922 blob_reset(&out);
1923 out = txt;
1924 }
1925 blob_write_to_file(&out, "-");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1926 }
1927
1928 /*
1929 ** COMMAND: test-markdown-render
1930 **
@@ -2024,12 +2098,14 @@
2024 ** [target|...]
2025 **
2026 ** Where "target" can be either an artifact ID prefix or a wiki page
2027 ** name. For each such hyperlink found, add an entry to the
2028 ** backlink table.
 
 
2029 */
2030 void wiki_extract_links(
2031 char *z, /* The wiki text from which to extract links */
2032 Backlink *pBklnk, /* Backlink extraction context */
2033 int flags /* wiki parsing flags */
2034 ){
2035 Renderer renderer;
@@ -2175,10 +2251,11 @@
2175 }
2176 }
2177 z += n;
2178 }
2179 free(renderer.aStack);
 
2180 }
2181
2182 /*
2183 ** Return the length, in bytes, of the HTML token that z is pointing to.
2184 */
2185
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -23,23 +23,41 @@
23
24 #if INTERFACE
25 /*
26 ** Allowed wiki transformation operations
27 */
28 #define WIKI_HTMLONLY 0x0001 /* HTML markup only. No wiki */
29 #define WIKI_INLINE 0x0002 /* Do not surround with <p>..</p> */
30 #define WIKI_NOBLOCK 0x0004 /* No block markup of any kind */
31 #define WIKI_BUTTONS 0x0008 /* Allow sub-menu buttons */
32 #define WIKI_NOBADLINKS 0x0010 /* Ignore broken hyperlinks */
33 #define WIKI_LINKSONLY 0x0020 /* No markup. Only decorate links */
34 #define WIKI_NEWLINE 0x0040 /* Honor \n - break lines at each \n */
35 #define WIKI_MARKDOWNLINKS 0x0080 /* Resolve hyperlinks as in markdown */
36 #define WIKI_SAFE 0x0100 /* Make the result safe for embedding */
37 #define WIKI_TARGET_BLANK 0x0200 /* Hyperlinks go to a new window */
38 #define WIKI_NOBRACKET 0x0400 /* Omit extra [..] around hyperlinks */
39 #define WIKI_ADMIN 0x0800 /* Ignore g.perm.Hyperlink */
40
41 /*
42 ** Return values from wiki_convert
43 */
44 #define RENDER_LINK 0x0001 /* One or more hyperlinks rendered */
45 #define RENDER_ENTITY 0x0002 /* One or more HTML entities (ex: &lt;) */
46 #define RENDER_TAG 0x0004 /* One or more HTML tags */
47 #define RENDER_BLOCKTAG 0x0008 /* One or more HTML block tags (ex: <p>) */
48 #define RENDER_BLOCK 0x0010 /* Block wiki (paragraphs, etc.) */
49 #define RENDER_BADLINK 0x0100 /* Bad hyperlink syntax seen */
50 #define RENDER_BADTARGET 0x0200 /* Bad hyperlink target */
51 #define RENDER_BADTAG 0x0400 /* Bad HTML tag or tag syntax */
52 #define RENDER_BADENTITY 0x0800 /* Bad HTML entity syntax */
53 #define RENDER_BADHTML 0x1000 /* Bad HTML seen */
54 #define RENDER_ERROR 0x8000 /* Some other kind of error */
55 /* Composite values: */
56 #define RENDER_ANYERROR 0x9f00 /* Mask for any kind of error */
57
58 #endif /* INTERFACE */
59
60
61 /*
62 ** These are the only markup attributes allowed.
63 */
@@ -455,10 +473,11 @@
473 */
474 typedef struct Renderer Renderer;
475 struct Renderer {
476 Blob *pOut; /* Output appended to this blob */
477 int state; /* Flag that govern rendering */
478 int mRender; /* Mask of RENDER_* values to return */
479 unsigned renderFlags; /* Flags from the client */
480 int wikiList; /* Current wiki list type */
481 int inVerbatim; /* True in <verbatim> mode */
482 int preVerbState; /* Value of state prior to verbatim */
483 int wantAutoParagraph; /* True if a <p> is desired */
@@ -680,21 +699,26 @@
699 static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
700 int n;
701 if( z[0]=='<' ){
702 n = html_tag_length(z);
703 if( n>0 ){
704 p->mRender |= RENDER_TAG;
705 *pTokenType = TOKEN_MARKUP;
706 return n;
707 }else{
708 p->mRender |= RENDER_BADTAG;
709 *pTokenType = TOKEN_CHARACTER;
710 return 1;
711 }
712 }
713 if( z[0]=='&' ){
714 p->mRender |= RENDER_ENTITY;
715 if( (p->inVerbatim || !isElement(z)) ){
716 *pTokenType = TOKEN_CHARACTER;
717 return 1;
718 }
719 }
 
 
 
 
720 if( (p->state & ALLOW_WIKI)!=0 ){
721 if( z[0]=='\n' ){
722 n = paragraphBreakLength(z);
723 if( n>0 ){
724 *pTokenType = TOKEN_PARAGRAPH;
@@ -726,17 +750,25 @@
750 if( n>0 ){
751 *pTokenType = TOKEN_INDENT;
752 return n;
753 }
754 }
755 if( z[0]=='[' ){
756 if( (n = linkLength(z))>0 ){
757 *pTokenType = TOKEN_LINK;
758 return n;
759 }else{
760 p->mRender |= RENDER_BADLINK;
761 }
762 }
763 }else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' ){
764 if( (n = linkLength(z))>0 ){
765 *pTokenType = TOKEN_LINK;
766 return n;
767 }else{
768 p->mRender |= RENDER_BADLINK;
769 }
 
 
 
770 }
771 *pTokenType = TOKEN_TEXT;
772 return 1 + textLength(z+1, p->state);
773 }
774
@@ -746,13 +778,17 @@
778 ** z points to the start of a token. Return the number of
779 ** characters in that token. Write the token type into *pTokenType.
780 */
781 static int nextRawToken(const char *z, Renderer *p, int *pTokenType){
782 int n;
783 if( z[0]=='[' ){
784 if( (n = linkLength(z))>0 ){
785 *pTokenType = TOKEN_LINK;
786 return n;
787 }else{
788 p->mRender |= RENDER_BADLINK;
789 }
790 }
791 *pTokenType = TOKEN_RAW;
792 return 1 + textLength(z+1, p->state);
793 }
794
@@ -1249,12 +1285,16 @@
1285 ** [wiki:WikiPageName]
1286 **
1287 ** [2010-02-27 07:13]
1288 **
1289 ** [InterMap:Link] -> Interwiki link
1290 **
1291 ** The return value is a mask of RENDER_* values indicating what happened.
1292 ** Probably the return value is 0 on success and RENDER_BADTARGET or
1293 ** RENDER_BADLINK if there are problems.
1294 */
1295 int wiki_resolve_hyperlink(
1296 Blob *pOut, /* Write the HTML output here */
1297 int mFlags, /* Rendering option flags */
1298 const char *zTarget, /* Hyperlink target; text within [...] */
1299 char *zClose, /* Write hyperlink closing text here */
1300 int nClose, /* Bytes available in zClose[] */
@@ -1264,10 +1304,11 @@
1304 const char *zTerm = "</a>";
1305 const char *z;
1306 char *zExtra = 0;
1307 const char *zExtraNS = 0;
1308 char *zRemote = 0;
1309 int rc = 0;
1310
1311 if( zTitle ){
1312 zExtra = mprintf(" title='%h'", zTitle);
1313 zExtraNS = zExtra+1;
1314 }else if( mFlags & WIKI_TARGET_BLANK ){
@@ -1321,10 +1362,11 @@
1362 zTerm = "";
1363 }else{
1364 blob_appendf(pOut, "<span class=\"brokenlink\">%s", zLB);
1365 zTerm = "]</span>";
1366 }
1367 rc |= RENDER_BADTARGET;
1368 }else if( g.perm.Hyperlink || (mFlags & WIKI_ADMIN)!=0 ){
1369 blob_appendf(pOut, "%z%s",xhref(zExtraNS, "%R/info/%s", zTarget), zLB);
1370 zTerm = "]</a>";
1371 }else{
1372 zTerm = "";
@@ -1341,11 +1383,11 @@
1383 }else{
1384 blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra);
1385 }
1386 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1387 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1388 /* Dates or date-and-times in ISO8601 resolve to a link to the
1389 ** timeline for that date */
1390 blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra);
1391 }else if( mFlags & WIKI_MARKDOWNLINKS ){
1392 /* If none of the above, and if rendering links for markdown, then
1393 ** create a link to the literal text of the target */
@@ -1357,17 +1399,20 @@
1399 ** hyperlink. Just ignore it. */
1400 zTerm = "";
1401 }else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){
1402 /* Also ignore the link if various flags are set */
1403 zTerm = "";
1404 rc |= RENDER_BADTARGET;
1405 }else{
1406 blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget);
1407 zTerm = "</span>";
1408 rc |= RENDER_BADTARGET;
1409 }
1410 if( zExtra ) fossil_free(zExtra);
1411 assert( (int)strlen(zTerm)<nClose );
1412 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1413 return rc;
1414 }
1415
1416 /*
1417 ** Check zTarget to see if it looks like a valid hyperlink target.
1418 ** Return true if it does seem valid and false if not.
@@ -1508,10 +1553,11 @@
1553 }
1554 p->state |= AT_NEWLINE;
1555 break;
1556 }
1557 case TOKEN_BUL_LI: {
1558 p->mRender |= RENDER_BLOCK;
1559 if( inlineOnly ){
1560 blob_append_string(p->pOut, " &bull; ");
1561 }else{
1562 if( p->wikiList!=MARKUP_UL ){
1563 if( p->wikiList ){
@@ -1528,10 +1574,11 @@
1574 blob_append_string(p->pOut, "<li>");
1575 }
1576 break;
1577 }
1578 case TOKEN_NUM_LI: {
1579 p->mRender |= RENDER_BLOCK;
1580 if( inlineOnly ){
1581 blob_append_string(p->pOut, " # ");
1582 }else{
1583 if( p->wikiList!=MARKUP_OL ){
1584 if( p->wikiList ){
@@ -1548,10 +1595,11 @@
1595 blob_append_string(p->pOut, "<li>");
1596 }
1597 break;
1598 }
1599 case TOKEN_ENUM: {
1600 p->mRender |= RENDER_BLOCK;
1601 if( inlineOnly ){
1602 blob_appendf(p->pOut, " (%d) ", atoi(z));
1603 }else{
1604 if( p->wikiList!=MARKUP_OL ){
1605 if( p->wikiList ){
@@ -1568,10 +1616,11 @@
1616 blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
1617 }
1618 break;
1619 }
1620 case TOKEN_INDENT: {
1621 p->mRender |= RENDER_BLOCK;
1622 if( !inlineOnly ){
1623 assert( p->wikiList==0 );
1624 pushStack(p, MARKUP_BLOCKQUOTE);
1625 blob_append_string(p->pOut, "<blockquote>");
1626 p->wantAutoParagraph = 0;
@@ -1596,10 +1645,11 @@
1645 char zClose[20];
1646 char cS1 = 0;
1647 int iS1 = 0;
1648
1649 startAutoParagraph(p);
1650 p->mRender |= RENDER_LINK;
1651 zTarget = &z[1];
1652 for(i=1; z[i] && z[i]!=']'; i++){
1653 if( z[i]=='|' && zDisplay==0 ){
1654 zDisplay = &z[i+1];
1655 for(j=i; j>0 && fossil_isspace(z[j-1]); j--){}
@@ -1612,11 +1662,11 @@
1662 if( zDisplay==0 ){
1663 zDisplay = zTarget + interwiki_removable_prefix(zTarget);
1664 }else{
1665 while( fossil_isspace(*zDisplay) ) zDisplay++;
1666 }
1667 p->mRender |= wiki_resolve_hyperlink(p->pOut, p->state,
1668 zTarget, zClose, sizeof(zClose), zOrig, 0);
1669 if( linksOnly || zClose[0]==0 || p->inVerbatim ){
1670 if( cS1 ) z[iS1] = cS1;
1671 if( zClose[0]!=']' ){
1672 blob_appendf(p->pOut, "[%h]%s", zTarget, zClose);
@@ -1702,10 +1752,11 @@
1752
1753 /* Render invalid markup literally. The markup appears in the
1754 ** final output as plain text.
1755 */
1756 if( markup.iCode==MARKUP_INVALID ){
1757 p->mRender |= RENDER_BADTAG;
1758 unparseMarkup(&markup);
1759 startAutoParagraph(p);
1760 blob_append_string(p->pOut, "&lt;");
1761 n = 1;
1762 }else
@@ -1814,10 +1865,11 @@
1865 }else
1866 {
1867 if( markup.iType==MUTYPE_FONT ){
1868 startAutoParagraph(p);
1869 }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){
1870 p->mRender |= RENDER_BLOCKTAG;
1871 p->wantAutoParagraph = 0;
1872 }
1873 if( markup.iCode==MARKUP_HR
1874 || markup.iCode==MARKUP_H1
1875 || markup.iCode==MARKUP_H2
@@ -1844,12 +1896,14 @@
1896 ** Transform the text in the pIn blob. Write the results
1897 ** into the pOut blob. The pOut blob should already be
1898 ** initialized. The output is merely appended to pOut.
1899 ** If pOut is NULL, then the output is appended to the CGI
1900 ** reply.
1901 **
1902 ** Return a mask of RENDER_ flags indicating what happened.
1903 */
1904 int wiki_convert(Blob *pIn, Blob *pOut, int flags){
1905 Renderer renderer;
1906
1907 memset(&renderer, 0, sizeof(renderer));
1908 renderer.renderFlags = flags;
1909 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
@@ -1873,10 +1927,11 @@
1927 while( renderer.nStack ){
1928 popStack(&renderer);
1929 }
1930 blob_append_char(renderer.pOut, '\n');
1931 free(renderer.aStack);
1932 return renderer.mRender;
1933 }
1934
1935 /*
1936 ** COMMAND: test-wiki-render
1937 **
@@ -1892,15 +1947,18 @@
1947 ** --inline Set the WIKI_INLINE flag
1948 ** --linksonly Set the WIKI_LINKSONLY flag
1949 ** --nobadlinks Set the WIKI_NOBADLINKS flag
1950 ** --noblock Set the WIKI_NOBLOCK flag
1951 ** --text Run the output through html_to_plaintext().
1952 ** --type Break down the return code from wiki_convert().
1953 */
1954 void test_wiki_render(void){
1955 Blob in, out;
1956 int flags = 0;
1957 int bText;
1958 int showType = 0;
1959 int mType;
1960 if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
1961 if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
1962 if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
1963 if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
1964 if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
@@ -1907,24 +1965,40 @@
1965 if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK;
1966 if( find_option("dark-pikchr",0,0)!=0 ){
1967 pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE );
1968 }
1969 bText = find_option("text",0,0)!=0;
1970 showType = find_option("type",0,0)!=0;
1971 db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
1972 verify_all_options();
1973 if( g.argc!=3 ) usage("FILE");
1974 blob_zero(&out);
1975 blob_read_from_file(&in, g.argv[2], ExtFILE);
1976 mType = wiki_convert(&in, &out, flags);
1977 if( bText ){
1978 Blob txt;
1979 blob_init(&txt, 0, 0);
1980 html_to_plaintext(blob_str(&out),&txt);
1981 blob_reset(&out);
1982 out = txt;
1983 }
1984 blob_write_to_file(&out, "-");
1985 if( showType ){
1986 fossil_print("%.*c\nResult Codes:", terminal_get_width(80)-1, '*');
1987 if( mType & RENDER_LINK ) fossil_print(" LINK");
1988 if( mType & RENDER_ENTITY ) fossil_print(" ENTITY");
1989 if( mType & RENDER_TAG ) fossil_print(" TAG");
1990 if( mType & RENDER_BLOCKTAG ) fossil_print(" BLOCKTAG");
1991 if( mType & RENDER_BLOCK ) fossil_print(" BLOCK");
1992 if( mType & RENDER_BADLINK ) fossil_print(" BADLINK");
1993 if( mType & RENDER_BADTARGET ) fossil_print(" BADTARGET");
1994 if( mType & RENDER_BADTAG ) fossil_print(" BADTAG");
1995 if( mType & RENDER_BADENTITY ) fossil_print(" BADENTITY");
1996 if( mType & RENDER_BADHTML ) fossil_print(" BADHTML");
1997 if( mType & RENDER_ERROR ) fossil_print(" ERROR");
1998 fossil_print("\n");
1999 }
2000 }
2001
2002 /*
2003 ** COMMAND: test-markdown-render
2004 **
@@ -2024,12 +2098,14 @@
2098 ** [target|...]
2099 **
2100 ** Where "target" can be either an artifact ID prefix or a wiki page
2101 ** name. For each such hyperlink found, add an entry to the
2102 ** backlink table.
2103 **
2104 ** The return value is a mask of RENDER_ flags.
2105 */
2106 int wiki_extract_links(
2107 char *z, /* The wiki text from which to extract links */
2108 Backlink *pBklnk, /* Backlink extraction context */
2109 int flags /* wiki parsing flags */
2110 ){
2111 Renderer renderer;
@@ -2175,10 +2251,11 @@
2251 }
2252 }
2253 z += n;
2254 }
2255 free(renderer.aStack);
2256 return renderer.mRender;
2257 }
2258
2259 /*
2260 ** Return the length, in bytes, of the HTML token that z is pointing to.
2261 */
2262

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button