Fossil SCM

Merge tagview branch into mainline

eric 2008-09-06 13:29 trunk merge
Commit 8745d0d579e1b95e8fb766be7ef69eb7ed361744
+12 -4
--- src/cgi.c
+++ src/cgi.c
@@ -200,13 +200,15 @@
200200
int lifetime /* Expiration of the cookie in seconds from now */
201201
){
202202
if( zPath==0 ) zPath = g.zTop;
203203
if( lifetime>0 ){
204204
lifetime += (int)time(0);
205
+ char * zDate = cgi_rfc822_datestamp(lifetime);
205206
blob_appendf(&extraHeader,
206
- "Set-Cookie: %s=%t; Path=%s; expires=%s; Version=1\r\n",
207
- zName, zValue, zPath, cgi_rfc822_datestamp(lifetime));
207
+ "Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n",
208
+ zName, zValue, zPath, zDate);
209
+ if( zDate[0] ) free( zDate );
208210
}else{
209211
blob_appendf(&extraHeader,
210212
"Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
211213
zName, zValue, zPath);
212214
}
@@ -286,11 +288,13 @@
286288
}
287289
#endif
288290
289291
if( g.fullHttpReply ){
290292
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
291
- fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
293
+ char * zDate = cgi_rfc822_datestamp(time(0));
294
+ fprintf(g.httpOut, "Date: %s\r\n", zDate );
295
+ if( zDate[0] ) free( zDate );
292296
fprintf(g.httpOut, "Connection: close\r\n");
293297
}else{
294298
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
295299
}
296300
@@ -307,11 +311,13 @@
307311
** stale cache is the least of the problem. So we provide an Expires
308312
** header set to a reasonable period (default: one week).
309313
*/
310314
/*time_t expires = time(0) + atoi(db_config("constant_expires","604800"));*/
311315
time_t expires = time(0) + 604800;
312
- fprintf(g.httpOut, "Expires: %s\r\n", cgi_rfc822_datestamp(expires));
316
+ char * zDate = cgi_rfc822_datestamp(expires);
317
+ fprintf(g.httpOut, "Expires: %s\r\n", zDate );
318
+ if( zDate[0] ) free( zDate );
313319
}
314320
315321
/* Content intended for logged in users should only be cached in
316322
** the browser, not some shared location.
317323
*/
@@ -1267,10 +1273,12 @@
12671273
12681274
/*
12691275
** Returns an RFC822-formatted time string suitable for HTTP headers, among
12701276
** other things.
12711277
** Returned timezone is always GMT as required by HTTP/1.1 specification.
1278
+** The returned string is allocated with malloc() and must be freed
1279
+** with free().
12721280
**
12731281
** See http://www.faqs.org/rfcs/rfc822.html, section 5
12741282
** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3.
12751283
*/
12761284
char *cgi_rfc822_datestamp(time_t now){
12771285
--- src/cgi.c
+++ src/cgi.c
@@ -200,13 +200,15 @@
200 int lifetime /* Expiration of the cookie in seconds from now */
201 ){
202 if( zPath==0 ) zPath = g.zTop;
203 if( lifetime>0 ){
204 lifetime += (int)time(0);
 
205 blob_appendf(&extraHeader,
206 "Set-Cookie: %s=%t; Path=%s; expires=%s; Version=1\r\n",
207 zName, zValue, zPath, cgi_rfc822_datestamp(lifetime));
 
208 }else{
209 blob_appendf(&extraHeader,
210 "Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
211 zName, zValue, zPath);
212 }
@@ -286,11 +288,13 @@
286 }
287 #endif
288
289 if( g.fullHttpReply ){
290 fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
291 fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
 
 
292 fprintf(g.httpOut, "Connection: close\r\n");
293 }else{
294 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
295 }
296
@@ -307,11 +311,13 @@
307 ** stale cache is the least of the problem. So we provide an Expires
308 ** header set to a reasonable period (default: one week).
309 */
310 /*time_t expires = time(0) + atoi(db_config("constant_expires","604800"));*/
311 time_t expires = time(0) + 604800;
312 fprintf(g.httpOut, "Expires: %s\r\n", cgi_rfc822_datestamp(expires));
 
 
313 }
314
315 /* Content intended for logged in users should only be cached in
316 ** the browser, not some shared location.
317 */
@@ -1267,10 +1273,12 @@
1267
1268 /*
1269 ** Returns an RFC822-formatted time string suitable for HTTP headers, among
1270 ** other things.
1271 ** Returned timezone is always GMT as required by HTTP/1.1 specification.
 
 
1272 **
1273 ** See http://www.faqs.org/rfcs/rfc822.html, section 5
1274 ** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3.
1275 */
1276 char *cgi_rfc822_datestamp(time_t now){
1277
--- src/cgi.c
+++ src/cgi.c
@@ -200,13 +200,15 @@
200 int lifetime /* Expiration of the cookie in seconds from now */
201 ){
202 if( zPath==0 ) zPath = g.zTop;
203 if( lifetime>0 ){
204 lifetime += (int)time(0);
205 char * zDate = cgi_rfc822_datestamp(lifetime);
206 blob_appendf(&extraHeader,
207 "Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n",
208 zName, zValue, zPath, zDate);
209 if( zDate[0] ) free( zDate );
210 }else{
211 blob_appendf(&extraHeader,
212 "Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
213 zName, zValue, zPath);
214 }
@@ -286,11 +288,13 @@
288 }
289 #endif
290
291 if( g.fullHttpReply ){
292 fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
293 char * zDate = cgi_rfc822_datestamp(time(0));
294 fprintf(g.httpOut, "Date: %s\r\n", zDate );
295 if( zDate[0] ) free( zDate );
296 fprintf(g.httpOut, "Connection: close\r\n");
297 }else{
298 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
299 }
300
@@ -307,11 +311,13 @@
311 ** stale cache is the least of the problem. So we provide an Expires
312 ** header set to a reasonable period (default: one week).
313 */
314 /*time_t expires = time(0) + atoi(db_config("constant_expires","604800"));*/
315 time_t expires = time(0) + 604800;
316 char * zDate = cgi_rfc822_datestamp(expires);
317 fprintf(g.httpOut, "Expires: %s\r\n", zDate );
318 if( zDate[0] ) free( zDate );
319 }
320
321 /* Content intended for logged in users should only be cached in
322 ** the browser, not some shared location.
323 */
@@ -1267,10 +1273,12 @@
1273
1274 /*
1275 ** Returns an RFC822-formatted time string suitable for HTTP headers, among
1276 ** other things.
1277 ** Returned timezone is always GMT as required by HTTP/1.1 specification.
1278 ** The returned string is allocated with malloc() and must be freed
1279 ** with free().
1280 **
1281 ** See http://www.faqs.org/rfcs/rfc822.html, section 5
1282 ** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3.
1283 */
1284 char *cgi_rfc822_datestamp(time_t now){
1285
+18 -1
--- src/info.c
+++ src/info.c
@@ -915,17 +915,34 @@
915915
**
916916
** Figure out what the UUID is and jump to it.
917917
*/
918918
void info_page(void){
919919
const char *zName;
920
+ Blob uuid;
920921
int rid, nName;
921922
922923
zName = P("name");
923924
if( zName==0 ) fossil_redirect_home();
924925
nName = strlen(zName);
925926
if( nName<4 || nName>UUID_SIZE || !validate16(zName, nName) ){
926
- fossil_redirect_home();
927
+ switch( sym_tag_to_uuid(zName, &uuid) ){
928
+ case 1: {
929
+ /* got one UUID, use it */
930
+ zName = blob_str(&uuid);
931
+ break;
932
+ }
933
+ case 2: {
934
+ /* go somewhere to show the multiple UUIDs */
935
+ tagview_page();
936
+ return;
937
+ break;
938
+ }
939
+ default: {
940
+ fossil_redirect_home();
941
+ break;
942
+ }
943
+ }
927944
}
928945
if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%s*'", zName) ){
929946
tktview_page();
930947
return;
931948
}
932949
--- src/info.c
+++ src/info.c
@@ -915,17 +915,34 @@
915 **
916 ** Figure out what the UUID is and jump to it.
917 */
918 void info_page(void){
919 const char *zName;
 
920 int rid, nName;
921
922 zName = P("name");
923 if( zName==0 ) fossil_redirect_home();
924 nName = strlen(zName);
925 if( nName<4 || nName>UUID_SIZE || !validate16(zName, nName) ){
926 fossil_redirect_home();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927 }
928 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%s*'", zName) ){
929 tktview_page();
930 return;
931 }
932
--- src/info.c
+++ src/info.c
@@ -915,17 +915,34 @@
915 **
916 ** Figure out what the UUID is and jump to it.
917 */
918 void info_page(void){
919 const char *zName;
920 Blob uuid;
921 int rid, nName;
922
923 zName = P("name");
924 if( zName==0 ) fossil_redirect_home();
925 nName = strlen(zName);
926 if( nName<4 || nName>UUID_SIZE || !validate16(zName, nName) ){
927 switch( sym_tag_to_uuid(zName, &uuid) ){
928 case 1: {
929 /* got one UUID, use it */
930 zName = blob_str(&uuid);
931 break;
932 }
933 case 2: {
934 /* go somewhere to show the multiple UUIDs */
935 tagview_page();
936 return;
937 break;
938 }
939 default: {
940 fossil_redirect_home();
941 break;
942 }
943 }
944 }
945 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%s*'", zName) ){
946 tktview_page();
947 return;
948 }
949
+46 -15
--- src/name.c
+++ src/name.c
@@ -44,34 +44,20 @@
4444
int name_to_uuid(Blob *pName, int iErrPriority){
4545
int rc;
4646
int sz;
4747
sz = blob_size(pName);
4848
if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
49
- Stmt q;
5049
Blob uuid;
5150
static const char prefix[] = "tag:";
5251
static const int preflen = sizeof(prefix)-1;
5352
const char *zName = blob_str(pName);
5453
5554
if( strncmp(zName, prefix, preflen)==0 ){
5655
zName += preflen;
5756
}
5857
59
- db_prepare(&q,
60
- "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
61
- " FROM tagxref JOIN event ON rid=objid"
62
- " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='sym-'||%Q)"
63
- " AND tagtype>0"
64
- " AND value IS NULL"
65
- " ORDER BY event.mtime DESC",
66
- zName
67
- );
68
- blob_zero(&uuid);
69
- if( db_step(&q)==SQLITE_ROW ){
70
- db_column_blob(&q, 0, &uuid);
71
- }
72
- db_finalize(&q);
58
+ sym_tag_to_uuid(zName, &uuid);
7359
if( blob_size(&uuid)==0 ){
7460
fossil_error(iErrPriority, "not a valid object name: %s", zName);
7561
blob_reset(&uuid);
7662
return 1;
7763
}else{
@@ -111,10 +97,55 @@
11197
}else{
11298
rc = 0;
11399
}
114100
return rc;
115101
}
102
+
103
+/*
104
+** This routine takes a name which might be a tag and attempts to
105
+** produce a UUID. The UUID (if any) is returned in the blob pointed
106
+** to by the second argument.
107
+**
108
+** Return as follows:
109
+** 0 Name is not a tag
110
+** 1 A single UUID was found
111
+** 2 More than one UUID was found, so this is presumably a
112
+** propagating tag. The return UUID is the most recent,
113
+** which is most likely to be the one wanted.
114
+*/
115
+int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
116
+ Stmt q;
117
+ int count = 0;
118
+ db_prepare(&q,
119
+ "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120
+ " FROM tagxref JOIN event ON rid=objid"
121
+ " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
122
+ " AND tagtype>0"
123
+ " AND value IS NULL"
124
+ " ORDER BY event.mtime DESC",
125
+ pPrefix,
126
+ pName
127
+ );
128
+ blob_zero(pUuid);
129
+ while( db_step(&q)==SQLITE_ROW ){
130
+ count++;
131
+ if(count>1){
132
+ break;
133
+ }
134
+ db_column_blob(&q, 0, pUuid);
135
+ }
136
+ db_finalize(&q);
137
+ return count;
138
+}
139
+
140
+/*
141
+** This routine takes a name which might be a symbolic tag and
142
+** attempts to produce a UUID. See tag_to_uuid.
143
+*/
144
+int sym_tag_to_uuid(const char *pName, Blob *pUuid){
145
+ return tag_to_uuid(pName,pUuid,"sym-");
146
+}
116147
117148
/*
118149
** COMMAND: test-name-to-uuid
119150
**
120151
** Convert a name to a full UUID.
121152
--- src/name.c
+++ src/name.c
@@ -44,34 +44,20 @@
44 int name_to_uuid(Blob *pName, int iErrPriority){
45 int rc;
46 int sz;
47 sz = blob_size(pName);
48 if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
49 Stmt q;
50 Blob uuid;
51 static const char prefix[] = "tag:";
52 static const int preflen = sizeof(prefix)-1;
53 const char *zName = blob_str(pName);
54
55 if( strncmp(zName, prefix, preflen)==0 ){
56 zName += preflen;
57 }
58
59 db_prepare(&q,
60 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
61 " FROM tagxref JOIN event ON rid=objid"
62 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='sym-'||%Q)"
63 " AND tagtype>0"
64 " AND value IS NULL"
65 " ORDER BY event.mtime DESC",
66 zName
67 );
68 blob_zero(&uuid);
69 if( db_step(&q)==SQLITE_ROW ){
70 db_column_blob(&q, 0, &uuid);
71 }
72 db_finalize(&q);
73 if( blob_size(&uuid)==0 ){
74 fossil_error(iErrPriority, "not a valid object name: %s", zName);
75 blob_reset(&uuid);
76 return 1;
77 }else{
@@ -111,10 +97,55 @@
111 }else{
112 rc = 0;
113 }
114 return rc;
115 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
117 /*
118 ** COMMAND: test-name-to-uuid
119 **
120 ** Convert a name to a full UUID.
121
--- src/name.c
+++ src/name.c
@@ -44,34 +44,20 @@
44 int name_to_uuid(Blob *pName, int iErrPriority){
45 int rc;
46 int sz;
47 sz = blob_size(pName);
48 if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
 
49 Blob uuid;
50 static const char prefix[] = "tag:";
51 static const int preflen = sizeof(prefix)-1;
52 const char *zName = blob_str(pName);
53
54 if( strncmp(zName, prefix, preflen)==0 ){
55 zName += preflen;
56 }
57
58 sym_tag_to_uuid(zName, &uuid);
 
 
 
 
 
 
 
 
 
 
 
 
 
59 if( blob_size(&uuid)==0 ){
60 fossil_error(iErrPriority, "not a valid object name: %s", zName);
61 blob_reset(&uuid);
62 return 1;
63 }else{
@@ -111,10 +97,55 @@
97 }else{
98 rc = 0;
99 }
100 return rc;
101 }
102
103 /*
104 ** This routine takes a name which might be a tag and attempts to
105 ** produce a UUID. The UUID (if any) is returned in the blob pointed
106 ** to by the second argument.
107 **
108 ** Return as follows:
109 ** 0 Name is not a tag
110 ** 1 A single UUID was found
111 ** 2 More than one UUID was found, so this is presumably a
112 ** propagating tag. The return UUID is the most recent,
113 ** which is most likely to be the one wanted.
114 */
115 int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
116 Stmt q;
117 int count = 0;
118 db_prepare(&q,
119 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120 " FROM tagxref JOIN event ON rid=objid"
121 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
122 " AND tagtype>0"
123 " AND value IS NULL"
124 " ORDER BY event.mtime DESC",
125 pPrefix,
126 pName
127 );
128 blob_zero(pUuid);
129 while( db_step(&q)==SQLITE_ROW ){
130 count++;
131 if(count>1){
132 break;
133 }
134 db_column_blob(&q, 0, pUuid);
135 }
136 db_finalize(&q);
137 return count;
138 }
139
140 /*
141 ** This routine takes a name which might be a symbolic tag and
142 ** attempts to produce a UUID. See tag_to_uuid.
143 */
144 int sym_tag_to_uuid(const char *pName, Blob *pUuid){
145 return tag_to_uuid(pName,pUuid,"sym-");
146 }
147
148 /*
149 ** COMMAND: test-name-to-uuid
150 **
151 ** Convert a name to a full UUID.
152
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297297
# define TAG_USER 3 /* User who made a checking */
298298
# define TAG_HIDDEN 4 /* Do not display or sync */
299299
# define TAG_PRIVATE 5 /* Display but do not sync */
300300
# define TAG_CLUSTER 6 /* A cluster */
301301
#endif
302
+#if EXPORT_INTERFACE
303
+# define MAX_INT_TAG 6 /* The largest pre-assigned tag id */
304
+#endif
302305
303306
/*
304307
** The schema for the locate FOSSIL database file found at the root
305308
** of very check-out. This database contains the complete state of
306309
** the checkout.
307310
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297 # define TAG_USER 3 /* User who made a checking */
298 # define TAG_HIDDEN 4 /* Do not display or sync */
299 # define TAG_PRIVATE 5 /* Display but do not sync */
300 # define TAG_CLUSTER 6 /* A cluster */
301 #endif
 
 
 
302
303 /*
304 ** The schema for the locate FOSSIL database file found at the root
305 ** of very check-out. This database contains the complete state of
306 ** the checkout.
307
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297 # define TAG_USER 3 /* User who made a checking */
298 # define TAG_HIDDEN 4 /* Do not display or sync */
299 # define TAG_PRIVATE 5 /* Display but do not sync */
300 # define TAG_CLUSTER 6 /* A cluster */
301 #endif
302 #if EXPORT_INTERFACE
303 # define MAX_INT_TAG 6 /* The largest pre-assigned tag id */
304 #endif
305
306 /*
307 ** The schema for the locate FOSSIL database file found at the root
308 ** of very check-out. This database contains the complete state of
309 ** the checkout.
310
--- src/style.c
+++ src/style.c
@@ -326,10 +326,16 @@
326326
@ padding: 5px 10px 5px 10px;
327327
@ text-align: right;
328328
@ background-color: #558195;
329329
@ color: white;
330330
@ }
331
+@
332
+@ /* Make the links in the footer less ugly... */
333
+@ div.footer a { color: white; }
334
+@ div.footer a:link { color: white; }
335
+@ div.footer a:visited { color: white; }
336
+@ div.footer a:hover { background-color: white; color: #558195; }
331337
@
332338
@ /* <verbatim> blocks */
333339
@ pre.verbatim {
334340
@ background-color: #f5f5f5;
335341
@ padding: 0.5em;
336342
--- src/style.c
+++ src/style.c
@@ -326,10 +326,16 @@
326 @ padding: 5px 10px 5px 10px;
327 @ text-align: right;
328 @ background-color: #558195;
329 @ color: white;
330 @ }
 
 
 
 
 
 
331 @
332 @ /* <verbatim> blocks */
333 @ pre.verbatim {
334 @ background-color: #f5f5f5;
335 @ padding: 0.5em;
336
--- src/style.c
+++ src/style.c
@@ -326,10 +326,16 @@
326 @ padding: 5px 10px 5px 10px;
327 @ text-align: right;
328 @ background-color: #558195;
329 @ color: white;
330 @ }
331 @
332 @ /* Make the links in the footer less ugly... */
333 @ div.footer a { color: white; }
334 @ div.footer a:link { color: white; }
335 @ div.footer a:visited { color: white; }
336 @ div.footer a:hover { background-color: white; color: #558195; }
337 @
338 @ /* <verbatim> blocks */
339 @ pre.verbatim {
340 @ background-color: #f5f5f5;
341 @ padding: 0.5em;
342
+109 -7
--- src/tagview.c
+++ src/tagview.c
@@ -60,11 +60,11 @@
6060
" linktagid(t.tagid) AS 'Tag ID',"
6161
" linktagname(t.tagname) AS 'Name',"
6262
" DATETIME(tx.mtime) AS 'Timestamp',"
6363
" linkuuid(b.uuid) AS 'Version'"
6464
" FROM tag t, tagxref tx, blob b "
65
- " WHERE t.tagid=tx.tagid AND tx.srcid=b.rid"
65
+ " WHERE t.tagid=tx.tagid AND tx.rid=b.rid"
6666
" AND tx.tagtype!=0 %s "
6767
TAGVIEW_DEFAULT_FILTER
6868
" ORDER BY tx.mtime DESC %s",
6969
zLikeClause, zLimit
7070
);
@@ -78,11 +78,11 @@
7878
** A small search form which forwards to ?like=SEARCH_STRING
7979
*/
8080
static void tagview_page_search_miniform(void){
8181
char const * like = P("like");
8282
@ <div style='font-size:smaller'>
83
- @ <form action='/tagview' method='post'>
83
+ @ <form action='tagview' method='post'>
8484
@ Search for tags:
8585
@ <input type='text' name='like' value='%h((like?like:""))' size='10'/>
8686
@ <input type='submit'/>
8787
@ </form>
8888
@ </div>
@@ -105,11 +105,11 @@
105105
"SELECT DISTINCT"
106106
" linktagname(t.tagname) AS 'Tag Name',"
107107
" DATETIME(tx.mtime) AS 'Timestamp',"
108108
" linkuuid(b.uuid) AS 'Version'"
109109
" FROM tag t, tagxref tx, blob b"
110
- " WHERE t.tagid=%d AND t.tagid=tx.tagid AND tx.srcid=b.rid "
110
+ " WHERE t.tagid=%d AND t.tagid=tx.tagid AND tx.rid=b.rid "
111111
TAGVIEW_DEFAULT_FILTER
112112
" ORDER BY tx.mtime DESC",
113113
tagid
114114
);
115115
db_generic_query_view(zSql, 1);
@@ -126,23 +126,22 @@
126126
"SELECT DISTINCT"
127127
" linktagid(t.tagid) AS 'Tag ID',"
128128
" DATETIME(tx.mtime) AS 'Timestamp',"
129129
" linkuuid(b.uuid) AS 'Version'"
130130
" FROM tag t, tagxref tx, blob b "
131
- " WHERE t.tagname='%q' AND t.tagid=tx.tagid AND tx.srcid=b.rid "
131
+ " WHERE t.tagname='%q' AND t.tagid=tx.tagid AND tx.rid=b.rid "
132132
TAGVIEW_DEFAULT_FILTER
133133
" ORDER BY tx.mtime DESC",
134134
tagname);
135135
db_generic_query_view(zSql, 1);
136136
free(zSql);
137137
}
138138
139
-
140139
/*
141
-** WEBPAGE: /tagview
140
+** WEBP AGE: /tagview
142141
*/
143
-void tagview_page(void){
142
+void old_tagview_page(void){
144143
char const * check = 0;
145144
login_check_credentials();
146145
if( !g.okRdWiki ){
147146
login_needed();
148147
}
@@ -161,5 +160,108 @@
161160
}
162161
style_footer();
163162
}
164163
165164
#undef TAGVIEW_DEFAULT_FILTER
165
+
166
+/*
167
+** Generate a timeline for the chosen tag
168
+*/
169
+void tagview_print_timeline(char const *pName, char const *pPrefix){
170
+ char *zSql;
171
+ Stmt q;
172
+ zSql = mprintf("%s AND EXISTS (SELECT 1"
173
+ " FROM tagxref"
174
+ " WHERE tagxref.rid = event.objid"
175
+ " AND tagxref.tagid = (SELECT tagid FROM tag"
176
+ " WHERE tagname = %Q||%Q))"
177
+ " ORDER BY 3 desc",
178
+ timeline_query_for_www(), pPrefix, pName);
179
+ db_prepare(&q, zSql);
180
+ free(zSql);
181
+ www_print_timeline(&q);
182
+ db_finalize(&q);
183
+}
184
+
185
+/*
186
+** WEBPAGE: /tagview
187
+*/
188
+void tagview_page(void){
189
+ char const *zName = 0;
190
+ int zTcount = 0;
191
+ login_check_credentials();
192
+ if( !g.okRead ){
193
+ login_needed();
194
+ }
195
+ login_anonymous_available();
196
+ if( 0 != (zName = P("name")) ){
197
+ Blob uuid;
198
+ style_header("Tagged Baselines");
199
+ @ <h2>%s(zName):</h2>
200
+ if( sym_tag_to_uuid(zName, &uuid) > 0){
201
+ tagview_print_timeline(zName, "sym-");
202
+ }else if( tag_to_uuid(zName, &uuid, "") > 0){
203
+ tagview_print_timeline(zName, "");
204
+ }else{
205
+ @ There is no artifact with this tag.
206
+ }
207
+ }else{
208
+ Stmt q;
209
+ const char *prefix = "sym-";
210
+ int preflen = strlen(prefix);
211
+ style_header("Tags");
212
+ db_prepare(&q,
213
+ "SELECT tagname"
214
+ " FROM tag"
215
+ " WHERE EXISTS(SELECT 1 FROM tagxref"
216
+ " WHERE tagid=tag.tagid"
217
+ " AND tagtype>0)"
218
+ " AND tagid > %d"
219
+ " AND tagname NOT GLOB 'wiki-*'"
220
+ " AND tagname NOT GLOB 'tkt-*'"
221
+ " ORDER BY tagname",
222
+ MAX_INT_TAG
223
+ );
224
+ @ <ul>
225
+ while( db_step(&q)==SQLITE_ROW ){
226
+ zTcount++;
227
+ const char *name = db_column_text(&q, 0);
228
+ if( g.okHistory ){
229
+ if( strncmp(name, prefix, preflen)==0 ){
230
+ @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
231
+ @ %s(name+preflen)</a>
232
+ }else{
233
+ @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
234
+ @ %s(name)</a>
235
+ }
236
+ }else{
237
+ if( strncmp(name, prefix, preflen)==0 ){
238
+ @ <li><strong>%s(name+preflen)</strong>
239
+ }else{
240
+ @ <li><strong>%s(name)</strong>
241
+ }
242
+ }
243
+ if( strncmp(name, prefix, preflen)==0 ){
244
+ @ (symbolic label)
245
+ }
246
+ @ </li>
247
+ }
248
+ @ </ul>
249
+ if( zTcount == 0) {
250
+ @ There are no relevant tags.
251
+ }
252
+ db_finalize(&q);
253
+ }
254
+ /*
255
+ * Put in dummy functions since www_print_timeline has generated calls to
256
+ * them. Some browsers don't seem to care, but better to be safe.
257
+ * Actually, it would be nice to use the functions on this page, but at
258
+ * the moment it looks to be too difficult.
259
+ */
260
+ @ <script>
261
+ @ function xin(id){
262
+ @ }
263
+ @ function xout(id){
264
+ @ }
265
+ @ </script>
266
+ style_footer();
267
+}
166268
--- src/tagview.c
+++ src/tagview.c
@@ -60,11 +60,11 @@
60 " linktagid(t.tagid) AS 'Tag ID',"
61 " linktagname(t.tagname) AS 'Name',"
62 " DATETIME(tx.mtime) AS 'Timestamp',"
63 " linkuuid(b.uuid) AS 'Version'"
64 " FROM tag t, tagxref tx, blob b "
65 " WHERE t.tagid=tx.tagid AND tx.srcid=b.rid"
66 " AND tx.tagtype!=0 %s "
67 TAGVIEW_DEFAULT_FILTER
68 " ORDER BY tx.mtime DESC %s",
69 zLikeClause, zLimit
70 );
@@ -78,11 +78,11 @@
78 ** A small search form which forwards to ?like=SEARCH_STRING
79 */
80 static void tagview_page_search_miniform(void){
81 char const * like = P("like");
82 @ <div style='font-size:smaller'>
83 @ <form action='/tagview' method='post'>
84 @ Search for tags:
85 @ <input type='text' name='like' value='%h((like?like:""))' size='10'/>
86 @ <input type='submit'/>
87 @ </form>
88 @ </div>
@@ -105,11 +105,11 @@
105 "SELECT DISTINCT"
106 " linktagname(t.tagname) AS 'Tag Name',"
107 " DATETIME(tx.mtime) AS 'Timestamp',"
108 " linkuuid(b.uuid) AS 'Version'"
109 " FROM tag t, tagxref tx, blob b"
110 " WHERE t.tagid=%d AND t.tagid=tx.tagid AND tx.srcid=b.rid "
111 TAGVIEW_DEFAULT_FILTER
112 " ORDER BY tx.mtime DESC",
113 tagid
114 );
115 db_generic_query_view(zSql, 1);
@@ -126,23 +126,22 @@
126 "SELECT DISTINCT"
127 " linktagid(t.tagid) AS 'Tag ID',"
128 " DATETIME(tx.mtime) AS 'Timestamp',"
129 " linkuuid(b.uuid) AS 'Version'"
130 " FROM tag t, tagxref tx, blob b "
131 " WHERE t.tagname='%q' AND t.tagid=tx.tagid AND tx.srcid=b.rid "
132 TAGVIEW_DEFAULT_FILTER
133 " ORDER BY tx.mtime DESC",
134 tagname);
135 db_generic_query_view(zSql, 1);
136 free(zSql);
137 }
138
139
140 /*
141 ** WEBPAGE: /tagview
142 */
143 void tagview_page(void){
144 char const * check = 0;
145 login_check_credentials();
146 if( !g.okRdWiki ){
147 login_needed();
148 }
@@ -161,5 +160,108 @@
161 }
162 style_footer();
163 }
164
165 #undef TAGVIEW_DEFAULT_FILTER
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
--- src/tagview.c
+++ src/tagview.c
@@ -60,11 +60,11 @@
60 " linktagid(t.tagid) AS 'Tag ID',"
61 " linktagname(t.tagname) AS 'Name',"
62 " DATETIME(tx.mtime) AS 'Timestamp',"
63 " linkuuid(b.uuid) AS 'Version'"
64 " FROM tag t, tagxref tx, blob b "
65 " WHERE t.tagid=tx.tagid AND tx.rid=b.rid"
66 " AND tx.tagtype!=0 %s "
67 TAGVIEW_DEFAULT_FILTER
68 " ORDER BY tx.mtime DESC %s",
69 zLikeClause, zLimit
70 );
@@ -78,11 +78,11 @@
78 ** A small search form which forwards to ?like=SEARCH_STRING
79 */
80 static void tagview_page_search_miniform(void){
81 char const * like = P("like");
82 @ <div style='font-size:smaller'>
83 @ <form action='tagview' method='post'>
84 @ Search for tags:
85 @ <input type='text' name='like' value='%h((like?like:""))' size='10'/>
86 @ <input type='submit'/>
87 @ </form>
88 @ </div>
@@ -105,11 +105,11 @@
105 "SELECT DISTINCT"
106 " linktagname(t.tagname) AS 'Tag Name',"
107 " DATETIME(tx.mtime) AS 'Timestamp',"
108 " linkuuid(b.uuid) AS 'Version'"
109 " FROM tag t, tagxref tx, blob b"
110 " WHERE t.tagid=%d AND t.tagid=tx.tagid AND tx.rid=b.rid "
111 TAGVIEW_DEFAULT_FILTER
112 " ORDER BY tx.mtime DESC",
113 tagid
114 );
115 db_generic_query_view(zSql, 1);
@@ -126,23 +126,22 @@
126 "SELECT DISTINCT"
127 " linktagid(t.tagid) AS 'Tag ID',"
128 " DATETIME(tx.mtime) AS 'Timestamp',"
129 " linkuuid(b.uuid) AS 'Version'"
130 " FROM tag t, tagxref tx, blob b "
131 " WHERE t.tagname='%q' AND t.tagid=tx.tagid AND tx.rid=b.rid "
132 TAGVIEW_DEFAULT_FILTER
133 " ORDER BY tx.mtime DESC",
134 tagname);
135 db_generic_query_view(zSql, 1);
136 free(zSql);
137 }
138
 
139 /*
140 ** WEBP AGE: /tagview
141 */
142 void old_tagview_page(void){
143 char const * check = 0;
144 login_check_credentials();
145 if( !g.okRdWiki ){
146 login_needed();
147 }
@@ -161,5 +160,108 @@
160 }
161 style_footer();
162 }
163
164 #undef TAGVIEW_DEFAULT_FILTER
165
166 /*
167 ** Generate a timeline for the chosen tag
168 */
169 void tagview_print_timeline(char const *pName, char const *pPrefix){
170 char *zSql;
171 Stmt q;
172 zSql = mprintf("%s AND EXISTS (SELECT 1"
173 " FROM tagxref"
174 " WHERE tagxref.rid = event.objid"
175 " AND tagxref.tagid = (SELECT tagid FROM tag"
176 " WHERE tagname = %Q||%Q))"
177 " ORDER BY 3 desc",
178 timeline_query_for_www(), pPrefix, pName);
179 db_prepare(&q, zSql);
180 free(zSql);
181 www_print_timeline(&q);
182 db_finalize(&q);
183 }
184
185 /*
186 ** WEBPAGE: /tagview
187 */
188 void tagview_page(void){
189 char const *zName = 0;
190 int zTcount = 0;
191 login_check_credentials();
192 if( !g.okRead ){
193 login_needed();
194 }
195 login_anonymous_available();
196 if( 0 != (zName = P("name")) ){
197 Blob uuid;
198 style_header("Tagged Baselines");
199 @ <h2>%s(zName):</h2>
200 if( sym_tag_to_uuid(zName, &uuid) > 0){
201 tagview_print_timeline(zName, "sym-");
202 }else if( tag_to_uuid(zName, &uuid, "") > 0){
203 tagview_print_timeline(zName, "");
204 }else{
205 @ There is no artifact with this tag.
206 }
207 }else{
208 Stmt q;
209 const char *prefix = "sym-";
210 int preflen = strlen(prefix);
211 style_header("Tags");
212 db_prepare(&q,
213 "SELECT tagname"
214 " FROM tag"
215 " WHERE EXISTS(SELECT 1 FROM tagxref"
216 " WHERE tagid=tag.tagid"
217 " AND tagtype>0)"
218 " AND tagid > %d"
219 " AND tagname NOT GLOB 'wiki-*'"
220 " AND tagname NOT GLOB 'tkt-*'"
221 " ORDER BY tagname",
222 MAX_INT_TAG
223 );
224 @ <ul>
225 while( db_step(&q)==SQLITE_ROW ){
226 zTcount++;
227 const char *name = db_column_text(&q, 0);
228 if( g.okHistory ){
229 if( strncmp(name, prefix, preflen)==0 ){
230 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
231 @ %s(name+preflen)</a>
232 }else{
233 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
234 @ %s(name)</a>
235 }
236 }else{
237 if( strncmp(name, prefix, preflen)==0 ){
238 @ <li><strong>%s(name+preflen)</strong>
239 }else{
240 @ <li><strong>%s(name)</strong>
241 }
242 }
243 if( strncmp(name, prefix, preflen)==0 ){
244 @ (symbolic label)
245 }
246 @ </li>
247 }
248 @ </ul>
249 if( zTcount == 0) {
250 @ There are no relevant tags.
251 }
252 db_finalize(&q);
253 }
254 /*
255 * Put in dummy functions since www_print_timeline has generated calls to
256 * them. Some browsers don't seem to care, but better to be safe.
257 * Actually, it would be nice to use the functions on this page, but at
258 * the moment it looks to be too difficult.
259 */
260 @ <script>
261 @ function xin(id){
262 @ }
263 @ function xout(id){
264 @ }
265 @ </script>
266 style_footer();
267 }
268

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button