Fossil SCM

Refactor the name resolution logic in name.c.

drh 2011-11-03 01:22 trunk
Commit 7858a39b36b5388c441eb84461a795bd9e260531
1 file changed +243 -257
+243 -257
--- src/name.c
+++ src/name.c
@@ -22,10 +22,220 @@
2222
** not necessarily in canonical form.
2323
*/
2424
#include "config.h"
2525
#include "name.h"
2626
#include <assert.h>
27
+
28
+/*
29
+** Return TRUE if the string begins with something that looks roughly
30
+** like an ISO date/time string. The SQLite date/time functions will
31
+** have the final say-so about whether or not the date/time string is
32
+** well-formed.
33
+*/
34
+static int is_date(const char *z){
35
+ if( !fossil_isdigit(z[0]) ) return 0;
36
+ if( !fossil_isdigit(z[1]) ) return 0;
37
+ if( !fossil_isdigit(z[2]) ) return 0;
38
+ if( !fossil_isdigit(z[3]) ) return 0;
39
+ if( z[4]!='-') return 0;
40
+ if( !fossil_isdigit(z[5]) ) return 0;
41
+ if( !fossil_isdigit(z[6]) ) return 0;
42
+ if( z[7]!='-') return 0;
43
+ if( !fossil_isdigit(z[8]) ) return 0;
44
+ if( !fossil_isdigit(z[9]) ) return 0;
45
+ return 1;
46
+}
47
+
48
+/*
49
+** Convert a symbolic name into a RID. Acceptable forms:
50
+**
51
+** * SHA1 hash
52
+** * SHA1 hash prefix of at least 4 characters
53
+** * Symbolic Name
54
+** * "tag:" + symbolic name
55
+** * Date or date-time
56
+** * "date:" + Date or date-time
57
+** * symbolic-name ":" date-time
58
+** * "tip"
59
+**
60
+** The following additional forms are available in local checkouts:
61
+**
62
+** * "current"
63
+** * "prev" or "previous"
64
+** * "next"
65
+**
66
+** Return the RID of the matching artifact. Or return 0 if the name does not
67
+** match any known object. Or return -1 if the name is ambiguious.
68
+**
69
+** The zType parameter specifies the type of artifact: ci, t, w, e, g.
70
+** If zType is NULL or "" or "*" then any type of artifact will serve.
71
+** zType is "ci" in most use cases since we are usually searching for
72
+** a check-in.
73
+*/
74
+static int symbolic_name_to_rid(const char *zTag, const char *zType){
75
+ int vid;
76
+ int rid = 0;
77
+ int nTag;
78
+ int i;
79
+
80
+ if( zType==0 || zType[0]==0 ) zType = "*";
81
+ if( zTag==0 || zTag[0]==0 ) return 0;
82
+
83
+ /* special keyword: "tip" */
84
+ if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){
85
+ rid = db_int(0,
86
+ "SELECT objid"
87
+ " FROM event"
88
+ " WHERE type='ci'"
89
+ " ORDER BY event.mtime DESC"
90
+ );
91
+ if( rid ) return rid;
92
+ }
93
+
94
+ /* special keywords: "prev", "previous", "current", and "next" */
95
+ if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
96
+ if( fossil_strcmp(zTag, "current")==0 ){
97
+ rid = vid;
98
+ }else if( fossil_strcmp(zTag, "prev")==0
99
+ || fossil_strcmp(zTag, "previous")==0 ){
100
+ rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid);
101
+ }else if( fossil_strcmp(zTag, "next")==0 ){
102
+ rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
103
+ " ORDER BY isprim DESC, mtime DESC", vid);
104
+ }
105
+ if( rid ) return rid;
106
+ }
107
+
108
+ /* Date and times */
109
+ if( memcmp(zTag, "date:", 5)==0 ){
110
+ rid = db_int(0,
111
+ "SELECT objid FROM event"
112
+ " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
113
+ " ORDER BY mtime DESC LIMIT 1",
114
+ &zTag[5], zType);
115
+ return rid;
116
+ }
117
+ if( is_date(zTag) ){
118
+ rid = db_int(0,
119
+ "SELECT objid FROM event"
120
+ " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
121
+ " ORDER BY mtime DESC LIMIT 1",
122
+ zTag, zType);
123
+ if( rid) return rid;
124
+ }
125
+
126
+ /* Deprecated date & time formats: "local:" + date-time and
127
+ ** "utc:" + date-time */
128
+ if( memcmp(zTag, "local:", 6)==0 ){
129
+ rid = db_int(0,
130
+ "SELECT objid FROM event"
131
+ " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
132
+ " ORDER BY mtime DESC LIMIT 1",
133
+ &zTag[6], zType);
134
+ return rid;
135
+ }
136
+ if( memcmp(zTag, "utc:", 4)==0 ){
137
+ rid = db_int(0,
138
+ "SELECT objid FROM event"
139
+ " WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
140
+ " ORDER BY mtime DESC LIMIT 1",
141
+ &zTag[4], zType);
142
+ return rid;
143
+ }
144
+
145
+ /* "tag:" + symbolic-name */
146
+ if( memcmp(zTag, "tag:", 4)==0 ){
147
+ rid = db_int(0,
148
+ "SELECT event.objid"
149
+ " FROM tag, tagxref, event"
150
+ " WHERE tag.tagname='sym-%q' "
151
+ " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
152
+ " AND event.objid=tagxref.rid "
153
+ " AND event.type GLOB '%q'"
154
+ " ORDER BY event.mtime DESC /*sort*/",
155
+ &zTag[4], zType
156
+ );
157
+ return rid;
158
+ }
159
+
160
+ /* symbolic-name ":" date-time */
161
+ nTag = strlen(zTag);
162
+ for(i=0; i<nTag-10 && zTag[i]!=':'; i++){}
163
+ if( zTag[i]==':' && is_date(&zTag[i+1]) ){
164
+ char *zDate = mprintf("%s", &zTag[i+1]);
165
+ char *zTagBase = mprintf("%.*s", i, zTag);
166
+ int nDate = strlen(zDate);
167
+ if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
168
+ zDate[nDate-3] = 'z';
169
+ zDate[nDate-2] = 0;
170
+ }
171
+ rid = db_int(0,
172
+ "SELECT event.objid"
173
+ " FROM tag, tagxref, event"
174
+ " WHERE tag.tagname='sym-%q' "
175
+ " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
176
+ " AND event.objid=tagxref.rid "
177
+ " AND event.mtime<=julianday(%Q)"
178
+ " AND event.type GLOB '%q'"
179
+ " ORDER BY event.mtime DESC /*sort*/ ",
180
+ zTagBase, zDate, zType
181
+ );
182
+ return rid;
183
+ }
184
+
185
+ /* SHA1 hash or prefix */
186
+ if( nTag>=4 && nTag<=UUID_SIZE && validate16(zTag, nTag) ){
187
+ Stmt q;
188
+ char zUuid[UUID_SIZE+1];
189
+ memcpy(zUuid, zTag, nTag+1);
190
+ canonical16(zUuid, nTag);
191
+ rid = 0;
192
+ if( zType[0]=='*' ){
193
+ db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%s*'", zUuid);
194
+ }else{
195
+ db_prepare(&q,
196
+ "SELECT blob.rid"
197
+ " FROM blob, event"
198
+ " WHERE blob.uuid GLOB '%s*'"
199
+ " AND event.objid=blob.rid"
200
+ " AND event.type GLOB '%q'",
201
+ zUuid, zType
202
+ );
203
+ }
204
+ if( db_step(&q)==SQLITE_ROW ){
205
+ rid = db_column_int(&q, 0);
206
+ if( db_step(&q)==SQLITE_ROW ) rid = -1;
207
+ }
208
+ db_finalize(&q);
209
+ if( rid ) return rid;
210
+ }
211
+
212
+ /* Symbolic name */
213
+ rid = db_int(0,
214
+ "SELECT event.objid"
215
+ " FROM tag, tagxref, event"
216
+ " WHERE tag.tagname='sym-%q' "
217
+ " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
218
+ " AND event.objid=tagxref.rid "
219
+ " AND event.type GLOB '%q'"
220
+ " ORDER BY event.mtime DESC /*sort*/ ",
221
+ zTag, zType
222
+ );
223
+ if( rid>0 ) return rid;
224
+
225
+ /* Undocumented: numeric tags get translated directly into the RID */
226
+ for(i=0; fossil_isdigit(zTag[i]); i++){}
227
+ if( zTag[i]==0 ){
228
+ rid = db_int(0,
229
+ "SELECT event.objid"
230
+ " FROM event"
231
+ " WHERE event.objid=%s"
232
+ " AND event.type GLOB '%q'", zTag, zType);
233
+ }
234
+ return rid;
235
+}
236
+
27237
28238
/*
29239
** This routine takes a user-entered UUID which might be in mixed
30240
** case and might only be a prefix of the full UUID and converts it
31241
** into the full-length UUID in canonical form.
@@ -41,228 +251,23 @@
41251
**
42252
** Return 0 on success. Return 1 if the name cannot be resolved.
43253
** Return 2 name is ambiguous.
44254
*/
45255
int name_to_uuid(Blob *pName, int iErrPriority, const char *zType){
46
- int rc;
47
- int sz;
48
- sz = blob_size(pName);
49
- if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
50
- char *zUuid;
51
- const char *zName = blob_str(pName);
52
- if( memcmp(zName, "tag:", 4)==0 ){
53
- zName += 4;
54
- zUuid = tag_to_uuid(zName, zType);
55
- }else{
56
- zUuid = tag_to_uuid(zName, zType);
57
- if( zUuid==0 ){
58
- zUuid = date_to_uuid(zName, zType);
59
- }
60
- }
61
- if( zUuid ){
62
- blob_reset(pName);
63
- blob_append(pName, zUuid, -1);
64
- free(zUuid);
65
- return 0;
66
- }
67
- fossil_error(iErrPriority, "not a valid object name: %s", zName);
68
- return 1;
69
- }
70
- blob_materialize(pName);
71
- canonical16(blob_buffer(pName), sz);
72
- if( sz==UUID_SIZE ){
73
- rc = db_int(1, "SELECT 0 FROM blob WHERE uuid=%B", pName);
74
- if( rc ){
75
- fossil_error(iErrPriority, "no such artifact: %b", pName);
76
- blob_reset(pName);
77
- }
78
- }else if( sz<UUID_SIZE && sz>=4 ){
79
- Stmt q;
80
- db_prepare(&q, "SELECT uuid FROM blob WHERE uuid GLOB '%b*'", pName);
81
- if( db_step(&q)!=SQLITE_ROW ){
82
- char *zUuid;
83
- db_finalize(&q);
84
- zUuid = tag_to_uuid(blob_str(pName), "*");
85
- if( zUuid ){
86
- blob_reset(pName);
87
- blob_append(pName, zUuid, -1);
88
- free(zUuid);
89
- return 0;
90
- }
91
- fossil_error(iErrPriority, "no artifacts match the prefix \"%b\"", pName);
92
- return 1;
93
- }
94
- blob_reset(pName);
95
- blob_append(pName, db_column_text(&q, 0), db_column_bytes(&q, 0));
96
- if( db_step(&q)==SQLITE_ROW ){
97
- fossil_error(iErrPriority,
98
- "multiple artifacts match"
99
- );
100
- blob_reset(pName);
101
- db_finalize(&q);
102
- return 2;
103
- }
104
- db_finalize(&q);
105
- rc = 0;
106
- }else{
107
- rc = 0;
108
- }
109
- return rc;
110
-}
111
-
112
-/*
113
-** Return TRUE if the string begins with an ISO8601 date: YYYY-MM-DD.
114
-*/
115
-static int is_date(const char *z){
116
- if( !fossil_isdigit(z[0]) ) return 0;
117
- if( !fossil_isdigit(z[1]) ) return 0;
118
- if( !fossil_isdigit(z[2]) ) return 0;
119
- if( !fossil_isdigit(z[3]) ) return 0;
120
- if( z[4]!='-') return 0;
121
- if( !fossil_isdigit(z[5]) ) return 0;
122
- if( !fossil_isdigit(z[6]) ) return 0;
123
- if( z[7]!='-') return 0;
124
- if( !fossil_isdigit(z[8]) ) return 0;
125
- if( !fossil_isdigit(z[9]) ) return 0;
126
- return 1;
127
-}
128
-
129
-/*
130
-** Convert a symbolic tag name into the UUID of a check-in that contains
131
-** that tag. If the tag appears on multiple check-ins, return the UUID
132
-** of the most recent check-in with the tag.
133
-**
134
-** If the input string is of the form:
135
-**
136
-** tag:date
137
-**
138
-** Then return the UUID of the oldest check-in with that tag that is
139
-** not older than 'date'.
140
-**
141
-** An input of "tip" returns the most recent check-in.
142
-**
143
-** Memory to hold the returned string comes from malloc() and needs to
144
-** be freed by the caller.
145
-*/
146
-char *tag_to_uuid(const char *zTag, const char *zType){
147
- int vid;
148
- char *zUuid;
149
-
150
- if( zType==0 || zType[0]==0 ) zType = "*";
151
- zUuid = db_text(0,
152
- "SELECT blob.uuid"
153
- " FROM tag, tagxref, event, blob"
154
- " WHERE tag.tagname='sym-%q' "
155
- " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
156
- " AND event.objid=tagxref.rid "
157
- " AND blob.rid=event.objid "
158
- " AND event.type GLOB '%q'"
159
- " ORDER BY event.mtime DESC /*sort*/",
160
- zTag, zType
161
- );
162
- if( zUuid==0 ){
163
- int nTag = strlen(zTag);
164
- int i;
165
- for(i=0; i<nTag-10; i++){
166
- if( zTag[i]==':' && is_date(&zTag[i+1]) ){
167
- char *zDate = mprintf("%s", &zTag[i+1]);
168
- char *zTagBase = mprintf("%.*s", i, zTag);
169
- int nDate = strlen(zDate);
170
- int useUtc = 0;
171
- if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
172
- nDate -= 3;
173
- zDate[nDate] = 0;
174
- useUtc = 1;
175
- }
176
- zUuid = db_text(0,
177
- "SELECT blob.uuid"
178
- " FROM tag, tagxref, event, blob"
179
- " WHERE tag.tagname='sym-%q' "
180
- " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
181
- " AND event.objid=tagxref.rid "
182
- " AND blob.rid=event.objid "
183
- " AND event.mtime<=julianday(%Q %s)"
184
- " AND event.type GLOB '%q'"
185
- " ORDER BY event.mtime DESC /*sort*/ ",
186
- zTagBase, zDate, (useUtc ? "" : ",'utc'"), zType
187
- );
188
- break;
189
- }
190
- }
191
- if( zUuid==0 && fossil_strcmp(zTag, "tip")==0 ){
192
- zUuid = db_text(0,
193
- "SELECT blob.uuid"
194
- " FROM event, blob"
195
- " WHERE event.type='ci'"
196
- " AND blob.rid=event.objid"
197
- " ORDER BY event.mtime DESC"
198
- );
199
- }
200
- if( zUuid==0 && g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
201
- if( fossil_strcmp(zTag, "current")==0 ){
202
- zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
203
- }else if( fossil_strcmp(zTag, "prev")==0
204
- || fossil_strcmp(zTag, "previous")==0 ){
205
- zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid="
206
- "(SELECT pid FROM plink WHERE cid=%d AND isprim)",
207
- vid);
208
- }else if( fossil_strcmp(zTag, "next")==0 ){
209
- zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid="
210
- "(SELECT cid FROM plink WHERE pid=%d"
211
- " ORDER BY isprim DESC, mtime DESC)",
212
- vid);
213
- }
214
- }
215
- }
216
- return zUuid;
217
-}
218
-
219
-/*
220
-** Convert a date/time string into a UUID.
221
-**
222
-** Input forms accepted:
223
-**
224
-** date:DATE
225
-** local:DATE
226
-** utc:DATE
227
-**
228
-** The DATE is interpreted as localtime unless the "utc:" prefix is used
229
-** or a "utc" string appears at the end of the DATE string.
230
-*/
231
-char *date_to_uuid(const char *zDate, const char *zType){
232
- int useUtc = 0;
233
- int n;
234
- char *zCopy = 0;
235
- char *zUuid;
236
-
237
- if( memcmp(zDate, "date:", 5)==0 ){
238
- zDate += 5;
239
- }else if( memcmp(zDate, "local:", 6)==0 ){
240
- zDate += 6;
241
- }else if( memcmp(zDate, "utc:", 4)==0 ){
242
- zDate += 4;
243
- useUtc = 1;
244
- }
245
- n = strlen(zDate);
246
- if( n<10 || !is_date(zDate) ) return 0;
247
- if( n>4 && sqlite3_strnicmp(&zDate[n-3], "utc", 3)==0 ){
248
- zCopy = mprintf("%s", zDate);
249
- zCopy[n-3] = 0;
250
- zDate = zCopy;
251
- n -= 3;
252
- useUtc = 1;
253
- }
254
- if( zType==0 || zType[0]==0 ) zType = "*";
255
- zUuid = db_text(0,
256
- "SELECT (SELECT uuid FROM blob WHERE rid=event.objid)"
257
- " FROM event"
258
- " WHERE mtime<=julianday(%Q %s) AND type GLOB '%q'"
259
- " ORDER BY mtime DESC LIMIT 1",
260
- zDate, useUtc ? "" : ",'utc'", zType
261
- );
262
- free(zCopy);
263
- return zUuid;
256
+ char *zName = blob_str(pName);
257
+ int rid = symbolic_name_to_rid(zName, zType);
258
+ if( rid<0 ){
259
+ fossil_error(iErrPriority, "ambiguous name: %s", zName);
260
+ return 2;
261
+ }else if( rid==0 ){
262
+ fossil_error(iErrPriority, "not found: %s", zName);
263
+ return 1;
264
+ }else{
265
+ blob_reset(pName);
266
+ db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid);
267
+ return 0;
268
+ }
264269
}
265270
266271
/*
267272
** COMMAND: test-name-to-id
268273
**
@@ -284,41 +289,38 @@
284289
blob_reset(&name);
285290
}
286291
}
287292
288293
/*
289
-** Convert a name to a rid. If the name is a small integer value then
290
-** just use atoi() to do the conversion. If the name contains alphabetic
291
-** characters or is not an existing rid, then use name_to_uuid then
292
-** convert the uuid to a rid.
294
+** Convert a name to a rid. If the name can be any of the various forms
295
+** accepted:
296
+**
297
+** * SHA1 hash or prefix thereof
298
+** * symbolic name
299
+** * date
300
+** * label:date
301
+** * prev, previous
302
+** * next
303
+** * tip
293304
**
294305
** This routine is used by command-line routines to resolve command-line inputs
295306
** into a rid.
296307
*/
297308
int name_to_typed_rid(const char *zName, const char *zType){
298
- int i;
299309
int rid;
300
- Blob name;
301310
302311
if( zName==0 || zName[0]==0 ) return 0;
303
- blob_init(&name, zName, -1);
304
- if( name_to_uuid(&name, -1, zType) ){
305
- blob_reset(&name);
306
- for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
307
- if( zName[i]==0 ){
308
- rid = atoi(zName);
309
- if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
310
- return rid;
311
- }
312
- }
313
- fossil_error(1, "no such artifact: %s", zName);
312
+ rid = symbolic_name_to_rid(zName, zType);
313
+ if( rid<0 ){
314
+ fossil_error(1, "ambiguous name: %s", zName);
315
+ return 0;
316
+ }else if( rid==0 ){
317
+ fossil_error(1, "not found: %s", zName);
314318
return 0;
315319
}else{
316
- rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
317
- blob_reset(&name);
320
+ return rid;
318321
}
319
- return rid;
320322
}
321323
int name_to_rid(const char *zName){
322324
return name_to_typed_rid(zName, "*");
323325
}
324326
@@ -362,32 +364,16 @@
362364
** rid. If the CGI parameter is missing or is not a valid artifact tag,
363365
** return 0. If the CGI parameter is ambiguous, redirect to a page that
364366
** shows all possibilities and do not return.
365367
*/
366368
int name_to_rid_www(const char *zParamName){
367
- int i, rc;
368369
int rid;
369370
const char *zName = P(zParamName);
370
- Blob name;
371371
372372
if( zName==0 || zName[0]==0 ) return 0;
373
- blob_init(&name, zName, -1);
374
- rc = name_to_uuid(&name, -1, "*");
375
- if( rc==1 ){
376
- blob_reset(&name);
377
- for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
378
- if( zName[i]==0 ){
379
- rid = atoi(zName);
380
- if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
381
- return rid;
382
- }
383
- }
384
- return 0;
385
- }else if( rc==2 ){
373
+ rid = symbolic_name_to_rid(zName, "*");
374
+ if( rid<0 ){
386375
cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
387
- return 0;
388
- }else{
389
- rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
390
- blob_reset(&name);
376
+ rid = 0;
391377
}
392378
return rid;
393379
}
394380
--- src/name.c
+++ src/name.c
@@ -22,10 +22,220 @@
22 ** not necessarily in canonical form.
23 */
24 #include "config.h"
25 #include "name.h"
26 #include <assert.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
28 /*
29 ** This routine takes a user-entered UUID which might be in mixed
30 ** case and might only be a prefix of the full UUID and converts it
31 ** into the full-length UUID in canonical form.
@@ -41,228 +251,23 @@
41 **
42 ** Return 0 on success. Return 1 if the name cannot be resolved.
43 ** Return 2 name is ambiguous.
44 */
45 int name_to_uuid(Blob *pName, int iErrPriority, const char *zType){
46 int rc;
47 int sz;
48 sz = blob_size(pName);
49 if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){
50 char *zUuid;
51 const char *zName = blob_str(pName);
52 if( memcmp(zName, "tag:", 4)==0 ){
53 zName += 4;
54 zUuid = tag_to_uuid(zName, zType);
55 }else{
56 zUuid = tag_to_uuid(zName, zType);
57 if( zUuid==0 ){
58 zUuid = date_to_uuid(zName, zType);
59 }
60 }
61 if( zUuid ){
62 blob_reset(pName);
63 blob_append(pName, zUuid, -1);
64 free(zUuid);
65 return 0;
66 }
67 fossil_error(iErrPriority, "not a valid object name: %s", zName);
68 return 1;
69 }
70 blob_materialize(pName);
71 canonical16(blob_buffer(pName), sz);
72 if( sz==UUID_SIZE ){
73 rc = db_int(1, "SELECT 0 FROM blob WHERE uuid=%B", pName);
74 if( rc ){
75 fossil_error(iErrPriority, "no such artifact: %b", pName);
76 blob_reset(pName);
77 }
78 }else if( sz<UUID_SIZE && sz>=4 ){
79 Stmt q;
80 db_prepare(&q, "SELECT uuid FROM blob WHERE uuid GLOB '%b*'", pName);
81 if( db_step(&q)!=SQLITE_ROW ){
82 char *zUuid;
83 db_finalize(&q);
84 zUuid = tag_to_uuid(blob_str(pName), "*");
85 if( zUuid ){
86 blob_reset(pName);
87 blob_append(pName, zUuid, -1);
88 free(zUuid);
89 return 0;
90 }
91 fossil_error(iErrPriority, "no artifacts match the prefix \"%b\"", pName);
92 return 1;
93 }
94 blob_reset(pName);
95 blob_append(pName, db_column_text(&q, 0), db_column_bytes(&q, 0));
96 if( db_step(&q)==SQLITE_ROW ){
97 fossil_error(iErrPriority,
98 "multiple artifacts match"
99 );
100 blob_reset(pName);
101 db_finalize(&q);
102 return 2;
103 }
104 db_finalize(&q);
105 rc = 0;
106 }else{
107 rc = 0;
108 }
109 return rc;
110 }
111
112 /*
113 ** Return TRUE if the string begins with an ISO8601 date: YYYY-MM-DD.
114 */
115 static int is_date(const char *z){
116 if( !fossil_isdigit(z[0]) ) return 0;
117 if( !fossil_isdigit(z[1]) ) return 0;
118 if( !fossil_isdigit(z[2]) ) return 0;
119 if( !fossil_isdigit(z[3]) ) return 0;
120 if( z[4]!='-') return 0;
121 if( !fossil_isdigit(z[5]) ) return 0;
122 if( !fossil_isdigit(z[6]) ) return 0;
123 if( z[7]!='-') return 0;
124 if( !fossil_isdigit(z[8]) ) return 0;
125 if( !fossil_isdigit(z[9]) ) return 0;
126 return 1;
127 }
128
129 /*
130 ** Convert a symbolic tag name into the UUID of a check-in that contains
131 ** that tag. If the tag appears on multiple check-ins, return the UUID
132 ** of the most recent check-in with the tag.
133 **
134 ** If the input string is of the form:
135 **
136 ** tag:date
137 **
138 ** Then return the UUID of the oldest check-in with that tag that is
139 ** not older than 'date'.
140 **
141 ** An input of "tip" returns the most recent check-in.
142 **
143 ** Memory to hold the returned string comes from malloc() and needs to
144 ** be freed by the caller.
145 */
146 char *tag_to_uuid(const char *zTag, const char *zType){
147 int vid;
148 char *zUuid;
149
150 if( zType==0 || zType[0]==0 ) zType = "*";
151 zUuid = db_text(0,
152 "SELECT blob.uuid"
153 " FROM tag, tagxref, event, blob"
154 " WHERE tag.tagname='sym-%q' "
155 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
156 " AND event.objid=tagxref.rid "
157 " AND blob.rid=event.objid "
158 " AND event.type GLOB '%q'"
159 " ORDER BY event.mtime DESC /*sort*/",
160 zTag, zType
161 );
162 if( zUuid==0 ){
163 int nTag = strlen(zTag);
164 int i;
165 for(i=0; i<nTag-10; i++){
166 if( zTag[i]==':' && is_date(&zTag[i+1]) ){
167 char *zDate = mprintf("%s", &zTag[i+1]);
168 char *zTagBase = mprintf("%.*s", i, zTag);
169 int nDate = strlen(zDate);
170 int useUtc = 0;
171 if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
172 nDate -= 3;
173 zDate[nDate] = 0;
174 useUtc = 1;
175 }
176 zUuid = db_text(0,
177 "SELECT blob.uuid"
178 " FROM tag, tagxref, event, blob"
179 " WHERE tag.tagname='sym-%q' "
180 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
181 " AND event.objid=tagxref.rid "
182 " AND blob.rid=event.objid "
183 " AND event.mtime<=julianday(%Q %s)"
184 " AND event.type GLOB '%q'"
185 " ORDER BY event.mtime DESC /*sort*/ ",
186 zTagBase, zDate, (useUtc ? "" : ",'utc'"), zType
187 );
188 break;
189 }
190 }
191 if( zUuid==0 && fossil_strcmp(zTag, "tip")==0 ){
192 zUuid = db_text(0,
193 "SELECT blob.uuid"
194 " FROM event, blob"
195 " WHERE event.type='ci'"
196 " AND blob.rid=event.objid"
197 " ORDER BY event.mtime DESC"
198 );
199 }
200 if( zUuid==0 && g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
201 if( fossil_strcmp(zTag, "current")==0 ){
202 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
203 }else if( fossil_strcmp(zTag, "prev")==0
204 || fossil_strcmp(zTag, "previous")==0 ){
205 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid="
206 "(SELECT pid FROM plink WHERE cid=%d AND isprim)",
207 vid);
208 }else if( fossil_strcmp(zTag, "next")==0 ){
209 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid="
210 "(SELECT cid FROM plink WHERE pid=%d"
211 " ORDER BY isprim DESC, mtime DESC)",
212 vid);
213 }
214 }
215 }
216 return zUuid;
217 }
218
219 /*
220 ** Convert a date/time string into a UUID.
221 **
222 ** Input forms accepted:
223 **
224 ** date:DATE
225 ** local:DATE
226 ** utc:DATE
227 **
228 ** The DATE is interpreted as localtime unless the "utc:" prefix is used
229 ** or a "utc" string appears at the end of the DATE string.
230 */
231 char *date_to_uuid(const char *zDate, const char *zType){
232 int useUtc = 0;
233 int n;
234 char *zCopy = 0;
235 char *zUuid;
236
237 if( memcmp(zDate, "date:", 5)==0 ){
238 zDate += 5;
239 }else if( memcmp(zDate, "local:", 6)==0 ){
240 zDate += 6;
241 }else if( memcmp(zDate, "utc:", 4)==0 ){
242 zDate += 4;
243 useUtc = 1;
244 }
245 n = strlen(zDate);
246 if( n<10 || !is_date(zDate) ) return 0;
247 if( n>4 && sqlite3_strnicmp(&zDate[n-3], "utc", 3)==0 ){
248 zCopy = mprintf("%s", zDate);
249 zCopy[n-3] = 0;
250 zDate = zCopy;
251 n -= 3;
252 useUtc = 1;
253 }
254 if( zType==0 || zType[0]==0 ) zType = "*";
255 zUuid = db_text(0,
256 "SELECT (SELECT uuid FROM blob WHERE rid=event.objid)"
257 " FROM event"
258 " WHERE mtime<=julianday(%Q %s) AND type GLOB '%q'"
259 " ORDER BY mtime DESC LIMIT 1",
260 zDate, useUtc ? "" : ",'utc'", zType
261 );
262 free(zCopy);
263 return zUuid;
264 }
265
266 /*
267 ** COMMAND: test-name-to-id
268 **
@@ -284,41 +289,38 @@
284 blob_reset(&name);
285 }
286 }
287
288 /*
289 ** Convert a name to a rid. If the name is a small integer value then
290 ** just use atoi() to do the conversion. If the name contains alphabetic
291 ** characters or is not an existing rid, then use name_to_uuid then
292 ** convert the uuid to a rid.
 
 
 
 
 
 
293 **
294 ** This routine is used by command-line routines to resolve command-line inputs
295 ** into a rid.
296 */
297 int name_to_typed_rid(const char *zName, const char *zType){
298 int i;
299 int rid;
300 Blob name;
301
302 if( zName==0 || zName[0]==0 ) return 0;
303 blob_init(&name, zName, -1);
304 if( name_to_uuid(&name, -1, zType) ){
305 blob_reset(&name);
306 for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
307 if( zName[i]==0 ){
308 rid = atoi(zName);
309 if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
310 return rid;
311 }
312 }
313 fossil_error(1, "no such artifact: %s", zName);
314 return 0;
315 }else{
316 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
317 blob_reset(&name);
318 }
319 return rid;
320 }
321 int name_to_rid(const char *zName){
322 return name_to_typed_rid(zName, "*");
323 }
324
@@ -362,32 +364,16 @@
362 ** rid. If the CGI parameter is missing or is not a valid artifact tag,
363 ** return 0. If the CGI parameter is ambiguous, redirect to a page that
364 ** shows all possibilities and do not return.
365 */
366 int name_to_rid_www(const char *zParamName){
367 int i, rc;
368 int rid;
369 const char *zName = P(zParamName);
370 Blob name;
371
372 if( zName==0 || zName[0]==0 ) return 0;
373 blob_init(&name, zName, -1);
374 rc = name_to_uuid(&name, -1, "*");
375 if( rc==1 ){
376 blob_reset(&name);
377 for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
378 if( zName[i]==0 ){
379 rid = atoi(zName);
380 if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
381 return rid;
382 }
383 }
384 return 0;
385 }else if( rc==2 ){
386 cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
387 return 0;
388 }else{
389 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
390 blob_reset(&name);
391 }
392 return rid;
393 }
394
--- src/name.c
+++ src/name.c
@@ -22,10 +22,220 @@
22 ** not necessarily in canonical form.
23 */
24 #include "config.h"
25 #include "name.h"
26 #include <assert.h>
27
28 /*
29 ** Return TRUE if the string begins with something that looks roughly
30 ** like an ISO date/time string. The SQLite date/time functions will
31 ** have the final say-so about whether or not the date/time string is
32 ** well-formed.
33 */
34 static int is_date(const char *z){
35 if( !fossil_isdigit(z[0]) ) return 0;
36 if( !fossil_isdigit(z[1]) ) return 0;
37 if( !fossil_isdigit(z[2]) ) return 0;
38 if( !fossil_isdigit(z[3]) ) return 0;
39 if( z[4]!='-') return 0;
40 if( !fossil_isdigit(z[5]) ) return 0;
41 if( !fossil_isdigit(z[6]) ) return 0;
42 if( z[7]!='-') return 0;
43 if( !fossil_isdigit(z[8]) ) return 0;
44 if( !fossil_isdigit(z[9]) ) return 0;
45 return 1;
46 }
47
48 /*
49 ** Convert a symbolic name into a RID. Acceptable forms:
50 **
51 ** * SHA1 hash
52 ** * SHA1 hash prefix of at least 4 characters
53 ** * Symbolic Name
54 ** * "tag:" + symbolic name
55 ** * Date or date-time
56 ** * "date:" + Date or date-time
57 ** * symbolic-name ":" date-time
58 ** * "tip"
59 **
60 ** The following additional forms are available in local checkouts:
61 **
62 ** * "current"
63 ** * "prev" or "previous"
64 ** * "next"
65 **
66 ** Return the RID of the matching artifact. Or return 0 if the name does not
67 ** match any known object. Or return -1 if the name is ambiguious.
68 **
69 ** The zType parameter specifies the type of artifact: ci, t, w, e, g.
70 ** If zType is NULL or "" or "*" then any type of artifact will serve.
71 ** zType is "ci" in most use cases since we are usually searching for
72 ** a check-in.
73 */
74 static int symbolic_name_to_rid(const char *zTag, const char *zType){
75 int vid;
76 int rid = 0;
77 int nTag;
78 int i;
79
80 if( zType==0 || zType[0]==0 ) zType = "*";
81 if( zTag==0 || zTag[0]==0 ) return 0;
82
83 /* special keyword: "tip" */
84 if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){
85 rid = db_int(0,
86 "SELECT objid"
87 " FROM event"
88 " WHERE type='ci'"
89 " ORDER BY event.mtime DESC"
90 );
91 if( rid ) return rid;
92 }
93
94 /* special keywords: "prev", "previous", "current", and "next" */
95 if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
96 if( fossil_strcmp(zTag, "current")==0 ){
97 rid = vid;
98 }else if( fossil_strcmp(zTag, "prev")==0
99 || fossil_strcmp(zTag, "previous")==0 ){
100 rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid);
101 }else if( fossil_strcmp(zTag, "next")==0 ){
102 rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
103 " ORDER BY isprim DESC, mtime DESC", vid);
104 }
105 if( rid ) return rid;
106 }
107
108 /* Date and times */
109 if( memcmp(zTag, "date:", 5)==0 ){
110 rid = db_int(0,
111 "SELECT objid FROM event"
112 " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
113 " ORDER BY mtime DESC LIMIT 1",
114 &zTag[5], zType);
115 return rid;
116 }
117 if( is_date(zTag) ){
118 rid = db_int(0,
119 "SELECT objid FROM event"
120 " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
121 " ORDER BY mtime DESC LIMIT 1",
122 zTag, zType);
123 if( rid) return rid;
124 }
125
126 /* Deprecated date & time formats: "local:" + date-time and
127 ** "utc:" + date-time */
128 if( memcmp(zTag, "local:", 6)==0 ){
129 rid = db_int(0,
130 "SELECT objid FROM event"
131 " WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
132 " ORDER BY mtime DESC LIMIT 1",
133 &zTag[6], zType);
134 return rid;
135 }
136 if( memcmp(zTag, "utc:", 4)==0 ){
137 rid = db_int(0,
138 "SELECT objid FROM event"
139 " WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
140 " ORDER BY mtime DESC LIMIT 1",
141 &zTag[4], zType);
142 return rid;
143 }
144
145 /* "tag:" + symbolic-name */
146 if( memcmp(zTag, "tag:", 4)==0 ){
147 rid = db_int(0,
148 "SELECT event.objid"
149 " FROM tag, tagxref, event"
150 " WHERE tag.tagname='sym-%q' "
151 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
152 " AND event.objid=tagxref.rid "
153 " AND event.type GLOB '%q'"
154 " ORDER BY event.mtime DESC /*sort*/",
155 &zTag[4], zType
156 );
157 return rid;
158 }
159
160 /* symbolic-name ":" date-time */
161 nTag = strlen(zTag);
162 for(i=0; i<nTag-10 && zTag[i]!=':'; i++){}
163 if( zTag[i]==':' && is_date(&zTag[i+1]) ){
164 char *zDate = mprintf("%s", &zTag[i+1]);
165 char *zTagBase = mprintf("%.*s", i, zTag);
166 int nDate = strlen(zDate);
167 if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
168 zDate[nDate-3] = 'z';
169 zDate[nDate-2] = 0;
170 }
171 rid = db_int(0,
172 "SELECT event.objid"
173 " FROM tag, tagxref, event"
174 " WHERE tag.tagname='sym-%q' "
175 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
176 " AND event.objid=tagxref.rid "
177 " AND event.mtime<=julianday(%Q)"
178 " AND event.type GLOB '%q'"
179 " ORDER BY event.mtime DESC /*sort*/ ",
180 zTagBase, zDate, zType
181 );
182 return rid;
183 }
184
185 /* SHA1 hash or prefix */
186 if( nTag>=4 && nTag<=UUID_SIZE && validate16(zTag, nTag) ){
187 Stmt q;
188 char zUuid[UUID_SIZE+1];
189 memcpy(zUuid, zTag, nTag+1);
190 canonical16(zUuid, nTag);
191 rid = 0;
192 if( zType[0]=='*' ){
193 db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%s*'", zUuid);
194 }else{
195 db_prepare(&q,
196 "SELECT blob.rid"
197 " FROM blob, event"
198 " WHERE blob.uuid GLOB '%s*'"
199 " AND event.objid=blob.rid"
200 " AND event.type GLOB '%q'",
201 zUuid, zType
202 );
203 }
204 if( db_step(&q)==SQLITE_ROW ){
205 rid = db_column_int(&q, 0);
206 if( db_step(&q)==SQLITE_ROW ) rid = -1;
207 }
208 db_finalize(&q);
209 if( rid ) return rid;
210 }
211
212 /* Symbolic name */
213 rid = db_int(0,
214 "SELECT event.objid"
215 " FROM tag, tagxref, event"
216 " WHERE tag.tagname='sym-%q' "
217 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
218 " AND event.objid=tagxref.rid "
219 " AND event.type GLOB '%q'"
220 " ORDER BY event.mtime DESC /*sort*/ ",
221 zTag, zType
222 );
223 if( rid>0 ) return rid;
224
225 /* Undocumented: numeric tags get translated directly into the RID */
226 for(i=0; fossil_isdigit(zTag[i]); i++){}
227 if( zTag[i]==0 ){
228 rid = db_int(0,
229 "SELECT event.objid"
230 " FROM event"
231 " WHERE event.objid=%s"
232 " AND event.type GLOB '%q'", zTag, zType);
233 }
234 return rid;
235 }
236
237
238 /*
239 ** This routine takes a user-entered UUID which might be in mixed
240 ** case and might only be a prefix of the full UUID and converts it
241 ** into the full-length UUID in canonical form.
@@ -41,228 +251,23 @@
251 **
252 ** Return 0 on success. Return 1 if the name cannot be resolved.
253 ** Return 2 name is ambiguous.
254 */
255 int name_to_uuid(Blob *pName, int iErrPriority, const char *zType){
256 char *zName = blob_str(pName);
257 int rid = symbolic_name_to_rid(zName, zType);
258 if( rid<0 ){
259 fossil_error(iErrPriority, "ambiguous name: %s", zName);
260 return 2;
261 }else if( rid==0 ){
262 fossil_error(iErrPriority, "not found: %s", zName);
263 return 1;
264 }else{
265 blob_reset(pName);
266 db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid);
267 return 0;
268 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269 }
270
271 /*
272 ** COMMAND: test-name-to-id
273 **
@@ -284,41 +289,38 @@
289 blob_reset(&name);
290 }
291 }
292
293 /*
294 ** Convert a name to a rid. If the name can be any of the various forms
295 ** accepted:
296 **
297 ** * SHA1 hash or prefix thereof
298 ** * symbolic name
299 ** * date
300 ** * label:date
301 ** * prev, previous
302 ** * next
303 ** * tip
304 **
305 ** This routine is used by command-line routines to resolve command-line inputs
306 ** into a rid.
307 */
308 int name_to_typed_rid(const char *zName, const char *zType){
 
309 int rid;
 
310
311 if( zName==0 || zName[0]==0 ) return 0;
312 rid = symbolic_name_to_rid(zName, zType);
313 if( rid<0 ){
314 fossil_error(1, "ambiguous name: %s", zName);
315 return 0;
316 }else if( rid==0 ){
317 fossil_error(1, "not found: %s", zName);
 
 
 
 
 
318 return 0;
319 }else{
320 return rid;
 
321 }
 
322 }
323 int name_to_rid(const char *zName){
324 return name_to_typed_rid(zName, "*");
325 }
326
@@ -362,32 +364,16 @@
364 ** rid. If the CGI parameter is missing or is not a valid artifact tag,
365 ** return 0. If the CGI parameter is ambiguous, redirect to a page that
366 ** shows all possibilities and do not return.
367 */
368 int name_to_rid_www(const char *zParamName){
 
369 int rid;
370 const char *zName = P(zParamName);
 
371
372 if( zName==0 || zName[0]==0 ) return 0;
373 rid = symbolic_name_to_rid(zName, "*");
374 if( rid<0 ){
 
 
 
 
 
 
 
 
 
 
 
375 cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
376 rid = 0;
 
 
 
377 }
378 return rid;
379 }
380

Keyboard Shortcuts

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