Fossil SCM
Experimental - Pass < !-- --> comments through the wiki unchanged unless inside a < verbatim > block in which case it is htmlized. Also pass <span> tags, treating them as font markup. These changes make it easier to convert existing html pages and specifically allow the inclusion of license text in pages derived from copyright material.
Commit
47cc9dfec89c25da28bfa9ee9cfe749e31c6f04c
Parent
767ae79c3dcc16b…
1 file changed
+75
-39
+75
-39
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -7,11 +7,11 @@ | ||
| 7 | 7 | ** |
| 8 | 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | 9 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | 10 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 11 | 11 | ** General Public License for more details. |
| 12 | -** | |
| 12 | +** | |
| 13 | 13 | ** You should have received a copy of the GNU General Public |
| 14 | 14 | ** License along with this library; if not, write to the |
| 15 | 15 | ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 16 | 16 | ** Boston, MA 02111-1307, USA. |
| 17 | 17 | ** |
| @@ -150,11 +150,11 @@ | ||
| 150 | 150 | /* |
| 151 | 151 | ** Allowed markup. |
| 152 | 152 | ** |
| 153 | 153 | ** Except for MARKUP_INVALID, this must all be in alphabetical order |
| 154 | 154 | ** and in numerical sequence. The first markup type must be zero. |
| 155 | -** The value for MARKUP_XYZ must correspond to the <xyz> entry | |
| 155 | +** The value for MARKUP_XYZ must correspond to the <xyz> entry | |
| 156 | 156 | ** in aAllowedMarkup[]. |
| 157 | 157 | */ |
| 158 | 158 | #define MARKUP_INVALID 0 |
| 159 | 159 | #define MARKUP_A 1 |
| 160 | 160 | #define MARKUP_ADDRESS 2 |
| @@ -189,23 +189,24 @@ | ||
| 189 | 189 | #define MARKUP_P 31 |
| 190 | 190 | #define MARKUP_PRE 32 |
| 191 | 191 | #define MARKUP_S 33 |
| 192 | 192 | #define MARKUP_SAMP 34 |
| 193 | 193 | #define MARKUP_SMALL 35 |
| 194 | -#define MARKUP_STRIKE 36 | |
| 195 | -#define MARKUP_STRONG 37 | |
| 196 | -#define MARKUP_SUB 38 | |
| 197 | -#define MARKUP_SUP 39 | |
| 198 | -#define MARKUP_TABLE 40 | |
| 199 | -#define MARKUP_TD 41 | |
| 200 | -#define MARKUP_TH 42 | |
| 201 | -#define MARKUP_TR 43 | |
| 202 | -#define MARKUP_TT 44 | |
| 203 | -#define MARKUP_U 45 | |
| 204 | -#define MARKUP_UL 46 | |
| 205 | -#define MARKUP_VAR 47 | |
| 206 | -#define MARKUP_VERBATIM 48 | |
| 194 | +#define MARKUP_SPAN 36 | |
| 195 | +#define MARKUP_STRIKE 37 | |
| 196 | +#define MARKUP_STRONG 38 | |
| 197 | +#define MARKUP_SUB 39 | |
| 198 | +#define MARKUP_SUP 40 | |
| 199 | +#define MARKUP_TABLE 41 | |
| 200 | +#define MARKUP_TD 42 | |
| 201 | +#define MARKUP_TH 43 | |
| 202 | +#define MARKUP_TR 44 | |
| 203 | +#define MARKUP_TT 45 | |
| 204 | +#define MARKUP_U 46 | |
| 205 | +#define MARKUP_UL 47 | |
| 206 | +#define MARKUP_VAR 48 | |
| 207 | +#define MARKUP_VERBATIM 49 | |
| 207 | 208 | |
| 208 | 209 | /* |
| 209 | 210 | ** The various markup is divided into the following types: |
| 210 | 211 | */ |
| 211 | 212 | #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */ |
| @@ -258,46 +259,47 @@ | ||
| 258 | 259 | { "h2", MARKUP_H2, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 259 | 260 | { "h3", MARKUP_H3, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 260 | 261 | { "h4", MARKUP_H4, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 261 | 262 | { "h5", MARKUP_H5, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 262 | 263 | { "h6", MARKUP_H6, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 263 | - { "hr", MARKUP_HR, MUTYPE_SINGLE, | |
| 264 | + { "hr", MARKUP_HR, MUTYPE_SINGLE, | |
| 264 | 265 | AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH }, |
| 265 | 266 | { "i", MARKUP_I, MUTYPE_FONT, 0 }, |
| 266 | - { "img", MARKUP_IMG, MUTYPE_SINGLE, | |
| 267 | + { "img", MARKUP_IMG, MUTYPE_SINGLE, | |
| 267 | 268 | AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT| |
| 268 | 269 | AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH }, |
| 269 | 270 | { "kbd", MARKUP_KBD, MUTYPE_FONT, 0 }, |
| 270 | - { "li", MARKUP_LI, MUTYPE_LI, | |
| 271 | + { "li", MARKUP_LI, MUTYPE_LI, | |
| 271 | 272 | AMSK_TYPE|AMSK_VALUE }, |
| 272 | 273 | { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 }, |
| 273 | 274 | { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 }, |
| 274 | - { "ol", MARKUP_OL, MUTYPE_LIST, | |
| 275 | + { "ol", MARKUP_OL, MUTYPE_LIST, | |
| 275 | 276 | AMSK_START|AMSK_TYPE|AMSK_COMPACT }, |
| 276 | 277 | { "p", MARKUP_P, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 277 | 278 | { "pre", MARKUP_PRE, MUTYPE_BLOCK, 0 }, |
| 278 | 279 | { "s", MARKUP_S, MUTYPE_FONT, 0 }, |
| 279 | 280 | { "samp", MARKUP_SAMP, MUTYPE_FONT, 0 }, |
| 280 | 281 | { "small", MARKUP_SMALL, MUTYPE_FONT, 0 }, |
| 282 | + { "span", MARKUP_SPAN, MUTYPE_FONT, 0 }, | |
| 281 | 283 | { "strike", MARKUP_STRIKE, MUTYPE_FONT, 0 }, |
| 282 | 284 | { "strong", MARKUP_STRONG, MUTYPE_FONT, 0 }, |
| 283 | 285 | { "sub", MARKUP_SUB, MUTYPE_FONT, 0 }, |
| 284 | 286 | { "sup", MARKUP_SUP, MUTYPE_FONT, 0 }, |
| 285 | - { "table", MARKUP_TABLE, MUTYPE_TABLE, | |
| 287 | + { "table", MARKUP_TABLE, MUTYPE_TABLE, | |
| 286 | 288 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING| |
| 287 | 289 | AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE }, |
| 288 | - { "td", MARKUP_TD, MUTYPE_TD, | |
| 290 | + { "td", MARKUP_TD, MUTYPE_TD, | |
| 289 | 291 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| |
| 290 | 292 | AMSK_ROWSPAN|AMSK_VALIGN }, |
| 291 | 293 | { "th", MARKUP_TH, MUTYPE_TD, |
| 292 | 294 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| |
| 293 | 295 | AMSK_ROWSPAN|AMSK_VALIGN }, |
| 294 | - { "tr", MARKUP_TR, MUTYPE_TR, | |
| 296 | + { "tr", MARKUP_TR, MUTYPE_TR, | |
| 295 | 297 | AMSK_ALIGN|AMSK_BGCOLOR||AMSK_VALIGN }, |
| 296 | 298 | { "tt", MARKUP_TT, MUTYPE_FONT, 0 }, |
| 297 | 299 | { "u", MARKUP_U, MUTYPE_FONT, 0 }, |
| 298 | - { "ul", MARKUP_UL, MUTYPE_LIST, | |
| 300 | + { "ul", MARKUP_UL, MUTYPE_LIST, | |
| 299 | 301 | AMSK_TYPE|AMSK_COMPACT }, |
| 300 | 302 | { "var", MARKUP_VAR, MUTYPE_FONT, 0 }, |
| 301 | 303 | { "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL, AMSK_ID }, |
| 302 | 304 | }; |
| 303 | 305 | |
| @@ -332,11 +334,12 @@ | ||
| 332 | 334 | #define TOKEN_PARAGRAPH 4 /* blank lines */ |
| 333 | 335 | #define TOKEN_NEWLINE 5 /* A single "\n" */ |
| 334 | 336 | #define TOKEN_BULLET 6 /* " * " */ |
| 335 | 337 | #define TOKEN_ENUM 7 /* " \(?\d+[.)]? " */ |
| 336 | 338 | #define TOKEN_INDENT 8 /* " " */ |
| 337 | -#define TOKEN_TEXT 9 /* None of the above */ | |
| 339 | +#define TOKEN_COMMENT 9 /* <!-- --> */ | |
| 340 | +#define TOKEN_TEXT 10 /* None of the above */ | |
| 338 | 341 | |
| 339 | 342 | /* |
| 340 | 343 | ** State flags |
| 341 | 344 | */ |
| 342 | 345 | #define AT_NEWLINE 0x001 /* At start of a line */ |
| @@ -376,10 +379,28 @@ | ||
| 376 | 379 | ** it is not well-formed markup, return 0. |
| 377 | 380 | */ |
| 378 | 381 | static int markupLength(const char *z){ |
| 379 | 382 | int n = 1; |
| 380 | 383 | int inparen = 0; |
| 384 | + | |
| 385 | + // is a comment - if valid return n else return 0 | |
| 386 | + if( z[n]=='!' ){ | |
| 387 | + n++; | |
| 388 | + if (z[n]!='-') return 0; | |
| 389 | + n++; | |
| 390 | + if (z[n]!='-') return 0; | |
| 391 | + n++; | |
| 392 | + while (z[n]){ | |
| 393 | + while (z[n] && z[n]!='>') n++; | |
| 394 | + if (!z[n]) return 0; | |
| 395 | + n++; | |
| 396 | + if(n>3 && z[n-3]=='-' && z[n-2]=='-') | |
| 397 | + return (n>7) ? n : 0; | |
| 398 | + } | |
| 399 | + return 0; | |
| 400 | + } | |
| 401 | + | |
| 381 | 402 | if( z[n]=='/' ){ n++; } |
| 382 | 403 | if( !isalpha(z[n]) ) return 0; |
| 383 | 404 | while( isalnum(z[n]) ){ n++; } |
| 384 | 405 | if( z[n]!='>' && !isspace(z[n]) ) return 0; |
| 385 | 406 | while( z[n] && (z[n]!='>' || inparen) ){ |
| @@ -433,11 +454,11 @@ | ||
| 433 | 454 | while( (c = z[0])!=0 && c!='<' && c!='&' && |
| 434 | 455 | (useWiki==0 || (c!='[' && c!='\n')) ){ |
| 435 | 456 | n++; |
| 436 | 457 | z++; |
| 437 | 458 | } |
| 438 | - return n; | |
| 459 | + return n; | |
| 439 | 460 | } |
| 440 | 461 | |
| 441 | 462 | /* |
| 442 | 463 | ** Return true if z[] begins with an HTML character element. |
| 443 | 464 | */ |
| @@ -554,13 +575,19 @@ | ||
| 554 | 575 | */ |
| 555 | 576 | static int nextToken(const char *z, Renderer *p, int *pTokenType){ |
| 556 | 577 | int n; |
| 557 | 578 | if( z[0]=='<' ){ |
| 558 | 579 | n = markupLength(z); |
| 559 | - if( n>0 ){ | |
| 560 | - *pTokenType = TOKEN_MARKUP; | |
| 561 | - return n; | |
| 580 | + | |
| 581 | + if( n>1 ){ | |
| 582 | + if (z[1]=='!'){ | |
| 583 | + *pTokenType = TOKEN_COMMENT; | |
| 584 | + return n; | |
| 585 | + } else { | |
| 586 | + *pTokenType = TOKEN_MARKUP; | |
| 587 | + return n; | |
| 588 | + } | |
| 562 | 589 | }else{ |
| 563 | 590 | *pTokenType = TOKEN_CHARACTER; |
| 564 | 591 | return 1; |
| 565 | 592 | } |
| 566 | 593 | } |
| @@ -626,11 +653,11 @@ | ||
| 626 | 653 | |
| 627 | 654 | /* |
| 628 | 655 | ** z[] is an HTML markup element - something that begins with '<'. |
| 629 | 656 | ** Parse this element into the p structure. |
| 630 | 657 | ** |
| 631 | -** The content of z[] might be modified by converting characters | |
| 658 | +** The content of z[] might be modified by converting characters | |
| 632 | 659 | ** to lowercase and by inserting some "\000" characters. |
| 633 | 660 | */ |
| 634 | 661 | static void parseMarkup(ParsedMarkup *p, char *z){ |
| 635 | 662 | int i, j, c; |
| 636 | 663 | int iACode; |
| @@ -644,11 +671,11 @@ | ||
| 644 | 671 | }else{ |
| 645 | 672 | p->endTag = 0; |
| 646 | 673 | i = 1; |
| 647 | 674 | } |
| 648 | 675 | j = 0; |
| 649 | - while( isalnum(z[i]) ){ | |
| 676 | + while( isalnum(z[i]) ){ | |
| 650 | 677 | if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]); |
| 651 | 678 | i++; |
| 652 | 679 | } |
| 653 | 680 | zTag[j] = 0; |
| 654 | 681 | p->iCode = findTag(zTag); |
| @@ -656,11 +683,11 @@ | ||
| 656 | 683 | p->nAttr = 0; |
| 657 | 684 | while( isspace(z[i]) ){ i++; } |
| 658 | 685 | while( p->nAttr<8 && isalpha(z[i]) ){ |
| 659 | 686 | int attrOk; /* True to preserver attribute. False to ignore it */ |
| 660 | 687 | j = 0; |
| 661 | - while( isalnum(z[i]) ){ | |
| 688 | + while( isalnum(z[i]) ){ | |
| 662 | 689 | if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]); |
| 663 | 690 | i++; |
| 664 | 691 | } |
| 665 | 692 | zTag[j] = 0; |
| 666 | 693 | p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag); |
| @@ -799,11 +826,11 @@ | ||
| 799 | 826 | } |
| 800 | 827 | } |
| 801 | 828 | |
| 802 | 829 | /* |
| 803 | 830 | ** Attempt to find a find a tag of type iTag with id zId. Return -1 |
| 804 | -** if not found. If found, return its stack level. | |
| 831 | +** if not found. If found, return its stack level. | |
| 805 | 832 | */ |
| 806 | 833 | static int findTagWithId(Renderer *p, int iTag, const char *zId){ |
| 807 | 834 | int i; |
| 808 | 835 | assert( zId!=0 ); |
| 809 | 836 | for(i=p->nStack-1; i>=0; i--){ |
| @@ -889,11 +916,11 @@ | ||
| 889 | 916 | canonical16(zLower, n+1); |
| 890 | 917 | memcpy(zUpper, zLower, n+1); |
| 891 | 918 | zUpper[n-1]++; |
| 892 | 919 | if( once ){ |
| 893 | 920 | const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); |
| 894 | - db_static_prepare(&q, | |
| 921 | + db_static_prepare(&q, | |
| 895 | 922 | "SELECT %s FROM ticket " |
| 896 | 923 | " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", |
| 897 | 924 | zClosedExpr |
| 898 | 925 | ); |
| 899 | 926 | once = 0; |
| @@ -927,13 +954,13 @@ | ||
| 927 | 954 | int nClose /* Bytes available in zClose[] */ |
| 928 | 955 | ){ |
| 929 | 956 | const char *zTerm = "</a>"; |
| 930 | 957 | assert( nClose>10 ); |
| 931 | 958 | |
| 932 | - if( strncmp(zTarget, "http:", 5)==0 | |
| 959 | + if( strncmp(zTarget, "http:", 5)==0 | |
| 933 | 960 | || strncmp(zTarget, "https:", 6)==0 |
| 934 | - || strncmp(zTarget, "ftp:", 4)==0 | |
| 961 | + || strncmp(zTarget, "ftp:", 4)==0 | |
| 935 | 962 | || strncmp(zTarget, "mailto:", 7)==0 |
| 936 | 963 | ){ |
| 937 | 964 | blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); |
| 938 | 965 | }else if( zTarget[0]=='/' ){ |
| 939 | 966 | if( 1 /* g.okHistory */ ){ |
| @@ -1022,10 +1049,19 @@ | ||
| 1022 | 1049 | |
| 1023 | 1050 | while( z[0] ){ |
| 1024 | 1051 | n = nextToken(z, p, &tokenType); |
| 1025 | 1052 | p->state &= ~(AT_NEWLINE|AT_PARAGRAPH); |
| 1026 | 1053 | switch( tokenType ){ |
| 1054 | + | |
| 1055 | + case TOKEN_COMMENT: { | |
| 1056 | + if (p->inVerbatim){ | |
| 1057 | + blob_append(p->pOut, htmlize(z, n), -1); | |
| 1058 | + } else { | |
| 1059 | + blob_append(p->pOut, z, n); | |
| 1060 | + } | |
| 1061 | + break; | |
| 1062 | + } | |
| 1027 | 1063 | case TOKEN_PARAGRAPH: { |
| 1028 | 1064 | if( inlineOnly ){ |
| 1029 | 1065 | /* blob_append(p->pOut, " ¶ ", -1); */ |
| 1030 | 1066 | blob_append(p->pOut, " ", -1); |
| 1031 | 1067 | }else{ |
| @@ -1143,11 +1179,11 @@ | ||
| 1143 | 1179 | int iDiv; |
| 1144 | 1180 | parseMarkup(&markup, z); |
| 1145 | 1181 | |
| 1146 | 1182 | /* Markup of the form </div id=ID> where there is a matching |
| 1147 | 1183 | ** ID somewhere on the stack. Exit the verbatim if were are in |
| 1148 | - ** it. Pop the stack up to the matching <div>. Discard the | |
| 1184 | + ** it. Pop the stack up to the matching <div>. Discard the | |
| 1149 | 1185 | ** </div> |
| 1150 | 1186 | */ |
| 1151 | 1187 | if( markup.iCode==MARKUP_DIV && markup.endTag && |
| 1152 | 1188 | (zId = markupId(&markup))!=0 && |
| 1153 | 1189 | (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0 |
| @@ -1167,11 +1203,11 @@ | ||
| 1167 | 1203 | p->nStack--; |
| 1168 | 1204 | }else |
| 1169 | 1205 | |
| 1170 | 1206 | /* If within <verbatim id=ID> ignore everything other than |
| 1171 | 1207 | ** </verbatim id=ID> and the </dev id=ID2> above. |
| 1172 | - */ | |
| 1208 | + */ | |
| 1173 | 1209 | if( p->inVerbatim ){ |
| 1174 | 1210 | if( endVerbatim(p, &markup) ){ |
| 1175 | 1211 | p->inVerbatim = 0; |
| 1176 | 1212 | p->state = p->preVerbState; |
| 1177 | 1213 | blob_append(p->pOut, "</pre>", 6); |
| @@ -1225,11 +1261,11 @@ | ||
| 1225 | 1261 | (p->state & ALLOW_WIKI)!=0); |
| 1226 | 1262 | }else |
| 1227 | 1263 | |
| 1228 | 1264 | /* Enter <verbatim> processing. With verbatim enabled, all other |
| 1229 | 1265 | ** markup other than the corresponding end-tag with the same ID is |
| 1230 | - ** ignored. | |
| 1266 | + ** ignored. | |
| 1231 | 1267 | */ |
| 1232 | 1268 | if( markup.iCode==MARKUP_VERBATIM ){ |
| 1233 | 1269 | if( markup.nAttr==1 ){ |
| 1234 | 1270 | p->zVerbatimId = markup.aAttr[0].zValue; |
| 1235 | 1271 | }else{ |
| @@ -1298,11 +1334,11 @@ | ||
| 1298 | 1334 | ** reply. |
| 1299 | 1335 | */ |
| 1300 | 1336 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1301 | 1337 | char *z; |
| 1302 | 1338 | Renderer renderer; |
| 1303 | - | |
| 1339 | + | |
| 1304 | 1340 | memset(&renderer, 0, sizeof(renderer)); |
| 1305 | 1341 | renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; |
| 1306 | 1342 | if( flags & WIKI_NOBLOCK ){ |
| 1307 | 1343 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1308 | 1344 | } |
| 1309 | 1345 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -7,11 +7,11 @@ | |
| 7 | ** |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 11 | ** General Public License for more details. |
| 12 | ** |
| 13 | ** You should have received a copy of the GNU General Public |
| 14 | ** License along with this library; if not, write to the |
| 15 | ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 16 | ** Boston, MA 02111-1307, USA. |
| 17 | ** |
| @@ -150,11 +150,11 @@ | |
| 150 | /* |
| 151 | ** Allowed markup. |
| 152 | ** |
| 153 | ** Except for MARKUP_INVALID, this must all be in alphabetical order |
| 154 | ** and in numerical sequence. The first markup type must be zero. |
| 155 | ** The value for MARKUP_XYZ must correspond to the <xyz> entry |
| 156 | ** in aAllowedMarkup[]. |
| 157 | */ |
| 158 | #define MARKUP_INVALID 0 |
| 159 | #define MARKUP_A 1 |
| 160 | #define MARKUP_ADDRESS 2 |
| @@ -189,23 +189,24 @@ | |
| 189 | #define MARKUP_P 31 |
| 190 | #define MARKUP_PRE 32 |
| 191 | #define MARKUP_S 33 |
| 192 | #define MARKUP_SAMP 34 |
| 193 | #define MARKUP_SMALL 35 |
| 194 | #define MARKUP_STRIKE 36 |
| 195 | #define MARKUP_STRONG 37 |
| 196 | #define MARKUP_SUB 38 |
| 197 | #define MARKUP_SUP 39 |
| 198 | #define MARKUP_TABLE 40 |
| 199 | #define MARKUP_TD 41 |
| 200 | #define MARKUP_TH 42 |
| 201 | #define MARKUP_TR 43 |
| 202 | #define MARKUP_TT 44 |
| 203 | #define MARKUP_U 45 |
| 204 | #define MARKUP_UL 46 |
| 205 | #define MARKUP_VAR 47 |
| 206 | #define MARKUP_VERBATIM 48 |
| 207 | |
| 208 | /* |
| 209 | ** The various markup is divided into the following types: |
| 210 | */ |
| 211 | #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */ |
| @@ -258,46 +259,47 @@ | |
| 258 | { "h2", MARKUP_H2, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 259 | { "h3", MARKUP_H3, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 260 | { "h4", MARKUP_H4, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 261 | { "h5", MARKUP_H5, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 262 | { "h6", MARKUP_H6, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 263 | { "hr", MARKUP_HR, MUTYPE_SINGLE, |
| 264 | AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH }, |
| 265 | { "i", MARKUP_I, MUTYPE_FONT, 0 }, |
| 266 | { "img", MARKUP_IMG, MUTYPE_SINGLE, |
| 267 | AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT| |
| 268 | AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH }, |
| 269 | { "kbd", MARKUP_KBD, MUTYPE_FONT, 0 }, |
| 270 | { "li", MARKUP_LI, MUTYPE_LI, |
| 271 | AMSK_TYPE|AMSK_VALUE }, |
| 272 | { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 }, |
| 273 | { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 }, |
| 274 | { "ol", MARKUP_OL, MUTYPE_LIST, |
| 275 | AMSK_START|AMSK_TYPE|AMSK_COMPACT }, |
| 276 | { "p", MARKUP_P, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 277 | { "pre", MARKUP_PRE, MUTYPE_BLOCK, 0 }, |
| 278 | { "s", MARKUP_S, MUTYPE_FONT, 0 }, |
| 279 | { "samp", MARKUP_SAMP, MUTYPE_FONT, 0 }, |
| 280 | { "small", MARKUP_SMALL, MUTYPE_FONT, 0 }, |
| 281 | { "strike", MARKUP_STRIKE, MUTYPE_FONT, 0 }, |
| 282 | { "strong", MARKUP_STRONG, MUTYPE_FONT, 0 }, |
| 283 | { "sub", MARKUP_SUB, MUTYPE_FONT, 0 }, |
| 284 | { "sup", MARKUP_SUP, MUTYPE_FONT, 0 }, |
| 285 | { "table", MARKUP_TABLE, MUTYPE_TABLE, |
| 286 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING| |
| 287 | AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE }, |
| 288 | { "td", MARKUP_TD, MUTYPE_TD, |
| 289 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| |
| 290 | AMSK_ROWSPAN|AMSK_VALIGN }, |
| 291 | { "th", MARKUP_TH, MUTYPE_TD, |
| 292 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| |
| 293 | AMSK_ROWSPAN|AMSK_VALIGN }, |
| 294 | { "tr", MARKUP_TR, MUTYPE_TR, |
| 295 | AMSK_ALIGN|AMSK_BGCOLOR||AMSK_VALIGN }, |
| 296 | { "tt", MARKUP_TT, MUTYPE_FONT, 0 }, |
| 297 | { "u", MARKUP_U, MUTYPE_FONT, 0 }, |
| 298 | { "ul", MARKUP_UL, MUTYPE_LIST, |
| 299 | AMSK_TYPE|AMSK_COMPACT }, |
| 300 | { "var", MARKUP_VAR, MUTYPE_FONT, 0 }, |
| 301 | { "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL, AMSK_ID }, |
| 302 | }; |
| 303 | |
| @@ -332,11 +334,12 @@ | |
| 332 | #define TOKEN_PARAGRAPH 4 /* blank lines */ |
| 333 | #define TOKEN_NEWLINE 5 /* A single "\n" */ |
| 334 | #define TOKEN_BULLET 6 /* " * " */ |
| 335 | #define TOKEN_ENUM 7 /* " \(?\d+[.)]? " */ |
| 336 | #define TOKEN_INDENT 8 /* " " */ |
| 337 | #define TOKEN_TEXT 9 /* None of the above */ |
| 338 | |
| 339 | /* |
| 340 | ** State flags |
| 341 | */ |
| 342 | #define AT_NEWLINE 0x001 /* At start of a line */ |
| @@ -376,10 +379,28 @@ | |
| 376 | ** it is not well-formed markup, return 0. |
| 377 | */ |
| 378 | static int markupLength(const char *z){ |
| 379 | int n = 1; |
| 380 | int inparen = 0; |
| 381 | if( z[n]=='/' ){ n++; } |
| 382 | if( !isalpha(z[n]) ) return 0; |
| 383 | while( isalnum(z[n]) ){ n++; } |
| 384 | if( z[n]!='>' && !isspace(z[n]) ) return 0; |
| 385 | while( z[n] && (z[n]!='>' || inparen) ){ |
| @@ -433,11 +454,11 @@ | |
| 433 | while( (c = z[0])!=0 && c!='<' && c!='&' && |
| 434 | (useWiki==0 || (c!='[' && c!='\n')) ){ |
| 435 | n++; |
| 436 | z++; |
| 437 | } |
| 438 | return n; |
| 439 | } |
| 440 | |
| 441 | /* |
| 442 | ** Return true if z[] begins with an HTML character element. |
| 443 | */ |
| @@ -554,13 +575,19 @@ | |
| 554 | */ |
| 555 | static int nextToken(const char *z, Renderer *p, int *pTokenType){ |
| 556 | int n; |
| 557 | if( z[0]=='<' ){ |
| 558 | n = markupLength(z); |
| 559 | if( n>0 ){ |
| 560 | *pTokenType = TOKEN_MARKUP; |
| 561 | return n; |
| 562 | }else{ |
| 563 | *pTokenType = TOKEN_CHARACTER; |
| 564 | return 1; |
| 565 | } |
| 566 | } |
| @@ -626,11 +653,11 @@ | |
| 626 | |
| 627 | /* |
| 628 | ** z[] is an HTML markup element - something that begins with '<'. |
| 629 | ** Parse this element into the p structure. |
| 630 | ** |
| 631 | ** The content of z[] might be modified by converting characters |
| 632 | ** to lowercase and by inserting some "\000" characters. |
| 633 | */ |
| 634 | static void parseMarkup(ParsedMarkup *p, char *z){ |
| 635 | int i, j, c; |
| 636 | int iACode; |
| @@ -644,11 +671,11 @@ | |
| 644 | }else{ |
| 645 | p->endTag = 0; |
| 646 | i = 1; |
| 647 | } |
| 648 | j = 0; |
| 649 | while( isalnum(z[i]) ){ |
| 650 | if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]); |
| 651 | i++; |
| 652 | } |
| 653 | zTag[j] = 0; |
| 654 | p->iCode = findTag(zTag); |
| @@ -656,11 +683,11 @@ | |
| 656 | p->nAttr = 0; |
| 657 | while( isspace(z[i]) ){ i++; } |
| 658 | while( p->nAttr<8 && isalpha(z[i]) ){ |
| 659 | int attrOk; /* True to preserver attribute. False to ignore it */ |
| 660 | j = 0; |
| 661 | while( isalnum(z[i]) ){ |
| 662 | if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]); |
| 663 | i++; |
| 664 | } |
| 665 | zTag[j] = 0; |
| 666 | p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag); |
| @@ -799,11 +826,11 @@ | |
| 799 | } |
| 800 | } |
| 801 | |
| 802 | /* |
| 803 | ** Attempt to find a find a tag of type iTag with id zId. Return -1 |
| 804 | ** if not found. If found, return its stack level. |
| 805 | */ |
| 806 | static int findTagWithId(Renderer *p, int iTag, const char *zId){ |
| 807 | int i; |
| 808 | assert( zId!=0 ); |
| 809 | for(i=p->nStack-1; i>=0; i--){ |
| @@ -889,11 +916,11 @@ | |
| 889 | canonical16(zLower, n+1); |
| 890 | memcpy(zUpper, zLower, n+1); |
| 891 | zUpper[n-1]++; |
| 892 | if( once ){ |
| 893 | const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); |
| 894 | db_static_prepare(&q, |
| 895 | "SELECT %s FROM ticket " |
| 896 | " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", |
| 897 | zClosedExpr |
| 898 | ); |
| 899 | once = 0; |
| @@ -927,13 +954,13 @@ | |
| 927 | int nClose /* Bytes available in zClose[] */ |
| 928 | ){ |
| 929 | const char *zTerm = "</a>"; |
| 930 | assert( nClose>10 ); |
| 931 | |
| 932 | if( strncmp(zTarget, "http:", 5)==0 |
| 933 | || strncmp(zTarget, "https:", 6)==0 |
| 934 | || strncmp(zTarget, "ftp:", 4)==0 |
| 935 | || strncmp(zTarget, "mailto:", 7)==0 |
| 936 | ){ |
| 937 | blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); |
| 938 | }else if( zTarget[0]=='/' ){ |
| 939 | if( 1 /* g.okHistory */ ){ |
| @@ -1022,10 +1049,19 @@ | |
| 1022 | |
| 1023 | while( z[0] ){ |
| 1024 | n = nextToken(z, p, &tokenType); |
| 1025 | p->state &= ~(AT_NEWLINE|AT_PARAGRAPH); |
| 1026 | switch( tokenType ){ |
| 1027 | case TOKEN_PARAGRAPH: { |
| 1028 | if( inlineOnly ){ |
| 1029 | /* blob_append(p->pOut, " ¶ ", -1); */ |
| 1030 | blob_append(p->pOut, " ", -1); |
| 1031 | }else{ |
| @@ -1143,11 +1179,11 @@ | |
| 1143 | int iDiv; |
| 1144 | parseMarkup(&markup, z); |
| 1145 | |
| 1146 | /* Markup of the form </div id=ID> where there is a matching |
| 1147 | ** ID somewhere on the stack. Exit the verbatim if were are in |
| 1148 | ** it. Pop the stack up to the matching <div>. Discard the |
| 1149 | ** </div> |
| 1150 | */ |
| 1151 | if( markup.iCode==MARKUP_DIV && markup.endTag && |
| 1152 | (zId = markupId(&markup))!=0 && |
| 1153 | (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0 |
| @@ -1167,11 +1203,11 @@ | |
| 1167 | p->nStack--; |
| 1168 | }else |
| 1169 | |
| 1170 | /* If within <verbatim id=ID> ignore everything other than |
| 1171 | ** </verbatim id=ID> and the </dev id=ID2> above. |
| 1172 | */ |
| 1173 | if( p->inVerbatim ){ |
| 1174 | if( endVerbatim(p, &markup) ){ |
| 1175 | p->inVerbatim = 0; |
| 1176 | p->state = p->preVerbState; |
| 1177 | blob_append(p->pOut, "</pre>", 6); |
| @@ -1225,11 +1261,11 @@ | |
| 1225 | (p->state & ALLOW_WIKI)!=0); |
| 1226 | }else |
| 1227 | |
| 1228 | /* Enter <verbatim> processing. With verbatim enabled, all other |
| 1229 | ** markup other than the corresponding end-tag with the same ID is |
| 1230 | ** ignored. |
| 1231 | */ |
| 1232 | if( markup.iCode==MARKUP_VERBATIM ){ |
| 1233 | if( markup.nAttr==1 ){ |
| 1234 | p->zVerbatimId = markup.aAttr[0].zValue; |
| 1235 | }else{ |
| @@ -1298,11 +1334,11 @@ | |
| 1298 | ** reply. |
| 1299 | */ |
| 1300 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1301 | char *z; |
| 1302 | Renderer renderer; |
| 1303 | |
| 1304 | memset(&renderer, 0, sizeof(renderer)); |
| 1305 | renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; |
| 1306 | if( flags & WIKI_NOBLOCK ){ |
| 1307 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1308 | } |
| 1309 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -7,11 +7,11 @@ | |
| 7 | ** |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 11 | ** General Public License for more details. |
| 12 | ** |
| 13 | ** You should have received a copy of the GNU General Public |
| 14 | ** License along with this library; if not, write to the |
| 15 | ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 16 | ** Boston, MA 02111-1307, USA. |
| 17 | ** |
| @@ -150,11 +150,11 @@ | |
| 150 | /* |
| 151 | ** Allowed markup. |
| 152 | ** |
| 153 | ** Except for MARKUP_INVALID, this must all be in alphabetical order |
| 154 | ** and in numerical sequence. The first markup type must be zero. |
| 155 | ** The value for MARKUP_XYZ must correspond to the <xyz> entry |
| 156 | ** in aAllowedMarkup[]. |
| 157 | */ |
| 158 | #define MARKUP_INVALID 0 |
| 159 | #define MARKUP_A 1 |
| 160 | #define MARKUP_ADDRESS 2 |
| @@ -189,23 +189,24 @@ | |
| 189 | #define MARKUP_P 31 |
| 190 | #define MARKUP_PRE 32 |
| 191 | #define MARKUP_S 33 |
| 192 | #define MARKUP_SAMP 34 |
| 193 | #define MARKUP_SMALL 35 |
| 194 | #define MARKUP_SPAN 36 |
| 195 | #define MARKUP_STRIKE 37 |
| 196 | #define MARKUP_STRONG 38 |
| 197 | #define MARKUP_SUB 39 |
| 198 | #define MARKUP_SUP 40 |
| 199 | #define MARKUP_TABLE 41 |
| 200 | #define MARKUP_TD 42 |
| 201 | #define MARKUP_TH 43 |
| 202 | #define MARKUP_TR 44 |
| 203 | #define MARKUP_TT 45 |
| 204 | #define MARKUP_U 46 |
| 205 | #define MARKUP_UL 47 |
| 206 | #define MARKUP_VAR 48 |
| 207 | #define MARKUP_VERBATIM 49 |
| 208 | |
| 209 | /* |
| 210 | ** The various markup is divided into the following types: |
| 211 | */ |
| 212 | #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */ |
| @@ -258,46 +259,47 @@ | |
| 259 | { "h2", MARKUP_H2, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 260 | { "h3", MARKUP_H3, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 261 | { "h4", MARKUP_H4, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 262 | { "h5", MARKUP_H5, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 263 | { "h6", MARKUP_H6, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 264 | { "hr", MARKUP_HR, MUTYPE_SINGLE, |
| 265 | AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH }, |
| 266 | { "i", MARKUP_I, MUTYPE_FONT, 0 }, |
| 267 | { "img", MARKUP_IMG, MUTYPE_SINGLE, |
| 268 | AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT| |
| 269 | AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH }, |
| 270 | { "kbd", MARKUP_KBD, MUTYPE_FONT, 0 }, |
| 271 | { "li", MARKUP_LI, MUTYPE_LI, |
| 272 | AMSK_TYPE|AMSK_VALUE }, |
| 273 | { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 }, |
| 274 | { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 }, |
| 275 | { "ol", MARKUP_OL, MUTYPE_LIST, |
| 276 | AMSK_START|AMSK_TYPE|AMSK_COMPACT }, |
| 277 | { "p", MARKUP_P, MUTYPE_BLOCK, AMSK_ALIGN }, |
| 278 | { "pre", MARKUP_PRE, MUTYPE_BLOCK, 0 }, |
| 279 | { "s", MARKUP_S, MUTYPE_FONT, 0 }, |
| 280 | { "samp", MARKUP_SAMP, MUTYPE_FONT, 0 }, |
| 281 | { "small", MARKUP_SMALL, MUTYPE_FONT, 0 }, |
| 282 | { "span", MARKUP_SPAN, MUTYPE_FONT, 0 }, |
| 283 | { "strike", MARKUP_STRIKE, MUTYPE_FONT, 0 }, |
| 284 | { "strong", MARKUP_STRONG, MUTYPE_FONT, 0 }, |
| 285 | { "sub", MARKUP_SUB, MUTYPE_FONT, 0 }, |
| 286 | { "sup", MARKUP_SUP, MUTYPE_FONT, 0 }, |
| 287 | { "table", MARKUP_TABLE, MUTYPE_TABLE, |
| 288 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING| |
| 289 | AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE }, |
| 290 | { "td", MARKUP_TD, MUTYPE_TD, |
| 291 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| |
| 292 | AMSK_ROWSPAN|AMSK_VALIGN }, |
| 293 | { "th", MARKUP_TH, MUTYPE_TD, |
| 294 | AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN| |
| 295 | AMSK_ROWSPAN|AMSK_VALIGN }, |
| 296 | { "tr", MARKUP_TR, MUTYPE_TR, |
| 297 | AMSK_ALIGN|AMSK_BGCOLOR||AMSK_VALIGN }, |
| 298 | { "tt", MARKUP_TT, MUTYPE_FONT, 0 }, |
| 299 | { "u", MARKUP_U, MUTYPE_FONT, 0 }, |
| 300 | { "ul", MARKUP_UL, MUTYPE_LIST, |
| 301 | AMSK_TYPE|AMSK_COMPACT }, |
| 302 | { "var", MARKUP_VAR, MUTYPE_FONT, 0 }, |
| 303 | { "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL, AMSK_ID }, |
| 304 | }; |
| 305 | |
| @@ -332,11 +334,12 @@ | |
| 334 | #define TOKEN_PARAGRAPH 4 /* blank lines */ |
| 335 | #define TOKEN_NEWLINE 5 /* A single "\n" */ |
| 336 | #define TOKEN_BULLET 6 /* " * " */ |
| 337 | #define TOKEN_ENUM 7 /* " \(?\d+[.)]? " */ |
| 338 | #define TOKEN_INDENT 8 /* " " */ |
| 339 | #define TOKEN_COMMENT 9 /* <!-- --> */ |
| 340 | #define TOKEN_TEXT 10 /* None of the above */ |
| 341 | |
| 342 | /* |
| 343 | ** State flags |
| 344 | */ |
| 345 | #define AT_NEWLINE 0x001 /* At start of a line */ |
| @@ -376,10 +379,28 @@ | |
| 379 | ** it is not well-formed markup, return 0. |
| 380 | */ |
| 381 | static int markupLength(const char *z){ |
| 382 | int n = 1; |
| 383 | int inparen = 0; |
| 384 | |
| 385 | // is a comment - if valid return n else return 0 |
| 386 | if( z[n]=='!' ){ |
| 387 | n++; |
| 388 | if (z[n]!='-') return 0; |
| 389 | n++; |
| 390 | if (z[n]!='-') return 0; |
| 391 | n++; |
| 392 | while (z[n]){ |
| 393 | while (z[n] && z[n]!='>') n++; |
| 394 | if (!z[n]) return 0; |
| 395 | n++; |
| 396 | if(n>3 && z[n-3]=='-' && z[n-2]=='-') |
| 397 | return (n>7) ? n : 0; |
| 398 | } |
| 399 | return 0; |
| 400 | } |
| 401 | |
| 402 | if( z[n]=='/' ){ n++; } |
| 403 | if( !isalpha(z[n]) ) return 0; |
| 404 | while( isalnum(z[n]) ){ n++; } |
| 405 | if( z[n]!='>' && !isspace(z[n]) ) return 0; |
| 406 | while( z[n] && (z[n]!='>' || inparen) ){ |
| @@ -433,11 +454,11 @@ | |
| 454 | while( (c = z[0])!=0 && c!='<' && c!='&' && |
| 455 | (useWiki==0 || (c!='[' && c!='\n')) ){ |
| 456 | n++; |
| 457 | z++; |
| 458 | } |
| 459 | return n; |
| 460 | } |
| 461 | |
| 462 | /* |
| 463 | ** Return true if z[] begins with an HTML character element. |
| 464 | */ |
| @@ -554,13 +575,19 @@ | |
| 575 | */ |
| 576 | static int nextToken(const char *z, Renderer *p, int *pTokenType){ |
| 577 | int n; |
| 578 | if( z[0]=='<' ){ |
| 579 | n = markupLength(z); |
| 580 | |
| 581 | if( n>1 ){ |
| 582 | if (z[1]=='!'){ |
| 583 | *pTokenType = TOKEN_COMMENT; |
| 584 | return n; |
| 585 | } else { |
| 586 | *pTokenType = TOKEN_MARKUP; |
| 587 | return n; |
| 588 | } |
| 589 | }else{ |
| 590 | *pTokenType = TOKEN_CHARACTER; |
| 591 | return 1; |
| 592 | } |
| 593 | } |
| @@ -626,11 +653,11 @@ | |
| 653 | |
| 654 | /* |
| 655 | ** z[] is an HTML markup element - something that begins with '<'. |
| 656 | ** Parse this element into the p structure. |
| 657 | ** |
| 658 | ** The content of z[] might be modified by converting characters |
| 659 | ** to lowercase and by inserting some "\000" characters. |
| 660 | */ |
| 661 | static void parseMarkup(ParsedMarkup *p, char *z){ |
| 662 | int i, j, c; |
| 663 | int iACode; |
| @@ -644,11 +671,11 @@ | |
| 671 | }else{ |
| 672 | p->endTag = 0; |
| 673 | i = 1; |
| 674 | } |
| 675 | j = 0; |
| 676 | while( isalnum(z[i]) ){ |
| 677 | if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]); |
| 678 | i++; |
| 679 | } |
| 680 | zTag[j] = 0; |
| 681 | p->iCode = findTag(zTag); |
| @@ -656,11 +683,11 @@ | |
| 683 | p->nAttr = 0; |
| 684 | while( isspace(z[i]) ){ i++; } |
| 685 | while( p->nAttr<8 && isalpha(z[i]) ){ |
| 686 | int attrOk; /* True to preserver attribute. False to ignore it */ |
| 687 | j = 0; |
| 688 | while( isalnum(z[i]) ){ |
| 689 | if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]); |
| 690 | i++; |
| 691 | } |
| 692 | zTag[j] = 0; |
| 693 | p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag); |
| @@ -799,11 +826,11 @@ | |
| 826 | } |
| 827 | } |
| 828 | |
| 829 | /* |
| 830 | ** Attempt to find a find a tag of type iTag with id zId. Return -1 |
| 831 | ** if not found. If found, return its stack level. |
| 832 | */ |
| 833 | static int findTagWithId(Renderer *p, int iTag, const char *zId){ |
| 834 | int i; |
| 835 | assert( zId!=0 ); |
| 836 | for(i=p->nStack-1; i>=0; i--){ |
| @@ -889,11 +916,11 @@ | |
| 916 | canonical16(zLower, n+1); |
| 917 | memcpy(zUpper, zLower, n+1); |
| 918 | zUpper[n-1]++; |
| 919 | if( once ){ |
| 920 | const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); |
| 921 | db_static_prepare(&q, |
| 922 | "SELECT %s FROM ticket " |
| 923 | " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", |
| 924 | zClosedExpr |
| 925 | ); |
| 926 | once = 0; |
| @@ -927,13 +954,13 @@ | |
| 954 | int nClose /* Bytes available in zClose[] */ |
| 955 | ){ |
| 956 | const char *zTerm = "</a>"; |
| 957 | assert( nClose>10 ); |
| 958 | |
| 959 | if( strncmp(zTarget, "http:", 5)==0 |
| 960 | || strncmp(zTarget, "https:", 6)==0 |
| 961 | || strncmp(zTarget, "ftp:", 4)==0 |
| 962 | || strncmp(zTarget, "mailto:", 7)==0 |
| 963 | ){ |
| 964 | blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); |
| 965 | }else if( zTarget[0]=='/' ){ |
| 966 | if( 1 /* g.okHistory */ ){ |
| @@ -1022,10 +1049,19 @@ | |
| 1049 | |
| 1050 | while( z[0] ){ |
| 1051 | n = nextToken(z, p, &tokenType); |
| 1052 | p->state &= ~(AT_NEWLINE|AT_PARAGRAPH); |
| 1053 | switch( tokenType ){ |
| 1054 | |
| 1055 | case TOKEN_COMMENT: { |
| 1056 | if (p->inVerbatim){ |
| 1057 | blob_append(p->pOut, htmlize(z, n), -1); |
| 1058 | } else { |
| 1059 | blob_append(p->pOut, z, n); |
| 1060 | } |
| 1061 | break; |
| 1062 | } |
| 1063 | case TOKEN_PARAGRAPH: { |
| 1064 | if( inlineOnly ){ |
| 1065 | /* blob_append(p->pOut, " ¶ ", -1); */ |
| 1066 | blob_append(p->pOut, " ", -1); |
| 1067 | }else{ |
| @@ -1143,11 +1179,11 @@ | |
| 1179 | int iDiv; |
| 1180 | parseMarkup(&markup, z); |
| 1181 | |
| 1182 | /* Markup of the form </div id=ID> where there is a matching |
| 1183 | ** ID somewhere on the stack. Exit the verbatim if were are in |
| 1184 | ** it. Pop the stack up to the matching <div>. Discard the |
| 1185 | ** </div> |
| 1186 | */ |
| 1187 | if( markup.iCode==MARKUP_DIV && markup.endTag && |
| 1188 | (zId = markupId(&markup))!=0 && |
| 1189 | (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0 |
| @@ -1167,11 +1203,11 @@ | |
| 1203 | p->nStack--; |
| 1204 | }else |
| 1205 | |
| 1206 | /* If within <verbatim id=ID> ignore everything other than |
| 1207 | ** </verbatim id=ID> and the </dev id=ID2> above. |
| 1208 | */ |
| 1209 | if( p->inVerbatim ){ |
| 1210 | if( endVerbatim(p, &markup) ){ |
| 1211 | p->inVerbatim = 0; |
| 1212 | p->state = p->preVerbState; |
| 1213 | blob_append(p->pOut, "</pre>", 6); |
| @@ -1225,11 +1261,11 @@ | |
| 1261 | (p->state & ALLOW_WIKI)!=0); |
| 1262 | }else |
| 1263 | |
| 1264 | /* Enter <verbatim> processing. With verbatim enabled, all other |
| 1265 | ** markup other than the corresponding end-tag with the same ID is |
| 1266 | ** ignored. |
| 1267 | */ |
| 1268 | if( markup.iCode==MARKUP_VERBATIM ){ |
| 1269 | if( markup.nAttr==1 ){ |
| 1270 | p->zVerbatimId = markup.aAttr[0].zValue; |
| 1271 | }else{ |
| @@ -1298,11 +1334,11 @@ | |
| 1334 | ** reply. |
| 1335 | */ |
| 1336 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1337 | char *z; |
| 1338 | Renderer renderer; |
| 1339 | |
| 1340 | memset(&renderer, 0, sizeof(renderer)); |
| 1341 | renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; |
| 1342 | if( flags & WIKI_NOBLOCK ){ |
| 1343 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1344 | } |
| 1345 |