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>.
Commit
90676f48f09d191360b560cb2baae6fbdded7428
Parent
e5b8eb12352f11f…
1 file changed
+57
-18
+57
-18
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -28,10 +28,12 @@ | ||
| 28 | 28 | #define WIKI_NOFOLLOW 0x001 |
| 29 | 29 | #define WIKI_HTML 0x002 |
| 30 | 30 | #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */ |
| 31 | 31 | #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */ |
| 32 | 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 */ | |
| 33 | 35 | #endif |
| 34 | 36 | |
| 35 | 37 | |
| 36 | 38 | /* |
| 37 | 39 | ** These are the only markup attributes allowed. |
| @@ -396,10 +398,11 @@ | ||
| 396 | 398 | */ |
| 397 | 399 | typedef struct Renderer Renderer; |
| 398 | 400 | struct Renderer { |
| 399 | 401 | Blob *pOut; /* Output appended to this blob */ |
| 400 | 402 | int state; /* Flag that govern rendering */ |
| 403 | + unsigned renderFlags; /* Flags from the client */ | |
| 401 | 404 | int wikiList; /* Current wiki list type */ |
| 402 | 405 | int inVerbatim; /* True in <verbatim> mode */ |
| 403 | 406 | int preVerbState; /* Value of state prior to verbatim */ |
| 404 | 407 | int wantAutoParagraph; /* True if a <p> is desired */ |
| 405 | 408 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| @@ -1075,16 +1078,37 @@ | ||
| 1075 | 1078 | rc = 0; |
| 1076 | 1079 | } |
| 1077 | 1080 | db_reset(&q); |
| 1078 | 1081 | return rc; |
| 1079 | 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 | +} | |
| 1080 | 1101 | |
| 1081 | 1102 | /* |
| 1082 | 1103 | ** Resolve a hyperlink. The zTarget argument is the content of the [...] |
| 1083 | 1104 | ** in the wiki. Append to the output string whatever text is appropriate |
| 1084 | 1105 | ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will |
| 1085 | 1106 | ** close the markup. |
| 1107 | +** | |
| 1108 | +** If this routine determines that no hyperlink should be generated, then | |
| 1109 | +** set zClose[0] to 0. | |
| 1086 | 1110 | ** |
| 1087 | 1111 | ** Actually, this routine might or might not append the hyperlink, depending |
| 1088 | 1112 | ** on current rendering rules: specifically does the current user have |
| 1089 | 1113 | ** "History" permission. |
| 1090 | 1114 | ** |
| @@ -1113,10 +1137,11 @@ | ||
| 1113 | 1137 | int nClose, /* Bytes available in zClose[] */ |
| 1114 | 1138 | const char *zOrig /* Complete document text */ |
| 1115 | 1139 | ){ |
| 1116 | 1140 | const char *zTerm = "</a>"; |
| 1117 | 1141 | assert( nClose>=20 ); |
| 1142 | + const char *z; | |
| 1118 | 1143 | |
| 1119 | 1144 | if( strncmp(zTarget, "http:", 5)==0 |
| 1120 | 1145 | || strncmp(zTarget, "https:", 6)==0 |
| 1121 | 1146 | || strncmp(zTarget, "ftp:", 4)==0 |
| 1122 | 1147 | || strncmp(zTarget, "mailto:", 7)==0 |
| @@ -1156,32 +1181,33 @@ | ||
| 1156 | 1181 | blob_appendf(p->pOut, "["); |
| 1157 | 1182 | zTerm = "]"; |
| 1158 | 1183 | } |
| 1159 | 1184 | } |
| 1160 | 1185 | }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 | + } | |
| 1163 | 1192 | }else if( g.perm.Hyperlink ){ |
| 1164 | 1193 | blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget)); |
| 1165 | 1194 | zTerm = "]</a>"; |
| 1166 | 1195 | } |
| 1167 | 1196 | }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' |
| 1168 | 1197 | && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ |
| 1169 | 1198 | 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); | |
| 1176 | 1201 | }else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){ |
| 1177 | 1202 | /* 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 = ""; | |
| 1180 | 1206 | }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>"; | |
| 1183 | 1209 | } |
| 1184 | 1210 | assert( strlen(zTerm)<nClose ); |
| 1185 | 1211 | sqlite3_snprintf(nClose, zClose, "%s", zTerm); |
| 1186 | 1212 | } |
| 1187 | 1213 | |
| @@ -1338,16 +1364,20 @@ | ||
| 1338 | 1364 | char *zTarget; |
| 1339 | 1365 | char *zDisplay = 0; |
| 1340 | 1366 | int i, j; |
| 1341 | 1367 | int savedState; |
| 1342 | 1368 | char zClose[20]; |
| 1369 | + char cS1 = 0; | |
| 1370 | + int iS1; | |
| 1343 | 1371 | |
| 1344 | 1372 | startAutoParagraph(p); |
| 1345 | 1373 | zTarget = &z[1]; |
| 1346 | 1374 | for(i=1; z[i] && z[i]!=']'; i++){ |
| 1347 | 1375 | if( z[i]=='|' && zDisplay==0 ){ |
| 1348 | 1376 | zDisplay = &z[i+1]; |
| 1377 | + iS1 = i; | |
| 1378 | + cS1 = z[i]; | |
| 1349 | 1379 | z[i] = 0; |
| 1350 | 1380 | for(j=i-1; j>0 && fossil_isspace(z[j]); j--){ z[j] = 0; } |
| 1351 | 1381 | } |
| 1352 | 1382 | } |
| 1353 | 1383 | z[i] = 0; |
| @@ -1355,16 +1385,21 @@ | ||
| 1355 | 1385 | zDisplay = zTarget; |
| 1356 | 1386 | }else{ |
| 1357 | 1387 | while( fossil_isspace(*zDisplay) ) zDisplay++; |
| 1358 | 1388 | } |
| 1359 | 1389 | 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 | + } | |
| 1366 | 1401 | break; |
| 1367 | 1402 | } |
| 1368 | 1403 | case TOKEN_TEXT: { |
| 1369 | 1404 | int i; |
| 1370 | 1405 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| @@ -1556,12 +1591,16 @@ | ||
| 1556 | 1591 | ** If pOut is NULL, then the output is appended to the CGI |
| 1557 | 1592 | ** reply. |
| 1558 | 1593 | */ |
| 1559 | 1594 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1560 | 1595 | Renderer renderer; |
| 1596 | + | |
| 1597 | + /* Never show bad hyperlinks */ | |
| 1598 | + flags |= WIKI_NOBADLINKS; | |
| 1561 | 1599 | |
| 1562 | 1600 | memset(&renderer, 0, sizeof(renderer)); |
| 1601 | + renderer.renderFlags = flags; | |
| 1563 | 1602 | renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags; |
| 1564 | 1603 | if( flags & WIKI_NOBLOCK ){ |
| 1565 | 1604 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1566 | 1605 | } |
| 1567 | 1606 | if( flags & WIKI_INLINE ){ |
| 1568 | 1607 |
| --- 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 |