Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merge tagview branch into mainline |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
8745d0d579e1b95e8fb766be7ef69eb7 |
| User & Date: | eric 2008-09-06 13:29:29.000 |
Context
|
2008-09-07
| ||
| 08:32 | Remove small glitch that prevent fossil to be built with BSD make. ... (check-in: f3fb059eb6 user: cle tags: trunk) | |
|
2008-09-06
| ||
| 13:29 | Merge tagview branch into mainline ... (check-in: 8745d0d579 user: eric tags: trunk) | |
| 13:16 | Merge mainline into tagview branch ... (check-in: a55a0a49a3 user: eric tags: eric-tagview-rework, trunk) | |
|
2008-08-30
| ||
| 13:20 | Add a much larger and more complete file-suffix to mimetype translation table to the "doc" method. ... (check-in: 8e66784522 user: drh tags: trunk) | |
Changes
Changes to src/cgi.c.
| ︙ | ︙ | |||
198 199 200 201 202 203 204 205 |
const char *zValue, /* Value of the cookie. Automatically escaped */
const char *zPath, /* Path cookie applies to. NULL means "/" */
int lifetime /* Expiration of the cookie in seconds from now */
){
if( zPath==0 ) zPath = g.zTop;
if( lifetime>0 ){
lifetime += (int)time(0);
blob_appendf(&extraHeader,
| > | | > | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
const char *zValue, /* Value of the cookie. Automatically escaped */
const char *zPath, /* Path cookie applies to. NULL means "/" */
int lifetime /* Expiration of the cookie in seconds from now */
){
if( zPath==0 ) zPath = g.zTop;
if( lifetime>0 ){
lifetime += (int)time(0);
char * zDate = cgi_rfc822_datestamp(lifetime);
blob_appendf(&extraHeader,
"Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n",
zName, zValue, zPath, zDate);
if( zDate[0] ) free( zDate );
}else{
blob_appendf(&extraHeader,
"Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
zName, zValue, zPath);
}
}
|
| ︙ | ︙ | |||
284 285 286 287 288 289 290 |
iReplyStatus = 304;
zReplyStatus = "Not Modified";
}
#endif
if( g.fullHttpReply ){
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
| > | > > | > | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
iReplyStatus = 304;
zReplyStatus = "Not Modified";
}
#endif
if( g.fullHttpReply ){
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
char * zDate = cgi_rfc822_datestamp(time(0));
fprintf(g.httpOut, "Date: %s\r\n", zDate );
if( zDate[0] ) free( zDate );
fprintf(g.httpOut, "Connection: close\r\n");
}else{
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
}
if( blob_size(&extraHeader)>0 ){
fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
}
if( g.isConst ){
/* constant means that the input URL will _never_ generate anything
** else. In the case of attachments, the contents won't change because
** an attempt to change them generates a new attachment number. In the
** case of most /getfile calls for specific versions, the only way the
** content changes is if someone breaks the SCM. And if that happens, a
** stale cache is the least of the problem. So we provide an Expires
** header set to a reasonable period (default: one week).
*/
/*time_t expires = time(0) + atoi(db_config("constant_expires","604800"));*/
time_t expires = time(0) + 604800;
char * zDate = cgi_rfc822_datestamp(expires);
fprintf(g.httpOut, "Expires: %s\r\n", zDate );
if( zDate[0] ) free( zDate );
}
/* Content intended for logged in users should only be cached in
** the browser, not some shared location.
*/
fprintf(g.httpOut, "Cache-control: private\r\n");
|
| ︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0};
/*
** Returns an RFC822-formatted time string suitable for HTTP headers, among
** other things.
** Returned timezone is always GMT as required by HTTP/1.1 specification.
**
** See http://www.faqs.org/rfcs/rfc822.html, section 5
** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3.
*/
char *cgi_rfc822_datestamp(time_t now){
struct tm *pTm;
pTm = gmtime(&now);
| > > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0};
/*
** Returns an RFC822-formatted time string suitable for HTTP headers, among
** other things.
** Returned timezone is always GMT as required by HTTP/1.1 specification.
** The returned string is allocated with malloc() and must be freed
** with free().
**
** See http://www.faqs.org/rfcs/rfc822.html, section 5
** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3.
*/
char *cgi_rfc822_datestamp(time_t now){
struct tm *pTm;
pTm = gmtime(&now);
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
913 914 915 916 917 918 919 920 921 922 923 924 925 |
** The argument is a UUID which might be a baseline or a file or
** a ticket changes or a wiki editor or something else.
**
** Figure out what the UUID is and jump to it.
*/
void info_page(void){
const char *zName;
int rid, nName;
zName = P("name");
if( zName==0 ) fossil_redirect_home();
nName = strlen(zName);
if( nName<4 || nName>UUID_SIZE || !validate16(zName, nName) ){
| > > > > > > > > > > > > > > | > > > | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
** The argument is a UUID which might be a baseline or a file or
** a ticket changes or a wiki editor or something else.
**
** Figure out what the UUID is and jump to it.
*/
void info_page(void){
const char *zName;
Blob uuid;
int rid, nName;
zName = P("name");
if( zName==0 ) fossil_redirect_home();
nName = strlen(zName);
if( nName<4 || nName>UUID_SIZE || !validate16(zName, nName) ){
switch( sym_tag_to_uuid(zName, &uuid) ){
case 1: {
/* got one UUID, use it */
zName = blob_str(&uuid);
break;
}
case 2: {
/* go somewhere to show the multiple UUIDs */
tagview_page();
return;
break;
}
default: {
fossil_redirect_home();
break;
}
}
}
if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%s*'", zName) ){
tktview_page();
return;
}
rid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%s*'", zName);
if( rid==0 ){
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
** Return the number of errors.
*/
int name_to_uuid(Blob *pName, int iErrPriority){
int rc;
int sz;
sz = blob_size(pName);
if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
| < < < < < < < < < < < < | < < | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
** Return the number of errors.
*/
int name_to_uuid(Blob *pName, int iErrPriority){
int rc;
int sz;
sz = blob_size(pName);
if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
Blob uuid;
static const char prefix[] = "tag:";
static const int preflen = sizeof(prefix)-1;
const char *zName = blob_str(pName);
if( strncmp(zName, prefix, preflen)==0 ){
zName += preflen;
}
sym_tag_to_uuid(zName, &uuid);
if( blob_size(&uuid)==0 ){
fossil_error(iErrPriority, "not a valid object name: %s", zName);
blob_reset(&uuid);
return 1;
}else{
blob_reset(pName);
*pName = uuid;
|
| ︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
}
}
}else{
rc = 0;
}
return rc;
}
/*
** COMMAND: test-name-to-uuid
**
** Convert a name to a full UUID.
*/
void test_name_to_uuid(void){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
}
}
}else{
rc = 0;
}
return rc;
}
/*
** This routine takes a name which might be a tag and attempts to
** produce a UUID. The UUID (if any) is returned in the blob pointed
** to by the second argument.
**
** Return as follows:
** 0 Name is not a tag
** 1 A single UUID was found
** 2 More than one UUID was found, so this is presumably a
** propagating tag. The return UUID is the most recent,
** which is most likely to be the one wanted.
*/
int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
Stmt q;
int count = 0;
db_prepare(&q,
"SELECT (SELECT uuid FROM blob WHERE rid=objid)"
" FROM tagxref JOIN event ON rid=objid"
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
" AND tagtype>0"
" AND value IS NULL"
" ORDER BY event.mtime DESC",
pPrefix,
pName
);
blob_zero(pUuid);
while( db_step(&q)==SQLITE_ROW ){
count++;
if(count>1){
break;
}
db_column_blob(&q, 0, pUuid);
}
db_finalize(&q);
return count;
}
/*
** This routine takes a name which might be a symbolic tag and
** attempts to produce a UUID. See tag_to_uuid.
*/
int sym_tag_to_uuid(const char *pName, Blob *pUuid){
return tag_to_uuid(pName,pUuid,"sym-");
}
/*
** COMMAND: test-name-to-uuid
**
** Convert a name to a full UUID.
*/
void test_name_to_uuid(void){
|
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
295 296 297 298 299 300 301 302 303 304 305 306 307 308 | # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a checking */ # define TAG_HIDDEN 4 /* Do not display or sync */ # define TAG_PRIVATE 5 /* Display but do not sync */ # define TAG_CLUSTER 6 /* A cluster */ #endif /* ** The schema for the locate FOSSIL database file found at the root ** of very check-out. This database contains the complete state of ** the checkout. */ const char zLocalSchema[] = | > > > | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a checking */ # define TAG_HIDDEN 4 /* Do not display or sync */ # define TAG_PRIVATE 5 /* Display but do not sync */ # define TAG_CLUSTER 6 /* A cluster */ #endif #if EXPORT_INTERFACE # define MAX_INT_TAG 6 /* The largest pre-assigned tag id */ #endif /* ** The schema for the locate FOSSIL database file found at the root ** of very check-out. This database contains the complete state of ** the checkout. */ const char zLocalSchema[] = |
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
@ font-size: 0.8em;
@ margin-top: 12px;
@ padding: 5px 10px 5px 10px;
@ text-align: right;
@ background-color: #558195;
@ color: white;
@ }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@ background-color: #f5f5f5;
@ padding: 0.5em;
@}
@
| > > > > > > | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
@ font-size: 0.8em;
@ margin-top: 12px;
@ padding: 5px 10px 5px 10px;
@ text-align: right;
@ background-color: #558195;
@ color: white;
@ }
@
@ /* Make the links in the footer less ugly... */
@ div.footer a { color: white; }
@ div.footer a:link { color: white; }
@ div.footer a:visited { color: white; }
@ div.footer a:hover { background-color: white; color: #558195; }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@ background-color: #f5f5f5;
@ padding: 0.5em;
@}
@
|
| ︙ | ︙ |
Changes to src/tagview.c.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
zSql = mprintf(
"SELECT "
" linktagid(t.tagid) AS 'Tag ID',"
" linktagname(t.tagname) AS 'Name',"
" DATETIME(tx.mtime) AS 'Timestamp',"
" linkuuid(b.uuid) AS 'Version'"
" FROM tag t, tagxref tx, blob b "
| | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
zSql = mprintf(
"SELECT "
" linktagid(t.tagid) AS 'Tag ID',"
" linktagname(t.tagname) AS 'Name',"
" DATETIME(tx.mtime) AS 'Timestamp',"
" linkuuid(b.uuid) AS 'Version'"
" FROM tag t, tagxref tx, blob b "
" WHERE t.tagid=tx.tagid AND tx.rid=b.rid"
" AND tx.tagtype!=0 %s "
TAGVIEW_DEFAULT_FILTER
" ORDER BY tx.mtime DESC %s",
zLikeClause, zLimit
);
db_generic_query_view(zSql, 1);
free(zSql);
if( zLikeClause[0] ) free(zLikeClause);
if( zLimit[0] ) free(zLimit);
}
/*
** A small search form which forwards to ?like=SEARCH_STRING
*/
static void tagview_page_search_miniform(void){
char const * like = P("like");
@ <div style='font-size:smaller'>
@ <form action='tagview' method='post'>
@ Search for tags:
@ <input type='text' name='like' value='%h((like?like:""))' size='10'/>
@ <input type='submit'/>
@ </form>
@ </div>
}
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
@ <h2>Tag #%d(tagid):</h2>
zSql = mprintf(
"SELECT DISTINCT"
" linktagname(t.tagname) AS 'Tag Name',"
" DATETIME(tx.mtime) AS 'Timestamp',"
" linkuuid(b.uuid) AS 'Version'"
" FROM tag t, tagxref tx, blob b"
| | | < | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
@ <h2>Tag #%d(tagid):</h2>
zSql = mprintf(
"SELECT DISTINCT"
" linktagname(t.tagname) AS 'Tag Name',"
" DATETIME(tx.mtime) AS 'Timestamp',"
" linkuuid(b.uuid) AS 'Version'"
" FROM tag t, tagxref tx, blob b"
" WHERE t.tagid=%d AND t.tagid=tx.tagid AND tx.rid=b.rid "
TAGVIEW_DEFAULT_FILTER
" ORDER BY tx.mtime DESC",
tagid
);
db_generic_query_view(zSql, 1);
free(zSql);
}
/*
** Lists all tags matching the given tag name.
*/
static void tagview_page_tag_by_name( char const * tagname ){
char *zSql;
@ <h2>Tag '%s(tagname)':</h2>
zSql = mprintf(
"SELECT DISTINCT"
" linktagid(t.tagid) AS 'Tag ID',"
" DATETIME(tx.mtime) AS 'Timestamp',"
" linkuuid(b.uuid) AS 'Version'"
" FROM tag t, tagxref tx, blob b "
" WHERE t.tagname='%q' AND t.tagid=tx.tagid AND tx.rid=b.rid "
TAGVIEW_DEFAULT_FILTER
" ORDER BY tx.mtime DESC",
tagname);
db_generic_query_view(zSql, 1);
free(zSql);
}
/*
** WEBP AGE: /tagview
*/
void old_tagview_page(void){
char const * check = 0;
login_check_credentials();
if( !g.okRdWiki ){
login_needed();
}
style_header("Tags");
login_anonymous_available();
|
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
}else{
tagview_page_default();
}
style_footer();
}
#undef TAGVIEW_DEFAULT_FILTER
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
}else{
tagview_page_default();
}
style_footer();
}
#undef TAGVIEW_DEFAULT_FILTER
/*
** Generate a timeline for the chosen tag
*/
void tagview_print_timeline(char const *pName, char const *pPrefix){
char *zSql;
Stmt q;
zSql = mprintf("%s AND EXISTS (SELECT 1"
" FROM tagxref"
" WHERE tagxref.rid = event.objid"
" AND tagxref.tagid = (SELECT tagid FROM tag"
" WHERE tagname = %Q||%Q))"
" ORDER BY 3 desc",
timeline_query_for_www(), pPrefix, pName);
db_prepare(&q, zSql);
free(zSql);
www_print_timeline(&q);
db_finalize(&q);
}
/*
** WEBPAGE: /tagview
*/
void tagview_page(void){
char const *zName = 0;
int zTcount = 0;
login_check_credentials();
if( !g.okRead ){
login_needed();
}
login_anonymous_available();
if( 0 != (zName = P("name")) ){
Blob uuid;
style_header("Tagged Baselines");
@ <h2>%s(zName):</h2>
if( sym_tag_to_uuid(zName, &uuid) > 0){
tagview_print_timeline(zName, "sym-");
}else if( tag_to_uuid(zName, &uuid, "") > 0){
tagview_print_timeline(zName, "");
}else{
@ There is no artifact with this tag.
}
}else{
Stmt q;
const char *prefix = "sym-";
int preflen = strlen(prefix);
style_header("Tags");
db_prepare(&q,
"SELECT tagname"
" FROM tag"
" WHERE EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=tag.tagid"
" AND tagtype>0)"
" AND tagid > %d"
" AND tagname NOT GLOB 'wiki-*'"
" AND tagname NOT GLOB 'tkt-*'"
" ORDER BY tagname",
MAX_INT_TAG
);
@ <ul>
while( db_step(&q)==SQLITE_ROW ){
zTcount++;
const char *name = db_column_text(&q, 0);
if( g.okHistory ){
if( strncmp(name, prefix, preflen)==0 ){
@ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
@ %s(name+preflen)</a>
}else{
@ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
@ %s(name)</a>
}
}else{
if( strncmp(name, prefix, preflen)==0 ){
@ <li><strong>%s(name+preflen)</strong>
}else{
@ <li><strong>%s(name)</strong>
}
}
if( strncmp(name, prefix, preflen)==0 ){
@ (symbolic label)
}
@ </li>
}
@ </ul>
if( zTcount == 0) {
@ There are no relevant tags.
}
db_finalize(&q);
}
/*
* Put in dummy functions since www_print_timeline has generated calls to
* them. Some browsers don't seem to care, but better to be safe.
* Actually, it would be nice to use the functions on this page, but at
* the moment it looks to be too difficult.
*/
@ <script>
@ function xin(id){
@ }
@ function xout(id){
@ }
@ </script>
style_footer();
}
|