Fossil SCM

Make no transformation to wiki hyperlinks (text inside [..]) if the content is not a valid hyperlink. Formerly, the faulty hyperlink would be displayed within <span class="brokenlink">..<span>.

drh 2012-11-19 13:54 trunk
Commit 90676f48f09d191360b560cb2baae6fbdded7428
1 file changed +57 -18
+57 -18
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -28,10 +28,12 @@
2828
#define WIKI_NOFOLLOW 0x001
2929
#define WIKI_HTML 0x002
3030
#define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
3131
#define WIKI_NOBLOCK 0x008 /* No block markup of any kind */
3232
#define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */
33
+#define WIKI_NOBADLINKS 0x020 /* Ignore broken hyperlinks */
34
+#define WIKI_DECORATEONLY 0x040 /* No markup. Only decorate links */
3335
#endif
3436
3537
3638
/*
3739
** These are the only markup attributes allowed.
@@ -396,10 +398,11 @@
396398
*/
397399
typedef struct Renderer Renderer;
398400
struct Renderer {
399401
Blob *pOut; /* Output appended to this blob */
400402
int state; /* Flag that govern rendering */
403
+ unsigned renderFlags; /* Flags from the client */
401404
int wikiList; /* Current wiki list type */
402405
int inVerbatim; /* True in <verbatim> mode */
403406
int preVerbState; /* Value of state prior to verbatim */
404407
int wantAutoParagraph; /* True if a <p> is desired */
405408
int inAutoParagraph; /* True if within an automatic paragraph */
@@ -1075,16 +1078,37 @@
10751078
rc = 0;
10761079
}
10771080
db_reset(&q);
10781081
return rc;
10791082
}
1083
+
1084
+/*
1085
+** Return a pointer to the name part of zTarget (skipping the "wiki:" prefix
1086
+** if there is one) if zTarget is a valid wiki page name. Return NULL if
1087
+** zTarget names a page that does not exist.
1088
+*/
1089
+static const char *validWikiPageName(const char *zTarget){
1090
+ if( strncmp(zTarget, "wiki:", 5)==0
1091
+ && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1092
+ return zTarget+5;
1093
+ }
1094
+ if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
1095
+ if( wiki_name_is_wellformed((const unsigned char *)zTarget)
1096
+ && db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'", zTarget) ){
1097
+ return zTarget;
1098
+ }
1099
+ return 0;
1100
+}
10801101
10811102
/*
10821103
** Resolve a hyperlink. The zTarget argument is the content of the [...]
10831104
** in the wiki. Append to the output string whatever text is appropriate
10841105
** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
10851106
** close the markup.
1107
+**
1108
+** If this routine determines that no hyperlink should be generated, then
1109
+** set zClose[0] to 0.
10861110
**
10871111
** Actually, this routine might or might not append the hyperlink, depending
10881112
** on current rendering rules: specifically does the current user have
10891113
** "History" permission.
10901114
**
@@ -1113,10 +1137,11 @@
11131137
int nClose, /* Bytes available in zClose[] */
11141138
const char *zOrig /* Complete document text */
11151139
){
11161140
const char *zTerm = "</a>";
11171141
assert( nClose>=20 );
1142
+ const char *z;
11181143
11191144
if( strncmp(zTarget, "http:", 5)==0
11201145
|| strncmp(zTarget, "https:", 6)==0
11211146
|| strncmp(zTarget, "ftp:", 4)==0
11221147
|| strncmp(zTarget, "mailto:", 7)==0
@@ -1156,32 +1181,33 @@
11561181
blob_appendf(p->pOut, "[");
11571182
zTerm = "]";
11581183
}
11591184
}
11601185
}else if( !in_this_repo(zTarget) ){
1161
- blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1162
- zTerm = "]</span>";
1186
+ if( (p->state & (WIKI_DECORATEONLY|WIKI_NOBADLINKS))!=0 ){
1187
+ zTerm = "";
1188
+ }else{
1189
+ blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1190
+ zTerm = "]</span>";
1191
+ }
11631192
}else if( g.perm.Hyperlink ){
11641193
blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
11651194
zTerm = "]</a>";
11661195
}
11671196
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
11681197
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
11691198
blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget);
1170
- }else if( strncmp(zTarget, "wiki:", 5)==0
1171
- && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1172
- zTarget += 5;
1173
- blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1174
- }else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
1175
- blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1199
+ }else if( (z = validWikiPageName(zTarget))!=0 ){
1200
+ blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", z);
11761201
}else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){
11771202
/* Probably an array subscript in code */
1178
- blob_appendf(p->pOut, "[");
1179
- zTerm = "]";
1203
+ zTerm = "";
1204
+ }else if( (p->state & (WIKI_NOBADLINKS|WIKI_DECORATEONLY))!=0 ){
1205
+ zTerm = "";
11801206
}else{
1181
- blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]</span>", zTarget);
1182
- zTerm = "";
1207
+ blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]", zTarget);
1208
+ zTerm = "</span>";
11831209
}
11841210
assert( strlen(zTerm)<nClose );
11851211
sqlite3_snprintf(nClose, zClose, "%s", zTerm);
11861212
}
11871213
@@ -1338,16 +1364,20 @@
13381364
char *zTarget;
13391365
char *zDisplay = 0;
13401366
int i, j;
13411367
int savedState;
13421368
char zClose[20];
1369
+ char cS1 = 0;
1370
+ int iS1;
13431371
13441372
startAutoParagraph(p);
13451373
zTarget = &z[1];
13461374
for(i=1; z[i] && z[i]!=']'; i++){
13471375
if( z[i]=='|' && zDisplay==0 ){
13481376
zDisplay = &z[i+1];
1377
+ iS1 = i;
1378
+ cS1 = z[i];
13491379
z[i] = 0;
13501380
for(j=i-1; j>0 && fossil_isspace(z[j]); j--){ z[j] = 0; }
13511381
}
13521382
}
13531383
z[i] = 0;
@@ -1355,16 +1385,21 @@
13551385
zDisplay = zTarget;
13561386
}else{
13571387
while( fossil_isspace(*zDisplay) ) zDisplay++;
13581388
}
13591389
openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig);
1360
- savedState = p->state;
1361
- p->state &= ~ALLOW_WIKI;
1362
- p->state |= FONT_MARKUP_ONLY;
1363
- wiki_render(p, zDisplay);
1364
- p->state = savedState;
1365
- blob_append(p->pOut, zClose, -1);
1390
+ if( zClose[0] ){
1391
+ savedState = p->state;
1392
+ p->state &= ~ALLOW_WIKI;
1393
+ p->state |= FONT_MARKUP_ONLY;
1394
+ wiki_render(p, zDisplay);
1395
+ p->state = savedState;
1396
+ blob_append(p->pOut, zClose, -1);
1397
+ }else{
1398
+ if( cS1 ) z[iS1] = cS1;
1399
+ blob_appendf(p->pOut, "[%h]", zTarget);
1400
+ }
13661401
break;
13671402
}
13681403
case TOKEN_TEXT: {
13691404
int i;
13701405
for(i=0; i<n && fossil_isspace(z[i]); i++){}
@@ -1556,12 +1591,16 @@
15561591
** If pOut is NULL, then the output is appended to the CGI
15571592
** reply.
15581593
*/
15591594
void wiki_convert(Blob *pIn, Blob *pOut, int flags){
15601595
Renderer renderer;
1596
+
1597
+ /* Never show bad hyperlinks */
1598
+ flags |= WIKI_NOBADLINKS;
15611599
15621600
memset(&renderer, 0, sizeof(renderer));
1601
+ renderer.renderFlags = flags;
15631602
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
15641603
if( flags & WIKI_NOBLOCK ){
15651604
renderer.state |= INLINE_MARKUP_ONLY;
15661605
}
15671606
if( flags & WIKI_INLINE ){
15681607
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -28,10 +28,12 @@
28 #define WIKI_NOFOLLOW 0x001
29 #define WIKI_HTML 0x002
30 #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
31 #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */
32 #define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */
 
 
33 #endif
34
35
36 /*
37 ** These are the only markup attributes allowed.
@@ -396,10 +398,11 @@
396 */
397 typedef struct Renderer Renderer;
398 struct Renderer {
399 Blob *pOut; /* Output appended to this blob */
400 int state; /* Flag that govern rendering */
 
401 int wikiList; /* Current wiki list type */
402 int inVerbatim; /* True in <verbatim> mode */
403 int preVerbState; /* Value of state prior to verbatim */
404 int wantAutoParagraph; /* True if a <p> is desired */
405 int inAutoParagraph; /* True if within an automatic paragraph */
@@ -1075,16 +1078,37 @@
1075 rc = 0;
1076 }
1077 db_reset(&q);
1078 return rc;
1079 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
1081 /*
1082 ** Resolve a hyperlink. The zTarget argument is the content of the [...]
1083 ** in the wiki. Append to the output string whatever text is appropriate
1084 ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
1085 ** close the markup.
 
 
 
1086 **
1087 ** Actually, this routine might or might not append the hyperlink, depending
1088 ** on current rendering rules: specifically does the current user have
1089 ** "History" permission.
1090 **
@@ -1113,10 +1137,11 @@
1113 int nClose, /* Bytes available in zClose[] */
1114 const char *zOrig /* Complete document text */
1115 ){
1116 const char *zTerm = "</a>";
1117 assert( nClose>=20 );
 
1118
1119 if( strncmp(zTarget, "http:", 5)==0
1120 || strncmp(zTarget, "https:", 6)==0
1121 || strncmp(zTarget, "ftp:", 4)==0
1122 || strncmp(zTarget, "mailto:", 7)==0
@@ -1156,32 +1181,33 @@
1156 blob_appendf(p->pOut, "[");
1157 zTerm = "]";
1158 }
1159 }
1160 }else if( !in_this_repo(zTarget) ){
1161 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1162 zTerm = "]</span>";
 
 
 
 
1163 }else if( g.perm.Hyperlink ){
1164 blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
1165 zTerm = "]</a>";
1166 }
1167 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1168 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1169 blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget);
1170 }else if( strncmp(zTarget, "wiki:", 5)==0
1171 && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1172 zTarget += 5;
1173 blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1174 }else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
1175 blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1176 }else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){
1177 /* Probably an array subscript in code */
1178 blob_appendf(p->pOut, "[");
1179 zTerm = "]";
 
1180 }else{
1181 blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]</span>", zTarget);
1182 zTerm = "";
1183 }
1184 assert( strlen(zTerm)<nClose );
1185 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1186 }
1187
@@ -1338,16 +1364,20 @@
1338 char *zTarget;
1339 char *zDisplay = 0;
1340 int i, j;
1341 int savedState;
1342 char zClose[20];
 
 
1343
1344 startAutoParagraph(p);
1345 zTarget = &z[1];
1346 for(i=1; z[i] && z[i]!=']'; i++){
1347 if( z[i]=='|' && zDisplay==0 ){
1348 zDisplay = &z[i+1];
 
 
1349 z[i] = 0;
1350 for(j=i-1; j>0 && fossil_isspace(z[j]); j--){ z[j] = 0; }
1351 }
1352 }
1353 z[i] = 0;
@@ -1355,16 +1385,21 @@
1355 zDisplay = zTarget;
1356 }else{
1357 while( fossil_isspace(*zDisplay) ) zDisplay++;
1358 }
1359 openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig);
1360 savedState = p->state;
1361 p->state &= ~ALLOW_WIKI;
1362 p->state |= FONT_MARKUP_ONLY;
1363 wiki_render(p, zDisplay);
1364 p->state = savedState;
1365 blob_append(p->pOut, zClose, -1);
 
 
 
 
 
1366 break;
1367 }
1368 case TOKEN_TEXT: {
1369 int i;
1370 for(i=0; i<n && fossil_isspace(z[i]); i++){}
@@ -1556,12 +1591,16 @@
1556 ** If pOut is NULL, then the output is appended to the CGI
1557 ** reply.
1558 */
1559 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1560 Renderer renderer;
 
 
 
1561
1562 memset(&renderer, 0, sizeof(renderer));
 
1563 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
1564 if( flags & WIKI_NOBLOCK ){
1565 renderer.state |= INLINE_MARKUP_ONLY;
1566 }
1567 if( flags & WIKI_INLINE ){
1568
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -28,10 +28,12 @@
28 #define WIKI_NOFOLLOW 0x001
29 #define WIKI_HTML 0x002
30 #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
31 #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */
32 #define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */
33 #define WIKI_NOBADLINKS 0x020 /* Ignore broken hyperlinks */
34 #define WIKI_DECORATEONLY 0x040 /* No markup. Only decorate links */
35 #endif
36
37
38 /*
39 ** These are the only markup attributes allowed.
@@ -396,10 +398,11 @@
398 */
399 typedef struct Renderer Renderer;
400 struct Renderer {
401 Blob *pOut; /* Output appended to this blob */
402 int state; /* Flag that govern rendering */
403 unsigned renderFlags; /* Flags from the client */
404 int wikiList; /* Current wiki list type */
405 int inVerbatim; /* True in <verbatim> mode */
406 int preVerbState; /* Value of state prior to verbatim */
407 int wantAutoParagraph; /* True if a <p> is desired */
408 int inAutoParagraph; /* True if within an automatic paragraph */
@@ -1075,16 +1078,37 @@
1078 rc = 0;
1079 }
1080 db_reset(&q);
1081 return rc;
1082 }
1083
1084 /*
1085 ** Return a pointer to the name part of zTarget (skipping the "wiki:" prefix
1086 ** if there is one) if zTarget is a valid wiki page name. Return NULL if
1087 ** zTarget names a page that does not exist.
1088 */
1089 static const char *validWikiPageName(const char *zTarget){
1090 if( strncmp(zTarget, "wiki:", 5)==0
1091 && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1092 return zTarget+5;
1093 }
1094 if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
1095 if( wiki_name_is_wellformed((const unsigned char *)zTarget)
1096 && db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'", zTarget) ){
1097 return zTarget;
1098 }
1099 return 0;
1100 }
1101
1102 /*
1103 ** Resolve a hyperlink. The zTarget argument is the content of the [...]
1104 ** in the wiki. Append to the output string whatever text is appropriate
1105 ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
1106 ** close the markup.
1107 **
1108 ** If this routine determines that no hyperlink should be generated, then
1109 ** set zClose[0] to 0.
1110 **
1111 ** Actually, this routine might or might not append the hyperlink, depending
1112 ** on current rendering rules: specifically does the current user have
1113 ** "History" permission.
1114 **
@@ -1113,10 +1137,11 @@
1137 int nClose, /* Bytes available in zClose[] */
1138 const char *zOrig /* Complete document text */
1139 ){
1140 const char *zTerm = "</a>";
1141 assert( nClose>=20 );
1142 const char *z;
1143
1144 if( strncmp(zTarget, "http:", 5)==0
1145 || strncmp(zTarget, "https:", 6)==0
1146 || strncmp(zTarget, "ftp:", 4)==0
1147 || strncmp(zTarget, "mailto:", 7)==0
@@ -1156,32 +1181,33 @@
1181 blob_appendf(p->pOut, "[");
1182 zTerm = "]";
1183 }
1184 }
1185 }else if( !in_this_repo(zTarget) ){
1186 if( (p->state & (WIKI_DECORATEONLY|WIKI_NOBADLINKS))!=0 ){
1187 zTerm = "";
1188 }else{
1189 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1190 zTerm = "]</span>";
1191 }
1192 }else if( g.perm.Hyperlink ){
1193 blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
1194 zTerm = "]</a>";
1195 }
1196 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1197 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1198 blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget);
1199 }else if( (z = validWikiPageName(zTarget))!=0 ){
1200 blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", z);
 
 
 
 
1201 }else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){
1202 /* Probably an array subscript in code */
1203 zTerm = "";
1204 }else if( (p->state & (WIKI_NOBADLINKS|WIKI_DECORATEONLY))!=0 ){
1205 zTerm = "";
1206 }else{
1207 blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]", zTarget);
1208 zTerm = "</span>";
1209 }
1210 assert( strlen(zTerm)<nClose );
1211 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1212 }
1213
@@ -1338,16 +1364,20 @@
1364 char *zTarget;
1365 char *zDisplay = 0;
1366 int i, j;
1367 int savedState;
1368 char zClose[20];
1369 char cS1 = 0;
1370 int iS1;
1371
1372 startAutoParagraph(p);
1373 zTarget = &z[1];
1374 for(i=1; z[i] && z[i]!=']'; i++){
1375 if( z[i]=='|' && zDisplay==0 ){
1376 zDisplay = &z[i+1];
1377 iS1 = i;
1378 cS1 = z[i];
1379 z[i] = 0;
1380 for(j=i-1; j>0 && fossil_isspace(z[j]); j--){ z[j] = 0; }
1381 }
1382 }
1383 z[i] = 0;
@@ -1355,16 +1385,21 @@
1385 zDisplay = zTarget;
1386 }else{
1387 while( fossil_isspace(*zDisplay) ) zDisplay++;
1388 }
1389 openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig);
1390 if( zClose[0] ){
1391 savedState = p->state;
1392 p->state &= ~ALLOW_WIKI;
1393 p->state |= FONT_MARKUP_ONLY;
1394 wiki_render(p, zDisplay);
1395 p->state = savedState;
1396 blob_append(p->pOut, zClose, -1);
1397 }else{
1398 if( cS1 ) z[iS1] = cS1;
1399 blob_appendf(p->pOut, "[%h]", zTarget);
1400 }
1401 break;
1402 }
1403 case TOKEN_TEXT: {
1404 int i;
1405 for(i=0; i<n && fossil_isspace(z[i]); i++){}
@@ -1556,12 +1591,16 @@
1591 ** If pOut is NULL, then the output is appended to the CGI
1592 ** reply.
1593 */
1594 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1595 Renderer renderer;
1596
1597 /* Never show bad hyperlinks */
1598 flags |= WIKI_NOBADLINKS;
1599
1600 memset(&renderer, 0, sizeof(renderer));
1601 renderer.renderFlags = flags;
1602 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
1603 if( flags & WIKI_NOBLOCK ){
1604 renderer.state |= INLINE_MARKUP_ONLY;
1605 }
1606 if( flags & WIKI_INLINE ){
1607

Keyboard Shortcuts

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