| | @@ -868,18 +868,16 @@ |
| 868 | 868 | return 1; |
| 869 | 869 | } |
| 870 | 870 | |
| 871 | 871 | /* |
| 872 | 872 | ** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket. |
| 873 | | -** If it is, fill zDisplay[0..nDisplay-1] with the title of the ticket |
| 874 | | -** (or a prefix if the title is too long) and return true. If zTarget |
| 873 | +** If it is, store in *pClosed a true or false depending on whether or not |
| 874 | +** the ticket is closed and return true. If zTarget |
| 875 | 875 | ** is not the UUID of a ticket, return false. |
| 876 | 876 | */ |
| 877 | 877 | static int is_ticket( |
| 878 | 878 | const char *zTarget, /* Ticket UUID */ |
| 879 | | - char *zDisplay, /* Space in which to write ticket title */ |
| 880 | | - int nDisplay, /* Bytes available in zDisplay[] */ |
| 881 | 879 | int *pClosed /* True if the ticket is closed */ |
| 882 | 880 | ){ |
| 883 | 881 | static Stmt q; |
| 884 | 882 | static int once = 1; |
| 885 | 883 | int n; |
| | @@ -890,107 +888,97 @@ |
| 890 | 888 | memcpy(zLower, zTarget, n+1); |
| 891 | 889 | canonical16(zLower, n+1); |
| 892 | 890 | memcpy(zUpper, zLower, n+1); |
| 893 | 891 | zUpper[n-1]++; |
| 894 | 892 | if( once ){ |
| 895 | | - const char *zTitleExpr = db_get("ticket-title-expr", "title"); |
| 896 | 893 | const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); |
| 897 | 894 | db_static_prepare(&q, |
| 898 | | - "SELECT %s, %s FROM ticket " |
| 895 | + "SELECT %s FROM ticket " |
| 899 | 896 | " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", |
| 900 | | - zTitleExpr, zClosedExpr |
| 897 | + zClosedExpr |
| 901 | 898 | ); |
| 899 | + once = 0; |
| 902 | 900 | } |
| 903 | 901 | db_bind_text(&q, ":lwr", zLower); |
| 904 | 902 | db_bind_text(&q, ":upr", zUpper); |
| 905 | 903 | if( db_step(&q)==SQLITE_ROW ){ |
| 906 | | - n = db_column_bytes(&q,0); |
| 907 | | - if( n>nDisplay-1 ) n = nDisplay - 1; |
| 908 | | - memcpy(zDisplay, db_column_text(&q, 0), n); |
| 909 | | - zDisplay[n] = 0; |
| 910 | 904 | rc = 1; |
| 911 | | - *pClosed = db_column_int(&q, 1); |
| 905 | + *pClosed = db_column_int(&q, 0); |
| 912 | 906 | }else{ |
| 913 | 907 | rc = 0; |
| 914 | 908 | } |
| 915 | 909 | db_reset(&q); |
| 916 | 910 | return rc; |
| 917 | 911 | } |
| 918 | 912 | |
| 919 | 913 | /* |
| 920 | 914 | ** Resolve a hyperlink. The zTarget argument is the content of the [...] |
| 921 | | -** in the wiki. Append an <a> markup to the output of the Renderer. |
| 915 | +** in the wiki. Append to the output string whatever text is approprate |
| 916 | +** for opening the hyperlink. Write into zClose[0...nClose-1] text that will |
| 917 | +** close the markup. |
| 922 | 918 | ** |
| 923 | 919 | ** Actually, this routine might or might not append the hyperlink, depending |
| 924 | 920 | ** on current rendering rules: specifically does the current user have |
| 925 | | -** "History" permission. If this routine does append the <a> and thus needs |
| 926 | | -** a </a> to follow, it returns true. If the <a> is suppressed, then return |
| 927 | | -** false. |
| 928 | | -** |
| 929 | | -** If nDisplay>0 then optionally write up to nDisplay bytes of |
| 930 | | -** alternative display text into zDisplay. The text must be zero |
| 931 | | -** terminated. The final zero is included in the nDisplay byte count |
| 932 | | -** limit. |
| 921 | +** "History" permission. |
| 933 | 922 | */ |
| 934 | | -static int resolveHyperlink( |
| 923 | +static void openHyperlink( |
| 935 | 924 | Renderer *p, /* Rendering context */ |
| 936 | 925 | const char *zTarget, /* Hyperlink traget; text within [...] */ |
| 937 | | - char *zDisplay, /* Space in which to write alternative display */ |
| 938 | | - int nDisplay /* Bytes available in zDisplay[] */ |
| 926 | + char *zClose, /* Write hyperlink closing text here */ |
| 927 | + int nClose /* Bytes available in zClose[] */ |
| 939 | 928 | ){ |
| 940 | | - int rc = 0; |
| 929 | + const char *zTerm = "</a>"; |
| 930 | + assert( nClose>10 ); |
| 931 | + |
| 941 | 932 | if( strncmp(zTarget, "http:", 5)==0 |
| 942 | 933 | || strncmp(zTarget, "https:", 6)==0 |
| 943 | 934 | || strncmp(zTarget, "ftp:", 4)==0 |
| 944 | 935 | || strncmp(zTarget, "mailto:", 7)==0 |
| 945 | 936 | ){ |
| 946 | 937 | blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); |
| 947 | | - rc = 1; |
| 948 | | - }else if( zTarget[0]=='/' ){ |
| 949 | | - if( g.okHistory ){ |
| 950 | | - blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget); |
| 951 | | - rc = 1; |
| 952 | | - } |
| 953 | | - }else if( is_valid_uuid(zTarget) ){ |
| 954 | | - int isClosed; |
| 955 | | - if( nDisplay && is_ticket(zTarget, zDisplay, nDisplay, &isClosed) ){ |
| 956 | | - /* Special display processing for tickets. Display the hyperlink |
| 957 | | - ** as crossed out if the ticket is closed. Add the title after the |
| 958 | | - ** hyperlink. |
| 959 | | - */ |
| 960 | | - if( isClosed ){ |
| 961 | | - if( g.okHistory ){ |
| 962 | | - blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[<s>%s</s>]</a>: %s", |
| 963 | | - g.zBaseURL, zTarget, zTarget, zDisplay |
| 964 | | - ); |
| 965 | | - }else{ |
| 966 | | - blob_appendf(p->pOut,"[<s>%s</s>]: %s", zTarget, zDisplay); |
| 967 | | - } |
| 968 | | - }else{ |
| 969 | | - if( g.okHistory ){ |
| 970 | | - blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[%s]</a>: %s", |
| 971 | | - g.zBaseURL, zTarget, zTarget, zDisplay |
| 972 | | - ); |
| 973 | | - }else{ |
| 974 | | - blob_appendf(p->pOut,"[%s]: %s", zTarget, zDisplay); |
| 975 | | - } |
| 976 | | - } |
| 977 | | - zDisplay[0] = ' '; |
| 978 | | - zDisplay[1] = 0; |
| 979 | | - rc = 0; |
| 980 | | - }else if( g.okHistory ){ |
| 981 | | - blob_appendf(p->pOut, "<a href=\"%s/info/%s\">", g.zBaseURL, zTarget); |
| 982 | | - rc = 1; |
| 983 | | - } |
| 984 | | - }else if( wiki_name_is_wellformed(zTarget) ){ |
| 985 | | - blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zBaseURL, zTarget); |
| 986 | | - rc = 1; |
| 987 | | - }else{ |
| 988 | | - blob_appendf(p->pOut, "[bad-link: %h]", zTarget); |
| 989 | | - rc = 0; |
| 990 | | - } |
| 991 | | - return rc; |
| 938 | + }else if( zTarget[0]=='/' ){ |
| 939 | + if( g.okHistory ){ |
| 940 | + blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget); |
| 941 | + }else{ |
| 942 | + zTerm = ""; |
| 943 | + } |
| 944 | + }else if( is_valid_uuid(zTarget) ){ |
| 945 | + int isClosed; |
| 946 | + if( is_ticket(zTarget, &isClosed) ){ |
| 947 | + /* Special display processing for tickets. Display the hyperlink |
| 948 | + ** as crossed out if the ticket is closed. |
| 949 | + */ |
| 950 | + if( isClosed ){ |
| 951 | + if( g.okHistory ){ |
| 952 | + blob_appendf(p->pOut,"<a href=\"%s/info/%s\"><s>", |
| 953 | + g.zBaseURL, zTarget |
| 954 | + ); |
| 955 | + zTerm = "</s></a>"; |
| 956 | + }else{ |
| 957 | + blob_appendf(p->pOut,"<s>"); |
| 958 | + zTerm = "</s>"; |
| 959 | + } |
| 960 | + }else{ |
| 961 | + if( g.okHistory ){ |
| 962 | + blob_appendf(p->pOut,"<a href=\"%s/info/%s\">", |
| 963 | + g.zBaseURL, zTarget |
| 964 | + ); |
| 965 | + }else{ |
| 966 | + zTerm = ""; |
| 967 | + } |
| 968 | + } |
| 969 | + }else if( g.okHistory ){ |
| 970 | + blob_appendf(p->pOut, "<a href=\"%s/info/%s\">", g.zBaseURL, zTarget); |
| 971 | + } |
| 972 | + }else if( wiki_name_is_wellformed(zTarget) ){ |
| 973 | + blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zBaseURL, zTarget); |
| 974 | + }else{ |
| 975 | + blob_appendf(p->pOut, "[bad-link: %h]", zTarget); |
| 976 | + zTerm = ""; |
| 977 | + } |
| 978 | + assert( strlen(zTerm)<nClose ); |
| 979 | + strcpy(zClose, zTerm); |
| 992 | 980 | } |
| 993 | 981 | |
| 994 | 982 | /* |
| 995 | 983 | ** Check to see if the given parsed markup is the correct |
| 996 | 984 | ** </verbatim> tag. |
| | @@ -1111,13 +1099,11 @@ |
| 1111 | 1099 | case TOKEN_LINK: { |
| 1112 | 1100 | char *zTarget; |
| 1113 | 1101 | char *zDisplay = 0; |
| 1114 | 1102 | int i, j; |
| 1115 | 1103 | int savedState; |
| 1116 | | - int needCloseA; |
| 1117 | | - int altSize; |
| 1118 | | - char zAltDisplay[100]; |
| 1104 | + char zClose[20]; |
| 1119 | 1105 | |
| 1120 | 1106 | startAutoParagraph(p); |
| 1121 | 1107 | zTarget = &z[1]; |
| 1122 | 1108 | for(i=1; z[i] && z[i]!=']'; i++){ |
| 1123 | 1109 | if( z[i]=='|' && zDisplay==0 ){ |
| | @@ -1127,27 +1113,20 @@ |
| 1127 | 1113 | } |
| 1128 | 1114 | } |
| 1129 | 1115 | z[i] = 0; |
| 1130 | 1116 | if( zDisplay==0 ){ |
| 1131 | 1117 | zDisplay = zTarget; |
| 1132 | | - altSize = sizeof(zAltDisplay); |
| 1133 | 1118 | }else{ |
| 1134 | 1119 | while( isspace(*zDisplay) ) zDisplay++; |
| 1135 | | - altSize = 0; |
| 1136 | 1120 | } |
| 1137 | | - zAltDisplay[0] = 0; |
| 1138 | | - needCloseA = resolveHyperlink(p, zTarget, zAltDisplay, altSize); |
| 1121 | + openHyperlink(p, zTarget, zClose, sizeof(zClose)); |
| 1139 | 1122 | savedState = p->state; |
| 1140 | 1123 | p->state &= ~ALLOW_WIKI; |
| 1141 | 1124 | p->state |= FONT_MARKUP_ONLY; |
| 1142 | | - if( zAltDisplay[0] ){ |
| 1143 | | - wiki_render(p, zAltDisplay); |
| 1144 | | - }else{ |
| 1145 | | - wiki_render(p, zDisplay); |
| 1146 | | - } |
| 1125 | + wiki_render(p, zDisplay); |
| 1147 | 1126 | p->state = savedState; |
| 1148 | | - if( needCloseA ) blob_append(p->pOut, "</a>", 4); |
| 1127 | + blob_append(p->pOut, zClose, -1); |
| 1149 | 1128 | break; |
| 1150 | 1129 | } |
| 1151 | 1130 | case TOKEN_TEXT: { |
| 1152 | 1131 | startAutoParagraph(p); |
| 1153 | 1132 | blob_append(p->pOut, z, n); |
| 1154 | 1133 | |