Fossil SCM
Add support for magic conversion of /doc/$SELF/ URIs by expanding the $SELF to the version of the currently displayed document.
Commit
703e62a68e87aea76d753ffb0410ea2997f5b88dc7cb99191a40f78ffd099dcd
Parent
367f9b32d677bc4…
2 files changed
+42
+49
-2
+42
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -507,10 +507,39 @@ | ||
| 507 | 507 | if( rid && content_get(rid, pContent)==0 ){ |
| 508 | 508 | rid = 0; |
| 509 | 509 | } |
| 510 | 510 | return rid; |
| 511 | 511 | } |
| 512 | + | |
| 513 | +/* | |
| 514 | +** Check to verify that z[i] is contained within HTML markup. | |
| 515 | +** | |
| 516 | +** This works by looking backwards in the string for the most recent | |
| 517 | +** '<' or '>' character. If a '<' is found first, then we assume that | |
| 518 | +** z[i] is within markup. If a '>' is seen or neither character is seen, | |
| 519 | +** then z[i] is not within markup. | |
| 520 | +*/ | |
| 521 | +static int isWithinHtmlMarkup(const char *z, int i){ | |
| 522 | + while( i>=0 && z[i]!='>' && z[i]!='<' ){ i--; } | |
| 523 | + return z[i]=='<'; | |
| 524 | +} | |
| 525 | + | |
| 526 | +/* | |
| 527 | +** Check to see if z[i] is contained within an href='...' of markup. | |
| 528 | +*/ | |
| 529 | +static int isWithinHref(const char *z, int i){ | |
| 530 | + while( i>5 | |
| 531 | + && !fossil_isspace(z[i]) | |
| 532 | + && z[i]!='\'' && z[i]!='"' | |
| 533 | + && z[i]!='>' | |
| 534 | + ){ i--; } | |
| 535 | + if( i<=6 ) return 0; | |
| 536 | + if( z[i]!='\'' && z[i]!='\"' ) return 0; | |
| 537 | + if( strncmp(&z[i-5],"href=",5)!=0 ) return 0; | |
| 538 | + if( !fossil_isspace(z[i-6]) ) return 0; | |
| 539 | + return 1; | |
| 540 | +} | |
| 512 | 541 | |
| 513 | 542 | /* |
| 514 | 543 | ** Transfer content to the output. During the transfer, when text of |
| 515 | 544 | ** the following form is seen: |
| 516 | 545 | ** |
| @@ -529,14 +558,27 @@ | ||
| 529 | 558 | && strncmp(&z[i],"$ROOT/", 6)==0 |
| 530 | 559 | && (z[i-1]=='\'' || z[i-1]=='"') |
| 531 | 560 | && i-base>=9 |
| 532 | 561 | && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) || |
| 533 | 562 | (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) ) |
| 563 | + && isWithinHtmlMarkup(z, i-6) | |
| 534 | 564 | ){ |
| 535 | 565 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 536 | 566 | blob_appendf(cgi_output_blob(), "%R"); |
| 537 | 567 | base = i+5; |
| 568 | + }else | |
| 569 | + if( z[i]=='$' | |
| 570 | + && strncmp(&z[i-5],"/doc/$SELF/", 11)==0 | |
| 571 | + && isWithinHref(z,i-5) | |
| 572 | + && isWithinHtmlMarkup(z, i-5) | |
| 573 | + && strncmp(g.zPath, "doc/",4)==0 | |
| 574 | + ){ | |
| 575 | + int j; | |
| 576 | + for(j=4; g.zPath[j] && g.zPath[j]!='/'; j++){} | |
| 577 | + blob_append(cgi_output_blob(), &z[base], i-base); | |
| 578 | + blob_appendf(cgi_output_blob(), "%.*s", j-4, g.zPath+4); | |
| 579 | + base = i+5; | |
| 538 | 580 | } |
| 539 | 581 | } |
| 540 | 582 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 541 | 583 | } |
| 542 | 584 | |
| 543 | 585 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -507,10 +507,39 @@ | |
| 507 | if( rid && content_get(rid, pContent)==0 ){ |
| 508 | rid = 0; |
| 509 | } |
| 510 | return rid; |
| 511 | } |
| 512 | |
| 513 | /* |
| 514 | ** Transfer content to the output. During the transfer, when text of |
| 515 | ** the following form is seen: |
| 516 | ** |
| @@ -529,14 +558,27 @@ | |
| 529 | && strncmp(&z[i],"$ROOT/", 6)==0 |
| 530 | && (z[i-1]=='\'' || z[i-1]=='"') |
| 531 | && i-base>=9 |
| 532 | && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) || |
| 533 | (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) ) |
| 534 | ){ |
| 535 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 536 | blob_appendf(cgi_output_blob(), "%R"); |
| 537 | base = i+5; |
| 538 | } |
| 539 | } |
| 540 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 541 | } |
| 542 | |
| 543 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -507,10 +507,39 @@ | |
| 507 | if( rid && content_get(rid, pContent)==0 ){ |
| 508 | rid = 0; |
| 509 | } |
| 510 | return rid; |
| 511 | } |
| 512 | |
| 513 | /* |
| 514 | ** Check to verify that z[i] is contained within HTML markup. |
| 515 | ** |
| 516 | ** This works by looking backwards in the string for the most recent |
| 517 | ** '<' or '>' character. If a '<' is found first, then we assume that |
| 518 | ** z[i] is within markup. If a '>' is seen or neither character is seen, |
| 519 | ** then z[i] is not within markup. |
| 520 | */ |
| 521 | static int isWithinHtmlMarkup(const char *z, int i){ |
| 522 | while( i>=0 && z[i]!='>' && z[i]!='<' ){ i--; } |
| 523 | return z[i]=='<'; |
| 524 | } |
| 525 | |
| 526 | /* |
| 527 | ** Check to see if z[i] is contained within an href='...' of markup. |
| 528 | */ |
| 529 | static int isWithinHref(const char *z, int i){ |
| 530 | while( i>5 |
| 531 | && !fossil_isspace(z[i]) |
| 532 | && z[i]!='\'' && z[i]!='"' |
| 533 | && z[i]!='>' |
| 534 | ){ i--; } |
| 535 | if( i<=6 ) return 0; |
| 536 | if( z[i]!='\'' && z[i]!='\"' ) return 0; |
| 537 | if( strncmp(&z[i-5],"href=",5)!=0 ) return 0; |
| 538 | if( !fossil_isspace(z[i-6]) ) return 0; |
| 539 | return 1; |
| 540 | } |
| 541 | |
| 542 | /* |
| 543 | ** Transfer content to the output. During the transfer, when text of |
| 544 | ** the following form is seen: |
| 545 | ** |
| @@ -529,14 +558,27 @@ | |
| 558 | && strncmp(&z[i],"$ROOT/", 6)==0 |
| 559 | && (z[i-1]=='\'' || z[i-1]=='"') |
| 560 | && i-base>=9 |
| 561 | && ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) || |
| 562 | (fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) ) |
| 563 | && isWithinHtmlMarkup(z, i-6) |
| 564 | ){ |
| 565 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 566 | blob_appendf(cgi_output_blob(), "%R"); |
| 567 | base = i+5; |
| 568 | }else |
| 569 | if( z[i]=='$' |
| 570 | && strncmp(&z[i-5],"/doc/$SELF/", 11)==0 |
| 571 | && isWithinHref(z,i-5) |
| 572 | && isWithinHtmlMarkup(z, i-5) |
| 573 | && strncmp(g.zPath, "doc/",4)==0 |
| 574 | ){ |
| 575 | int j; |
| 576 | for(j=4; g.zPath[j] && g.zPath[j]!='/'; j++){} |
| 577 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 578 | blob_appendf(cgi_output_blob(), "%.*s", j-4, g.zPath+4); |
| 579 | base = i+5; |
| 580 | } |
| 581 | } |
| 582 | blob_append(cgi_output_blob(), &z[base], i-base); |
| 583 | } |
| 584 | |
| 585 |
+49
-2
| --- www/mdtest/test1.md | ||
| +++ www/mdtest/test1.md | ||
| @@ -1,12 +1,59 @@ | ||
| 1 | 1 | # Markdown Link-test |
| 2 | 2 | |
| 3 | -This document exist solely to test relative-path linking capabilities | |
| 4 | -in markdown. | |
| 3 | +This document exist solely as a test for some of the hyperlinking | |
| 4 | +capabilities of Markdown as implemented by Fossil. | |
| 5 | + | |
| 6 | +## Relative-Path Links | |
| 5 | 7 | |
| 6 | 8 | * The index: [](../index.wiki) |
| 7 | 9 | |
| 8 | 10 | * Load management: [](../loadmgmt.md) |
| 9 | 11 | |
| 10 | 12 | * Site-map: [](../../../../sitemap) |
| 11 | 13 | |
| 12 | 14 | * Windows CGI: [](../server/windows/cgi.md) |
| 15 | + | |
| 16 | +## The Magic $ROOT Path Prefix | |
| 17 | + | |
| 18 | +In text of the form `href="$ROOT/..."` in the HTML that markdown | |
| 19 | +generates, the $ROOT is replaced by the complete URI for the root | |
| 20 | +of the document tree. | |
| 21 | +Note that the $ROOT translation only occurs within the `<a href="...">` | |
| 22 | +element, not within the text of the hyperlink. So you should see the | |
| 23 | +$ROOT text on this page, but if you mouse-over the hyperlink the $ROOT | |
| 24 | +value should have been expanded to the actual document root. | |
| 25 | + | |
| 26 | + * Timeline: []($ROOT/timeline) | |
| 27 | + | |
| 28 | + * Site-map: []($ROOT/sitemap) | |
| 29 | + | |
| 30 | +The $ROOT prefix on markdown links is superfluous. The same link | |
| 31 | +works without the $ROOT prefix. (Though: the $ROOT prefix is required | |
| 32 | +for HTML documents.) | |
| 33 | + | |
| 34 | + * Timeline: [](/timeline) | |
| 35 | + | |
| 36 | + * Help: [](/help?cmd=help) | |
| 37 | + | |
| 38 | + * Site-map: [](/sitemap) | |
| 39 | + | |
| 40 | +## The Magic $SELF Document Version Translation | |
| 41 | + | |
| 42 | +In URI text of the form `.../doc/$SELF/...` the | |
| 43 | +$SELF value is converted to the version number of the document | |
| 44 | +currently being displayed. This conversion happens after translation | |
| 45 | +into HTML and only occurs on href='...' attributes so it does not occur | |
| 46 | +for plain text. | |
| 47 | + | |
| 48 | + * Document index: [](/doc/$SELF/www/index.wiki) | |
| 49 | + | |
| 50 | +Both the $ROOT and the $SELF conversions can occur on the same link. | |
| 51 | + | |
| 52 | + * Document index: []($ROOT/doc/$SELF/www/index.wiki) | |
| 53 | + | |
| 54 | +The translations must be contained within HTML markup in order to work. | |
| 55 | +They do not work for ordinary text that appears to be an href= attribute. | |
| 56 | + | |
| 57 | + * `x href='$ROOT/timeline'` | |
| 58 | + * `x action="$ROOT/whatever"` | |
| 59 | + * `x href="https://some-other-site.com/doc/$SELF/tail"` | |
| 13 | 60 |
| --- www/mdtest/test1.md | |
| +++ www/mdtest/test1.md | |
| @@ -1,12 +1,59 @@ | |
| 1 | # Markdown Link-test |
| 2 | |
| 3 | This document exist solely to test relative-path linking capabilities |
| 4 | in markdown. |
| 5 | |
| 6 | * The index: [](../index.wiki) |
| 7 | |
| 8 | * Load management: [](../loadmgmt.md) |
| 9 | |
| 10 | * Site-map: [](../../../../sitemap) |
| 11 | |
| 12 | * Windows CGI: [](../server/windows/cgi.md) |
| 13 |
| --- www/mdtest/test1.md | |
| +++ www/mdtest/test1.md | |
| @@ -1,12 +1,59 @@ | |
| 1 | # Markdown Link-test |
| 2 | |
| 3 | This document exist solely as a test for some of the hyperlinking |
| 4 | capabilities of Markdown as implemented by Fossil. |
| 5 | |
| 6 | ## Relative-Path Links |
| 7 | |
| 8 | * The index: [](../index.wiki) |
| 9 | |
| 10 | * Load management: [](../loadmgmt.md) |
| 11 | |
| 12 | * Site-map: [](../../../../sitemap) |
| 13 | |
| 14 | * Windows CGI: [](../server/windows/cgi.md) |
| 15 | |
| 16 | ## The Magic $ROOT Path Prefix |
| 17 | |
| 18 | In text of the form `href="$ROOT/..."` in the HTML that markdown |
| 19 | generates, the $ROOT is replaced by the complete URI for the root |
| 20 | of the document tree. |
| 21 | Note that the $ROOT translation only occurs within the `<a href="...">` |
| 22 | element, not within the text of the hyperlink. So you should see the |
| 23 | $ROOT text on this page, but if you mouse-over the hyperlink the $ROOT |
| 24 | value should have been expanded to the actual document root. |
| 25 | |
| 26 | * Timeline: []($ROOT/timeline) |
| 27 | |
| 28 | * Site-map: []($ROOT/sitemap) |
| 29 | |
| 30 | The $ROOT prefix on markdown links is superfluous. The same link |
| 31 | works without the $ROOT prefix. (Though: the $ROOT prefix is required |
| 32 | for HTML documents.) |
| 33 | |
| 34 | * Timeline: [](/timeline) |
| 35 | |
| 36 | * Help: [](/help?cmd=help) |
| 37 | |
| 38 | * Site-map: [](/sitemap) |
| 39 | |
| 40 | ## The Magic $SELF Document Version Translation |
| 41 | |
| 42 | In URI text of the form `.../doc/$SELF/...` the |
| 43 | $SELF value is converted to the version number of the document |
| 44 | currently being displayed. This conversion happens after translation |
| 45 | into HTML and only occurs on href='...' attributes so it does not occur |
| 46 | for plain text. |
| 47 | |
| 48 | * Document index: [](/doc/$SELF/www/index.wiki) |
| 49 | |
| 50 | Both the $ROOT and the $SELF conversions can occur on the same link. |
| 51 | |
| 52 | * Document index: []($ROOT/doc/$SELF/www/index.wiki) |
| 53 | |
| 54 | The translations must be contained within HTML markup in order to work. |
| 55 | They do not work for ordinary text that appears to be an href= attribute. |
| 56 | |
| 57 | * `x href='$ROOT/timeline'` |
| 58 | * `x action="$ROOT/whatever"` |
| 59 | * `x href="https://some-other-site.com/doc/$SELF/tail"` |
| 60 |