Fossil SCM

merged in trunk [272e304d3f].

stephan 2011-11-04 17:24 json-multitag-test merge
Commit 34359c3ad1324acc56df349be331e221640d1da3
+2 -2
--- src/add.c
+++ src/add.c
@@ -260,11 +260,11 @@
260260
db_end_transaction(0);
261261
}
262262
263263
/*
264264
** COMMAND: rm
265
-** COMMAND: delete
265
+** COMMAND: delete*
266266
**
267267
** Usage: %fossil rm FILE1 ?FILE2 ...?
268268
** or: %fossil delete FILE1 ?FILE2 ...?
269269
**
270270
** Remove one or more files or directories from the repository.
@@ -473,11 +473,11 @@
473473
);
474474
}
475475
476476
/*
477477
** COMMAND: mv
478
-** COMMAND: rename
478
+** COMMAND: rename*
479479
**
480480
** Usage: %fossil mv|rename OLDNAME NEWNAME
481481
** or: %fossil mv|rename OLDNAME... DIR
482482
**
483483
** Move or rename one or more files or directories within the repository tree.
484484
--- src/add.c
+++ src/add.c
@@ -260,11 +260,11 @@
260 db_end_transaction(0);
261 }
262
263 /*
264 ** COMMAND: rm
265 ** COMMAND: delete
266 **
267 ** Usage: %fossil rm FILE1 ?FILE2 ...?
268 ** or: %fossil delete FILE1 ?FILE2 ...?
269 **
270 ** Remove one or more files or directories from the repository.
@@ -473,11 +473,11 @@
473 );
474 }
475
476 /*
477 ** COMMAND: mv
478 ** COMMAND: rename
479 **
480 ** Usage: %fossil mv|rename OLDNAME NEWNAME
481 ** or: %fossil mv|rename OLDNAME... DIR
482 **
483 ** Move or rename one or more files or directories within the repository tree.
484
--- src/add.c
+++ src/add.c
@@ -260,11 +260,11 @@
260 db_end_transaction(0);
261 }
262
263 /*
264 ** COMMAND: rm
265 ** COMMAND: delete*
266 **
267 ** Usage: %fossil rm FILE1 ?FILE2 ...?
268 ** or: %fossil delete FILE1 ?FILE2 ...?
269 **
270 ** Remove one or more files or directories from the repository.
@@ -473,11 +473,11 @@
473 );
474 }
475
476 /*
477 ** COMMAND: mv
478 ** COMMAND: rename*
479 **
480 ** Usage: %fossil mv|rename OLDNAME NEWNAME
481 ** or: %fossil mv|rename OLDNAME... DIR
482 **
483 ** Move or rename one or more files or directories within the repository tree.
484
+14 -2
--- src/blob.c
+++ src/blob.c
@@ -766,12 +766,24 @@
766766
int blob_write_to_file(Blob *pBlob, const char *zFilename){
767767
FILE *out;
768768
int wrote;
769769
770770
if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
771
- fossil_puts(blob_str(pBlob), 0);
772
- return blob_size(pBlob);
771
+ int n;
772
+#if defined(_WIN32)
773
+ if( _isatty(fileno(stdout)) ){
774
+ char *z;
775
+ z = fossil_utf8_to_console(blob_str(pBlob));
776
+ n = strlen(z);
777
+ fwrite(z, 1, n, stdout);
778
+ free(z);
779
+ return n;
780
+ }
781
+#endif
782
+ n = blob_size(pBlob);
783
+ fwrite(blob_buffer(pBlob), 1, n, stdout);
784
+ return n;
773785
}else{
774786
int i, nName;
775787
char *zName, zBuf[1000];
776788
777789
nName = strlen(zFilename);
778790
--- src/blob.c
+++ src/blob.c
@@ -766,12 +766,24 @@
766 int blob_write_to_file(Blob *pBlob, const char *zFilename){
767 FILE *out;
768 int wrote;
769
770 if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
771 fossil_puts(blob_str(pBlob), 0);
772 return blob_size(pBlob);
 
 
 
 
 
 
 
 
 
 
 
 
773 }else{
774 int i, nName;
775 char *zName, zBuf[1000];
776
777 nName = strlen(zFilename);
778
--- src/blob.c
+++ src/blob.c
@@ -766,12 +766,24 @@
766 int blob_write_to_file(Blob *pBlob, const char *zFilename){
767 FILE *out;
768 int wrote;
769
770 if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
771 int n;
772 #if defined(_WIN32)
773 if( _isatty(fileno(stdout)) ){
774 char *z;
775 z = fossil_utf8_to_console(blob_str(pBlob));
776 n = strlen(z);
777 fwrite(z, 1, n, stdout);
778 free(z);
779 return n;
780 }
781 #endif
782 n = blob_size(pBlob);
783 fwrite(blob_buffer(pBlob), 1, n, stdout);
784 return n;
785 }else{
786 int i, nName;
787 char *zName, zBuf[1000];
788
789 nName = strlen(zFilename);
790
+14 -2
--- src/blob.c
+++ src/blob.c
@@ -766,12 +766,24 @@
766766
int blob_write_to_file(Blob *pBlob, const char *zFilename){
767767
FILE *out;
768768
int wrote;
769769
770770
if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
771
- fossil_puts(blob_str(pBlob), 0);
772
- return blob_size(pBlob);
771
+ int n;
772
+#if defined(_WIN32)
773
+ if( _isatty(fileno(stdout)) ){
774
+ char *z;
775
+ z = fossil_utf8_to_console(blob_str(pBlob));
776
+ n = strlen(z);
777
+ fwrite(z, 1, n, stdout);
778
+ free(z);
779
+ return n;
780
+ }
781
+#endif
782
+ n = blob_size(pBlob);
783
+ fwrite(blob_buffer(pBlob), 1, n, stdout);
784
+ return n;
773785
}else{
774786
int i, nName;
775787
char *zName, zBuf[1000];
776788
777789
nName = strlen(zFilename);
778790
--- src/blob.c
+++ src/blob.c
@@ -766,12 +766,24 @@
766 int blob_write_to_file(Blob *pBlob, const char *zFilename){
767 FILE *out;
768 int wrote;
769
770 if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
771 fossil_puts(blob_str(pBlob), 0);
772 return blob_size(pBlob);
 
 
 
 
 
 
 
 
 
 
 
 
773 }else{
774 int i, nName;
775 char *zName, zBuf[1000];
776
777 nName = strlen(zFilename);
778
--- src/blob.c
+++ src/blob.c
@@ -766,12 +766,24 @@
766 int blob_write_to_file(Blob *pBlob, const char *zFilename){
767 FILE *out;
768 int wrote;
769
770 if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
771 int n;
772 #if defined(_WIN32)
773 if( _isatty(fileno(stdout)) ){
774 char *z;
775 z = fossil_utf8_to_console(blob_str(pBlob));
776 n = strlen(z);
777 fwrite(z, 1, n, stdout);
778 free(z);
779 return n;
780 }
781 #endif
782 n = blob_size(pBlob);
783 fwrite(blob_buffer(pBlob), 1, n, stdout);
784 return n;
785 }else{
786 int i, nName;
787 char *zName, zBuf[1000];
788
789 nName = strlen(zFilename);
790
--- src/browse.c
+++ src/browse.c
@@ -249,10 +249,11 @@
249249
/* Generate a multi-column table listing the contents of zD[]
250250
** directory.
251251
*/
252252
mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/");
253253
cnt = db_int(0, "SELECT count(*) FROM localfiles /*scan*/");
254
+ if( mxLen<12 ) mxLen = 12;
254255
nCol = 100/mxLen;
255256
if( nCol<1 ) nCol = 1;
256257
if( nCol>5 ) nCol = 5;
257258
nRow = (cnt+nCol-1)/nCol;
258259
db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/");
259260
--- src/browse.c
+++ src/browse.c
@@ -249,10 +249,11 @@
249 /* Generate a multi-column table listing the contents of zD[]
250 ** directory.
251 */
252 mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/");
253 cnt = db_int(0, "SELECT count(*) FROM localfiles /*scan*/");
 
254 nCol = 100/mxLen;
255 if( nCol<1 ) nCol = 1;
256 if( nCol>5 ) nCol = 5;
257 nRow = (cnt+nCol-1)/nCol;
258 db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/");
259
--- src/browse.c
+++ src/browse.c
@@ -249,10 +249,11 @@
249 /* Generate a multi-column table listing the contents of zD[]
250 ** directory.
251 */
252 mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/");
253 cnt = db_int(0, "SELECT count(*) FROM localfiles /*scan*/");
254 if( mxLen<12 ) mxLen = 12;
255 nCol = 100/mxLen;
256 if( nCol<1 ) nCol = 1;
257 if( nCol>5 ) nCol = 5;
258 nRow = (cnt+nCol-1)/nCol;
259 db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/");
260
+2 -2
--- src/checkin.c
+++ src/checkin.c
@@ -182,15 +182,15 @@
182182
int vid;
183183
db_must_be_within_tree();
184184
/* 012345678901234 */
185185
fossil_print("repository: %s\n", db_lget("repository",""));
186186
fossil_print("local-root: %s\n", g.zLocalRoot);
187
- fossil_print("server-code: %s\n", db_get("server-code", ""));
188187
vid = db_lget_int("checkout", 0);
189188
if( vid ){
190189
show_common_info(vid, "checkout:", 1, 1);
191190
}
191
+ db_record_repository_filename(0);
192192
changes_cmd();
193193
}
194194
195195
/*
196196
** COMMAND: ls
@@ -825,11 +825,11 @@
825825
blob_reset(&fname);
826826
}
827827
}
828828
829829
/*
830
-** COMMAND: ci
830
+** COMMAND: ci*
831831
** COMMAND: commit
832832
**
833833
** Usage: %fossil commit ?OPTIONS? ?FILE...?
834834
**
835835
** Create a new version containing all of the changes in the current
836836
--- src/checkin.c
+++ src/checkin.c
@@ -182,15 +182,15 @@
182 int vid;
183 db_must_be_within_tree();
184 /* 012345678901234 */
185 fossil_print("repository: %s\n", db_lget("repository",""));
186 fossil_print("local-root: %s\n", g.zLocalRoot);
187 fossil_print("server-code: %s\n", db_get("server-code", ""));
188 vid = db_lget_int("checkout", 0);
189 if( vid ){
190 show_common_info(vid, "checkout:", 1, 1);
191 }
 
192 changes_cmd();
193 }
194
195 /*
196 ** COMMAND: ls
@@ -825,11 +825,11 @@
825 blob_reset(&fname);
826 }
827 }
828
829 /*
830 ** COMMAND: ci
831 ** COMMAND: commit
832 **
833 ** Usage: %fossil commit ?OPTIONS? ?FILE...?
834 **
835 ** Create a new version containing all of the changes in the current
836
--- src/checkin.c
+++ src/checkin.c
@@ -182,15 +182,15 @@
182 int vid;
183 db_must_be_within_tree();
184 /* 012345678901234 */
185 fossil_print("repository: %s\n", db_lget("repository",""));
186 fossil_print("local-root: %s\n", g.zLocalRoot);
 
187 vid = db_lget_int("checkout", 0);
188 if( vid ){
189 show_common_info(vid, "checkout:", 1, 1);
190 }
191 db_record_repository_filename(0);
192 changes_cmd();
193 }
194
195 /*
196 ** COMMAND: ls
@@ -825,11 +825,11 @@
825 blob_reset(&fname);
826 }
827 }
828
829 /*
830 ** COMMAND: ci*
831 ** COMMAND: commit
832 **
833 ** Usage: %fossil commit ?OPTIONS? ?FILE...?
834 **
835 ** Create a new version containing all of the changes in the current
836
+3 -3
--- src/checkout.c
+++ src/checkout.c
@@ -161,12 +161,12 @@
161161
}
162162
163163
}
164164
165165
/*
166
-** COMMAND: checkout
167
-** COMMAND: co
166
+** COMMAND: checkout*
167
+** COMMAND: co*
168168
**
169169
** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS?
170170
** or: %fossil co ?VERSION | --latest? ?OPTIONS?
171171
**
172172
** Check out a version specified on the command-line. This command
@@ -272,11 +272,11 @@
272272
}
273273
}
274274
}
275275
276276
/*
277
-** COMMAND: close
277
+** COMMAND: close*
278278
**
279279
** Usage: %fossil close ?OPTIONS?
280280
**
281281
** The opposite of "open". Close the current database connection.
282282
** Require a -f or --force flag if there are unsaved changed in the
283283
--- src/checkout.c
+++ src/checkout.c
@@ -161,12 +161,12 @@
161 }
162
163 }
164
165 /*
166 ** COMMAND: checkout
167 ** COMMAND: co
168 **
169 ** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS?
170 ** or: %fossil co ?VERSION | --latest? ?OPTIONS?
171 **
172 ** Check out a version specified on the command-line. This command
@@ -272,11 +272,11 @@
272 }
273 }
274 }
275
276 /*
277 ** COMMAND: close
278 **
279 ** Usage: %fossil close ?OPTIONS?
280 **
281 ** The opposite of "open". Close the current database connection.
282 ** Require a -f or --force flag if there are unsaved changed in the
283
--- src/checkout.c
+++ src/checkout.c
@@ -161,12 +161,12 @@
161 }
162
163 }
164
165 /*
166 ** COMMAND: checkout*
167 ** COMMAND: co*
168 **
169 ** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS?
170 ** or: %fossil co ?VERSION | --latest? ?OPTIONS?
171 **
172 ** Check out a version specified on the command-line. This command
@@ -272,11 +272,11 @@
272 }
273 }
274 }
275
276 /*
277 ** COMMAND: close*
278 **
279 ** Usage: %fossil close ?OPTIONS?
280 **
281 ** The opposite of "open". Close the current database connection.
282 ** Require a -f or --force flag if there are unsaved changed in the
283
+1 -1
--- src/configure.c
+++ src/configure.c
@@ -724,11 +724,11 @@
724724
blob_reset(&out);
725725
}
726726
727727
728728
/*
729
-** COMMAND: configuration
729
+** COMMAND: configuration*
730730
**
731731
** Usage: %fossil configuration METHOD ... ?OPTIONS?
732732
**
733733
** Where METHOD is one of: export import merge pull push reset. All methods
734734
** accept the -R or --repository option to specific a repository.
735735
--- src/configure.c
+++ src/configure.c
@@ -724,11 +724,11 @@
724 blob_reset(&out);
725 }
726
727
728 /*
729 ** COMMAND: configuration
730 **
731 ** Usage: %fossil configuration METHOD ... ?OPTIONS?
732 **
733 ** Where METHOD is one of: export import merge pull push reset. All methods
734 ** accept the -R or --repository option to specific a repository.
735
--- src/configure.c
+++ src/configure.c
@@ -724,11 +724,11 @@
724 blob_reset(&out);
725 }
726
727
728 /*
729 ** COMMAND: configuration*
730 **
731 ** Usage: %fossil configuration METHOD ... ?OPTIONS?
732 **
733 ** Where METHOD is one of: export import merge pull push reset. All methods
734 ** accept the -R or --repository option to specific a repository.
735
+1 -1
--- src/content.c
+++ src/content.c
@@ -303,11 +303,11 @@
303303
}
304304
return rc;
305305
}
306306
307307
/*
308
-** COMMAND: artifact
308
+** COMMAND: artifact*
309309
**
310310
** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
311311
**
312312
** Extract an artifact by its SHA1 hash and write the results on
313313
** standard output, or if the optional 4th argument is given, in
314314
--- src/content.c
+++ src/content.c
@@ -303,11 +303,11 @@
303 }
304 return rc;
305 }
306
307 /*
308 ** COMMAND: artifact
309 **
310 ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
311 **
312 ** Extract an artifact by its SHA1 hash and write the results on
313 ** standard output, or if the optional 4th argument is given, in
314
--- src/content.c
+++ src/content.c
@@ -303,11 +303,11 @@
303 }
304 return rc;
305 }
306
307 /*
308 ** COMMAND: artifact*
309 **
310 ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
311 **
312 ** Extract an artifact by its SHA1 hash and write the results on
313 ** standard output, or if the optional 4th argument is given, in
314
+16 -2
--- src/db.c
+++ src/db.c
@@ -1186,11 +1186,11 @@
11861186
manifest_crosslink(rid, &manifest);
11871187
}
11881188
}
11891189
11901190
/*
1191
-** COMMAND: new
1191
+** COMMAND: new*
11921192
** COMMAND: init
11931193
**
11941194
** Usage: %fossil new ?OPTIONS? FILENAME
11951195
** Or: %fossil init ?OPTIONS? FILENAME
11961196
**
@@ -1643,10 +1643,17 @@
16431643
** of the following form:
16441644
**
16451645
** repo:%s
16461646
**
16471647
** The value field is set to 1.
1648
+**
1649
+** If running from a local checkout, also record the root of the checkout
1650
+** as follows:
1651
+**
1652
+** ckout:%s
1653
+**
1654
+** Where %s is the checkout root. The value is the repository file.
16481655
*/
16491656
void db_record_repository_filename(const char *zName){
16501657
Blob full;
16511658
if( zName==0 ){
16521659
if( !g.localOpen ) return;
@@ -1657,10 +1664,17 @@
16571664
db_multi_exec(
16581665
"INSERT OR IGNORE INTO global_config(name,value)"
16591666
"VALUES('repo:%q',1)",
16601667
blob_str(&full)
16611668
);
1669
+ if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){
1670
+ db_multi_exec(
1671
+ "REPLACE INTO global_config(name, value)"
1672
+ "VALUES('ckout:%q','%q');",
1673
+ g.zLocalRoot, blob_str(&full)
1674
+ );
1675
+ }
16621676
db_swap_connections();
16631677
blob_reset(&full);
16641678
}
16651679
16661680
/*
@@ -1821,11 +1835,11 @@
18211835
{ 0,0,0,0,0 }
18221836
};
18231837
18241838
/*
18251839
** COMMAND: settings
1826
-** COMMAND: unset
1840
+** COMMAND: unset*
18271841
**
18281842
** %fossil settings ?PROPERTY? ?VALUE? ?-global?
18291843
** %fossil unset PROPERTY ?-global?
18301844
**
18311845
** The "settings" command with no arguments lists all properties and their
18321846
--- src/db.c
+++ src/db.c
@@ -1186,11 +1186,11 @@
1186 manifest_crosslink(rid, &manifest);
1187 }
1188 }
1189
1190 /*
1191 ** COMMAND: new
1192 ** COMMAND: init
1193 **
1194 ** Usage: %fossil new ?OPTIONS? FILENAME
1195 ** Or: %fossil init ?OPTIONS? FILENAME
1196 **
@@ -1643,10 +1643,17 @@
1643 ** of the following form:
1644 **
1645 ** repo:%s
1646 **
1647 ** The value field is set to 1.
 
 
 
 
 
 
 
1648 */
1649 void db_record_repository_filename(const char *zName){
1650 Blob full;
1651 if( zName==0 ){
1652 if( !g.localOpen ) return;
@@ -1657,10 +1664,17 @@
1657 db_multi_exec(
1658 "INSERT OR IGNORE INTO global_config(name,value)"
1659 "VALUES('repo:%q',1)",
1660 blob_str(&full)
1661 );
 
 
 
 
 
 
 
1662 db_swap_connections();
1663 blob_reset(&full);
1664 }
1665
1666 /*
@@ -1821,11 +1835,11 @@
1821 { 0,0,0,0,0 }
1822 };
1823
1824 /*
1825 ** COMMAND: settings
1826 ** COMMAND: unset
1827 **
1828 ** %fossil settings ?PROPERTY? ?VALUE? ?-global?
1829 ** %fossil unset PROPERTY ?-global?
1830 **
1831 ** The "settings" command with no arguments lists all properties and their
1832
--- src/db.c
+++ src/db.c
@@ -1186,11 +1186,11 @@
1186 manifest_crosslink(rid, &manifest);
1187 }
1188 }
1189
1190 /*
1191 ** COMMAND: new*
1192 ** COMMAND: init
1193 **
1194 ** Usage: %fossil new ?OPTIONS? FILENAME
1195 ** Or: %fossil init ?OPTIONS? FILENAME
1196 **
@@ -1643,10 +1643,17 @@
1643 ** of the following form:
1644 **
1645 ** repo:%s
1646 **
1647 ** The value field is set to 1.
1648 **
1649 ** If running from a local checkout, also record the root of the checkout
1650 ** as follows:
1651 **
1652 ** ckout:%s
1653 **
1654 ** Where %s is the checkout root. The value is the repository file.
1655 */
1656 void db_record_repository_filename(const char *zName){
1657 Blob full;
1658 if( zName==0 ){
1659 if( !g.localOpen ) return;
@@ -1657,10 +1664,17 @@
1664 db_multi_exec(
1665 "INSERT OR IGNORE INTO global_config(name,value)"
1666 "VALUES('repo:%q',1)",
1667 blob_str(&full)
1668 );
1669 if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){
1670 db_multi_exec(
1671 "REPLACE INTO global_config(name, value)"
1672 "VALUES('ckout:%q','%q');",
1673 g.zLocalRoot, blob_str(&full)
1674 );
1675 }
1676 db_swap_connections();
1677 blob_reset(&full);
1678 }
1679
1680 /*
@@ -1821,11 +1835,11 @@
1835 { 0,0,0,0,0 }
1836 };
1837
1838 /*
1839 ** COMMAND: settings
1840 ** COMMAND: unset*
1841 **
1842 ** %fossil settings ?PROPERTY? ?VALUE? ?-global?
1843 ** %fossil unset PROPERTY ?-global?
1844 **
1845 ** The "settings" command with no arguments lists all properties and their
1846
+16 -2
--- src/db.c
+++ src/db.c
@@ -1186,11 +1186,11 @@
11861186
manifest_crosslink(rid, &manifest);
11871187
}
11881188
}
11891189
11901190
/*
1191
-** COMMAND: new
1191
+** COMMAND: new*
11921192
** COMMAND: init
11931193
**
11941194
** Usage: %fossil new ?OPTIONS? FILENAME
11951195
** Or: %fossil init ?OPTIONS? FILENAME
11961196
**
@@ -1643,10 +1643,17 @@
16431643
** of the following form:
16441644
**
16451645
** repo:%s
16461646
**
16471647
** The value field is set to 1.
1648
+**
1649
+** If running from a local checkout, also record the root of the checkout
1650
+** as follows:
1651
+**
1652
+** ckout:%s
1653
+**
1654
+** Where %s is the checkout root. The value is the repository file.
16481655
*/
16491656
void db_record_repository_filename(const char *zName){
16501657
Blob full;
16511658
if( zName==0 ){
16521659
if( !g.localOpen ) return;
@@ -1657,10 +1664,17 @@
16571664
db_multi_exec(
16581665
"INSERT OR IGNORE INTO global_config(name,value)"
16591666
"VALUES('repo:%q',1)",
16601667
blob_str(&full)
16611668
);
1669
+ if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){
1670
+ db_multi_exec(
1671
+ "REPLACE INTO global_config(name, value)"
1672
+ "VALUES('ckout:%q','%q');",
1673
+ g.zLocalRoot, blob_str(&full)
1674
+ );
1675
+ }
16621676
db_swap_connections();
16631677
blob_reset(&full);
16641678
}
16651679
16661680
/*
@@ -1821,11 +1835,11 @@
18211835
{ 0,0,0,0,0 }
18221836
};
18231837
18241838
/*
18251839
** COMMAND: settings
1826
-** COMMAND: unset
1840
+** COMMAND: unset*
18271841
**
18281842
** %fossil settings ?PROPERTY? ?VALUE? ?-global?
18291843
** %fossil unset PROPERTY ?-global?
18301844
**
18311845
** The "settings" command with no arguments lists all properties and their
18321846
--- src/db.c
+++ src/db.c
@@ -1186,11 +1186,11 @@
1186 manifest_crosslink(rid, &manifest);
1187 }
1188 }
1189
1190 /*
1191 ** COMMAND: new
1192 ** COMMAND: init
1193 **
1194 ** Usage: %fossil new ?OPTIONS? FILENAME
1195 ** Or: %fossil init ?OPTIONS? FILENAME
1196 **
@@ -1643,10 +1643,17 @@
1643 ** of the following form:
1644 **
1645 ** repo:%s
1646 **
1647 ** The value field is set to 1.
 
 
 
 
 
 
 
1648 */
1649 void db_record_repository_filename(const char *zName){
1650 Blob full;
1651 if( zName==0 ){
1652 if( !g.localOpen ) return;
@@ -1657,10 +1664,17 @@
1657 db_multi_exec(
1658 "INSERT OR IGNORE INTO global_config(name,value)"
1659 "VALUES('repo:%q',1)",
1660 blob_str(&full)
1661 );
 
 
 
 
 
 
 
1662 db_swap_connections();
1663 blob_reset(&full);
1664 }
1665
1666 /*
@@ -1821,11 +1835,11 @@
1821 { 0,0,0,0,0 }
1822 };
1823
1824 /*
1825 ** COMMAND: settings
1826 ** COMMAND: unset
1827 **
1828 ** %fossil settings ?PROPERTY? ?VALUE? ?-global?
1829 ** %fossil unset PROPERTY ?-global?
1830 **
1831 ** The "settings" command with no arguments lists all properties and their
1832
--- src/db.c
+++ src/db.c
@@ -1186,11 +1186,11 @@
1186 manifest_crosslink(rid, &manifest);
1187 }
1188 }
1189
1190 /*
1191 ** COMMAND: new*
1192 ** COMMAND: init
1193 **
1194 ** Usage: %fossil new ?OPTIONS? FILENAME
1195 ** Or: %fossil init ?OPTIONS? FILENAME
1196 **
@@ -1643,10 +1643,17 @@
1643 ** of the following form:
1644 **
1645 ** repo:%s
1646 **
1647 ** The value field is set to 1.
1648 **
1649 ** If running from a local checkout, also record the root of the checkout
1650 ** as follows:
1651 **
1652 ** ckout:%s
1653 **
1654 ** Where %s is the checkout root. The value is the repository file.
1655 */
1656 void db_record_repository_filename(const char *zName){
1657 Blob full;
1658 if( zName==0 ){
1659 if( !g.localOpen ) return;
@@ -1657,10 +1664,17 @@
1664 db_multi_exec(
1665 "INSERT OR IGNORE INTO global_config(name,value)"
1666 "VALUES('repo:%q',1)",
1667 blob_str(&full)
1668 );
1669 if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){
1670 db_multi_exec(
1671 "REPLACE INTO global_config(name, value)"
1672 "VALUES('ckout:%q','%q');",
1673 g.zLocalRoot, blob_str(&full)
1674 );
1675 }
1676 db_swap_connections();
1677 blob_reset(&full);
1678 }
1679
1680 /*
@@ -1821,11 +1835,11 @@
1835 { 0,0,0,0,0 }
1836 };
1837
1838 /*
1839 ** COMMAND: settings
1840 ** COMMAND: unset*
1841 **
1842 ** %fossil settings ?PROPERTY? ?VALUE? ?-global?
1843 ** %fossil unset PROPERTY ?-global?
1844 **
1845 ** The "settings" command with no arguments lists all properties and their
1846
--- src/descendants.c
+++ src/descendants.c
@@ -263,11 +263,11 @@
263263
db_finalize(&ins);
264264
db_finalize(&q);
265265
}
266266
267267
/*
268
-** COMMAND: descendants
268
+** COMMAND: descendants*
269269
**
270270
** Usage: %fossil descendants ?BASELINE-ID? ?OPTIONS?
271271
**
272272
** Find all leaf descendants of the baseline specified or if the argument
273273
** is omitted, of the baseline currently checked out.
@@ -298,11 +298,11 @@
298298
print_timeline(&q, 20, 0);
299299
db_finalize(&q);
300300
}
301301
302302
/*
303
-** COMMAND: leaves
303
+** COMMAND: leaves*
304304
**
305305
** Usage: %fossil leaves ?OPTIONS?
306306
**
307307
** Find leaves of all branches. By default show only open leaves.
308308
** The --all flag causes all leaves (closed and open) to be shown.
309309
--- src/descendants.c
+++ src/descendants.c
@@ -263,11 +263,11 @@
263 db_finalize(&ins);
264 db_finalize(&q);
265 }
266
267 /*
268 ** COMMAND: descendants
269 **
270 ** Usage: %fossil descendants ?BASELINE-ID? ?OPTIONS?
271 **
272 ** Find all leaf descendants of the baseline specified or if the argument
273 ** is omitted, of the baseline currently checked out.
@@ -298,11 +298,11 @@
298 print_timeline(&q, 20, 0);
299 db_finalize(&q);
300 }
301
302 /*
303 ** COMMAND: leaves
304 **
305 ** Usage: %fossil leaves ?OPTIONS?
306 **
307 ** Find leaves of all branches. By default show only open leaves.
308 ** The --all flag causes all leaves (closed and open) to be shown.
309
--- src/descendants.c
+++ src/descendants.c
@@ -263,11 +263,11 @@
263 db_finalize(&ins);
264 db_finalize(&q);
265 }
266
267 /*
268 ** COMMAND: descendants*
269 **
270 ** Usage: %fossil descendants ?BASELINE-ID? ?OPTIONS?
271 **
272 ** Find all leaf descendants of the baseline specified or if the argument
273 ** is omitted, of the baseline currently checked out.
@@ -298,11 +298,11 @@
298 print_timeline(&q, 20, 0);
299 db_finalize(&q);
300 }
301
302 /*
303 ** COMMAND: leaves*
304 **
305 ** Usage: %fossil leaves ?OPTIONS?
306 **
307 ** Find leaves of all branches. By default show only open leaves.
308 ** The --all flag causes all leaves (closed and open) to be shown.
309
+13 -2
--- src/doc.c
+++ src/doc.c
@@ -367,18 +367,27 @@
367367
login_check_credentials();
368368
if( !g.perm.Read ){ login_needed(); return; }
369369
zName = PD("name", "tip/index.wiki");
370370
for(i=0; zName[i] && zName[i]!='/'; i++){}
371371
if( zName[i]==0 || i>UUID_SIZE ){
372
+ zName = "index.html";
372373
goto doc_not_found;
373374
}
374375
memcpy(zBaseline, zName, i);
375376
zBaseline[i] = 0;
376377
zName += i;
377378
while( zName[0]=='/' ){ zName++; }
378379
if( !file_is_simple_pathname(zName) ){
379
- goto doc_not_found;
380
+ int n = strlen(zName);
381
+ if( n>0 && zName[n-1]=='/' ){
382
+ zName = mprintf("%sindex.html", zName);
383
+ if( !file_is_simple_pathname(zName) ){
384
+ goto doc_not_found;
385
+ }
386
+ }else{
387
+ goto doc_not_found;
388
+ }
380389
}
381390
if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local()==0 ){
382391
sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip");
383392
}
384393
if( fossil_strcmp(zBaseline,"ckout")==0 ){
@@ -408,10 +417,12 @@
408417
" fname TEXT, -- filename\n"
409418
" rid INTEGER, -- artifact ID\n"
410419
" UNIQUE(vid,fname,rid)\n"
411420
")"
412421
);
422
+
423
+
413424
414425
/* Check to see if the documentation file artifact ID is contained
415426
** in the baseline cache */
416427
rid = db_int(0, "SELECT rid FROM vcache"
417428
" WHERE vid=%d AND fname=%Q", vid, zName);
@@ -499,11 +510,11 @@
499510
500511
doc_not_found:
501512
/* Jump here when unable to locate the document */
502513
db_end_transaction(0);
503514
style_header("Document Not Found");
504
- @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
515
+ @ <p>No such document: %h(zName)</p>
505516
style_footer();
506517
return;
507518
}
508519
509520
/*
510521
--- src/doc.c
+++ src/doc.c
@@ -367,18 +367,27 @@
367 login_check_credentials();
368 if( !g.perm.Read ){ login_needed(); return; }
369 zName = PD("name", "tip/index.wiki");
370 for(i=0; zName[i] && zName[i]!='/'; i++){}
371 if( zName[i]==0 || i>UUID_SIZE ){
 
372 goto doc_not_found;
373 }
374 memcpy(zBaseline, zName, i);
375 zBaseline[i] = 0;
376 zName += i;
377 while( zName[0]=='/' ){ zName++; }
378 if( !file_is_simple_pathname(zName) ){
379 goto doc_not_found;
 
 
 
 
 
 
 
 
380 }
381 if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local()==0 ){
382 sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip");
383 }
384 if( fossil_strcmp(zBaseline,"ckout")==0 ){
@@ -408,10 +417,12 @@
408 " fname TEXT, -- filename\n"
409 " rid INTEGER, -- artifact ID\n"
410 " UNIQUE(vid,fname,rid)\n"
411 ")"
412 );
 
 
413
414 /* Check to see if the documentation file artifact ID is contained
415 ** in the baseline cache */
416 rid = db_int(0, "SELECT rid FROM vcache"
417 " WHERE vid=%d AND fname=%Q", vid, zName);
@@ -499,11 +510,11 @@
499
500 doc_not_found:
501 /* Jump here when unable to locate the document */
502 db_end_transaction(0);
503 style_header("Document Not Found");
504 @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
505 style_footer();
506 return;
507 }
508
509 /*
510
--- src/doc.c
+++ src/doc.c
@@ -367,18 +367,27 @@
367 login_check_credentials();
368 if( !g.perm.Read ){ login_needed(); return; }
369 zName = PD("name", "tip/index.wiki");
370 for(i=0; zName[i] && zName[i]!='/'; i++){}
371 if( zName[i]==0 || i>UUID_SIZE ){
372 zName = "index.html";
373 goto doc_not_found;
374 }
375 memcpy(zBaseline, zName, i);
376 zBaseline[i] = 0;
377 zName += i;
378 while( zName[0]=='/' ){ zName++; }
379 if( !file_is_simple_pathname(zName) ){
380 int n = strlen(zName);
381 if( n>0 && zName[n-1]=='/' ){
382 zName = mprintf("%sindex.html", zName);
383 if( !file_is_simple_pathname(zName) ){
384 goto doc_not_found;
385 }
386 }else{
387 goto doc_not_found;
388 }
389 }
390 if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local()==0 ){
391 sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip");
392 }
393 if( fossil_strcmp(zBaseline,"ckout")==0 ){
@@ -408,10 +417,12 @@
417 " fname TEXT, -- filename\n"
418 " rid INTEGER, -- artifact ID\n"
419 " UNIQUE(vid,fname,rid)\n"
420 ")"
421 );
422
423
424
425 /* Check to see if the documentation file artifact ID is contained
426 ** in the baseline cache */
427 rid = db_int(0, "SELECT rid FROM vcache"
428 " WHERE vid=%d AND fname=%Q", vid, zName);
@@ -499,11 +510,11 @@
510
511 doc_not_found:
512 /* Jump here when unable to locate the document */
513 db_end_transaction(0);
514 style_header("Document Not Found");
515 @ <p>No such document: %h(zName)</p>
516 style_footer();
517 return;
518 }
519
520 /*
521
-2
--- src/info.c
+++ src/info.c
@@ -148,11 +148,10 @@
148148
db_open_config(0);
149149
db_record_repository_filename(g.argv[2]);
150150
db_open_repository(g.argv[2]);
151151
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
152152
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
153
- fossil_print("server-code: %s\n", db_get("server-code", "<none>"));
154153
return;
155154
}
156155
db_find_and_open_repository(0,0);
157156
if( g.argc==2 ){
158157
int vid;
@@ -167,11 +166,10 @@
167166
if( g.zHome ){
168167
fossil_print("user-home: %s\n", g.zHome);
169168
}
170169
#endif
171170
fossil_print("project-code: %s\n", db_get("project-code", ""));
172
- fossil_print("server-code: %s\n", db_get("server-code", ""));
173171
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
174172
if( vid ){
175173
show_common_info(vid, "checkout:", 1, 1);
176174
}
177175
}else{
178176
--- src/info.c
+++ src/info.c
@@ -148,11 +148,10 @@
148 db_open_config(0);
149 db_record_repository_filename(g.argv[2]);
150 db_open_repository(g.argv[2]);
151 fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
152 fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
153 fossil_print("server-code: %s\n", db_get("server-code", "<none>"));
154 return;
155 }
156 db_find_and_open_repository(0,0);
157 if( g.argc==2 ){
158 int vid;
@@ -167,11 +166,10 @@
167 if( g.zHome ){
168 fossil_print("user-home: %s\n", g.zHome);
169 }
170 #endif
171 fossil_print("project-code: %s\n", db_get("project-code", ""));
172 fossil_print("server-code: %s\n", db_get("server-code", ""));
173 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
174 if( vid ){
175 show_common_info(vid, "checkout:", 1, 1);
176 }
177 }else{
178
--- src/info.c
+++ src/info.c
@@ -148,11 +148,10 @@
148 db_open_config(0);
149 db_record_repository_filename(g.argv[2]);
150 db_open_repository(g.argv[2]);
151 fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
152 fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
 
153 return;
154 }
155 db_find_and_open_repository(0,0);
156 if( g.argc==2 ){
157 int vid;
@@ -167,11 +166,10 @@
166 if( g.zHome ){
167 fossil_print("user-home: %s\n", g.zHome);
168 }
169 #endif
170 fossil_print("project-code: %s\n", db_get("project-code", ""));
 
171 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
172 if( vid ){
173 show_common_info(vid, "checkout:", 1, 1);
174 }
175 }else{
176
+45 -27
--- src/main.c
+++ src/main.c
@@ -409,14 +409,17 @@
409409
for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
410410
if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
411411
zCmdName = "cgi";
412412
g.isHTTP = 1;
413413
}else if( argc<2 ){
414
- fossil_fatal("Usage: %s COMMAND ...\n"
415
- "\"%s help\" for a list of available commands\n"
416
- "\"%s help COMMAND\" for specific details\n",
417
- argv[0], argv[0], argv[0]);
414
+ fossil_print(
415
+ "Usage: %s COMMAND ...\n"
416
+ " or: %s help -- for a list of common commands\n"
417
+ " or: %s help COMMMAND -- for help with the named command\n"
418
+ " or: %s commands -- for a list of all commands\n",
419
+ argv[0], argv[0], argv[0], argv[0]);
420
+ fossil_exit(1);
418421
}else{
419422
g.isHTTP = 0;
420423
g.fQuiet = find_option("quiet", 0, 0)!=0;
421424
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
422425
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
@@ -453,14 +456,15 @@
453456
for(i=0; i<count(aCommand); i++){
454457
if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){
455458
blob_appendf(&couldbe, " %s", aCommand[i].zName);
456459
}
457460
}
458
- fossil_fatal("%s: ambiguous command prefix: %s\n"
461
+ fossil_print("%s: ambiguous command prefix: %s\n"
459462
"%s: could be any of:%s\n"
460463
"%s: use \"help\" for more information\n",
461464
argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]);
465
+ fossil_exit(1);
462466
}
463467
if(rc){
464468
fossil_fatal("%s: unrecoverable error while initializing JSON CGI bits: "
465469
"cson error code #%d (%s)\n",
466470
argv[0], rc, cson_rc_string(rc));
@@ -810,38 +814,45 @@
810814
}
811815
812816
/*
813817
** List of commands starting with zPrefix, or all commands if zPrefix is NULL.
814818
*/
815
-static void cmd_cmd_list(const char *zPrefix){
819
+static void command_list(const char *zPrefix, int cmdMask){
816820
int i, nCmd;
817821
int nPrefix = zPrefix ? strlen(zPrefix) : 0;
818822
const char *aCmd[count(aCommand)];
819823
for(i=nCmd=0; i<count(aCommand); i++){
820824
const char *z = aCommand[i].zName;
821
- if( memcmp(z,"test",4)==0 ) continue;
825
+ if( (aCommand[i].cmdFlags & cmdMask)==0 ) continue;
822826
if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue;
823827
aCmd[nCmd++] = aCommand[i].zName;
824828
}
825829
multi_column_list(aCmd, nCmd);
826830
}
827831
828832
/*
829
-** COMMAND: test-commands
833
+** COMMAND: commands
830834
**
831
-** Usage: %fossil test-commands
835
+** Usage: %fossil commands ?--test? ?--all? ?--aux?
832836
**
833
-** List all commands used for testing and debugging.
837
+** List available commands. If the --test option is used list only unsupported
838
+** commands intended for testing and debugging. With --all, show all commands
839
+** including test debugging commands. With --aux, show only the auxiliary
840
+** and less often used commands, and/or command aliases.
834841
*/
835
-void cmd_test_cmd_list(void){
836
- int i, nCmd;
837
- const char *aCmd[count(aCommand)];
838
- for(i=nCmd=0; i<count(aCommand); i++){
839
- if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
840
- aCmd[nCmd++] = aCommand[i].zName;
841
- }
842
- multi_column_list(aCmd, nCmd);
842
+void cmd_command_list(void){
843
+ int cmdFlags = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
844
+ if( find_option("all",0,0)!=0 ){
845
+ cmdFlags |= CMDFLAG_TEST;
846
+ }else if( find_option("test",0,0)!=0 ){
847
+ cmdFlags = CMDFLAG_TEST;
848
+ }else if( find_option("aux",0,0)!=0 ){
849
+ cmdFlags = CMDFLAG_2ND_TIER;
850
+ }else{
851
+ fossil_print("Use --test or --all to see test and debug commands.\n");
852
+ }
853
+ command_list(0, cmdFlags);
843854
}
844855
845856
846857
/*
847858
** COMMAND: test-list-webpage
@@ -873,32 +884,39 @@
873884
874885
/*
875886
** COMMAND: help
876887
**
877888
** Usage: %fossil help COMMAND
889
+** or: %fossil COMMAND -help
890
+**
891
+** Display information on how to use COMMAND. To display a list of
892
+** available commands use:
878893
**
879
-** Display information on how to use COMMAND
894
+** %fossil commands
880895
*/
881896
void help_cmd(void){
882897
int rc, idx;
883898
const char *z;
884899
if( g.argc<3 ){
885
- fossil_print("Usage: %s help COMMAND.\nAvailable COMMANDs:\n",
886
- fossil_nameofexe());
887
- cmd_cmd_list(0);
900
+ z = fossil_nameofexe();
901
+ fossil_print(
902
+ "Usage: %s help COMMAND\n"
903
+ "Common COMMANDs: (use \"%s commands\" for a complete list)\n",
904
+ z, z);
905
+ command_list(0, CMDFLAG_1ST_TIER);
888906
version_cmd();
889907
return;
890908
}
891909
rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
892910
if( rc==1 ){
893911
fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
894
- cmd_cmd_list(0);
912
+ command_list(0, 0xff);
895913
fossil_exit(1);
896914
}else if( rc==2 ){
897915
fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
898916
g.argv[2]);
899
- cmd_cmd_list(g.argv[2]);
917
+ command_list(g.argv[2], 0xff);
900918
fossil_exit(1);
901919
}
902920
z = aCmdHelp[idx];
903921
if( z==0 ){
904922
fossil_fatal("no help available for the %s command",
@@ -1285,11 +1303,11 @@
12851303
*/
12861304
cgi_reply();
12871305
}
12881306
12891307
/*
1290
-** COMMAND: cgi
1308
+** COMMAND: cgi*
12911309
**
12921310
** Usage: %fossil ?cgi? SCRIPT
12931311
**
12941312
** The SCRIPT argument is the name of a file that is the CGI script
12951313
** that is being run. The command name, "cgi", may be omitted if
@@ -1472,11 +1490,11 @@
14721490
**
14731491
** fossil http REPOSITORY INFILE OUTFILE IPADDR
14741492
**
14751493
** The argv==6 form is used by the win32 server only.
14761494
**
1477
-** COMMAND: http
1495
+** COMMAND: http*
14781496
**
14791497
** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
14801498
**
14811499
** Handle a single HTTP request appearing on stdin. The resulting webpage
14821500
** is delivered on stdout. This method is used to launch an HTTP request
@@ -1573,11 +1591,11 @@
15731591
}
15741592
#endif
15751593
#endif
15761594
15771595
/*
1578
-** COMMAND: server
1596
+** COMMAND: server*
15791597
** COMMAND: ui
15801598
**
15811599
** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
15821600
** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
15831601
**
15841602
--- src/main.c
+++ src/main.c
@@ -409,14 +409,17 @@
409 for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
410 if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
411 zCmdName = "cgi";
412 g.isHTTP = 1;
413 }else if( argc<2 ){
414 fossil_fatal("Usage: %s COMMAND ...\n"
415 "\"%s help\" for a list of available commands\n"
416 "\"%s help COMMAND\" for specific details\n",
417 argv[0], argv[0], argv[0]);
 
 
 
418 }else{
419 g.isHTTP = 0;
420 g.fQuiet = find_option("quiet", 0, 0)!=0;
421 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
422 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
@@ -453,14 +456,15 @@
453 for(i=0; i<count(aCommand); i++){
454 if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){
455 blob_appendf(&couldbe, " %s", aCommand[i].zName);
456 }
457 }
458 fossil_fatal("%s: ambiguous command prefix: %s\n"
459 "%s: could be any of:%s\n"
460 "%s: use \"help\" for more information\n",
461 argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]);
 
462 }
463 if(rc){
464 fossil_fatal("%s: unrecoverable error while initializing JSON CGI bits: "
465 "cson error code #%d (%s)\n",
466 argv[0], rc, cson_rc_string(rc));
@@ -810,38 +814,45 @@
810 }
811
812 /*
813 ** List of commands starting with zPrefix, or all commands if zPrefix is NULL.
814 */
815 static void cmd_cmd_list(const char *zPrefix){
816 int i, nCmd;
817 int nPrefix = zPrefix ? strlen(zPrefix) : 0;
818 const char *aCmd[count(aCommand)];
819 for(i=nCmd=0; i<count(aCommand); i++){
820 const char *z = aCommand[i].zName;
821 if( memcmp(z,"test",4)==0 ) continue;
822 if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue;
823 aCmd[nCmd++] = aCommand[i].zName;
824 }
825 multi_column_list(aCmd, nCmd);
826 }
827
828 /*
829 ** COMMAND: test-commands
830 **
831 ** Usage: %fossil test-commands
832 **
833 ** List all commands used for testing and debugging.
 
 
 
834 */
835 void cmd_test_cmd_list(void){
836 int i, nCmd;
837 const char *aCmd[count(aCommand)];
838 for(i=nCmd=0; i<count(aCommand); i++){
839 if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
840 aCmd[nCmd++] = aCommand[i].zName;
841 }
842 multi_column_list(aCmd, nCmd);
 
 
 
 
843 }
844
845
846 /*
847 ** COMMAND: test-list-webpage
@@ -873,32 +884,39 @@
873
874 /*
875 ** COMMAND: help
876 **
877 ** Usage: %fossil help COMMAND
 
 
 
 
878 **
879 ** Display information on how to use COMMAND
880 */
881 void help_cmd(void){
882 int rc, idx;
883 const char *z;
884 if( g.argc<3 ){
885 fossil_print("Usage: %s help COMMAND.\nAvailable COMMANDs:\n",
886 fossil_nameofexe());
887 cmd_cmd_list(0);
 
 
 
888 version_cmd();
889 return;
890 }
891 rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
892 if( rc==1 ){
893 fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
894 cmd_cmd_list(0);
895 fossil_exit(1);
896 }else if( rc==2 ){
897 fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
898 g.argv[2]);
899 cmd_cmd_list(g.argv[2]);
900 fossil_exit(1);
901 }
902 z = aCmdHelp[idx];
903 if( z==0 ){
904 fossil_fatal("no help available for the %s command",
@@ -1285,11 +1303,11 @@
1285 */
1286 cgi_reply();
1287 }
1288
1289 /*
1290 ** COMMAND: cgi
1291 **
1292 ** Usage: %fossil ?cgi? SCRIPT
1293 **
1294 ** The SCRIPT argument is the name of a file that is the CGI script
1295 ** that is being run. The command name, "cgi", may be omitted if
@@ -1472,11 +1490,11 @@
1472 **
1473 ** fossil http REPOSITORY INFILE OUTFILE IPADDR
1474 **
1475 ** The argv==6 form is used by the win32 server only.
1476 **
1477 ** COMMAND: http
1478 **
1479 ** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
1480 **
1481 ** Handle a single HTTP request appearing on stdin. The resulting webpage
1482 ** is delivered on stdout. This method is used to launch an HTTP request
@@ -1573,11 +1591,11 @@
1573 }
1574 #endif
1575 #endif
1576
1577 /*
1578 ** COMMAND: server
1579 ** COMMAND: ui
1580 **
1581 ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
1582 ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
1583 **
1584
--- src/main.c
+++ src/main.c
@@ -409,14 +409,17 @@
409 for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
410 if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
411 zCmdName = "cgi";
412 g.isHTTP = 1;
413 }else if( argc<2 ){
414 fossil_print(
415 "Usage: %s COMMAND ...\n"
416 " or: %s help -- for a list of common commands\n"
417 " or: %s help COMMMAND -- for help with the named command\n"
418 " or: %s commands -- for a list of all commands\n",
419 argv[0], argv[0], argv[0], argv[0]);
420 fossil_exit(1);
421 }else{
422 g.isHTTP = 0;
423 g.fQuiet = find_option("quiet", 0, 0)!=0;
424 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
425 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
@@ -453,14 +456,15 @@
456 for(i=0; i<count(aCommand); i++){
457 if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){
458 blob_appendf(&couldbe, " %s", aCommand[i].zName);
459 }
460 }
461 fossil_print("%s: ambiguous command prefix: %s\n"
462 "%s: could be any of:%s\n"
463 "%s: use \"help\" for more information\n",
464 argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]);
465 fossil_exit(1);
466 }
467 if(rc){
468 fossil_fatal("%s: unrecoverable error while initializing JSON CGI bits: "
469 "cson error code #%d (%s)\n",
470 argv[0], rc, cson_rc_string(rc));
@@ -810,38 +814,45 @@
814 }
815
816 /*
817 ** List of commands starting with zPrefix, or all commands if zPrefix is NULL.
818 */
819 static void command_list(const char *zPrefix, int cmdMask){
820 int i, nCmd;
821 int nPrefix = zPrefix ? strlen(zPrefix) : 0;
822 const char *aCmd[count(aCommand)];
823 for(i=nCmd=0; i<count(aCommand); i++){
824 const char *z = aCommand[i].zName;
825 if( (aCommand[i].cmdFlags & cmdMask)==0 ) continue;
826 if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue;
827 aCmd[nCmd++] = aCommand[i].zName;
828 }
829 multi_column_list(aCmd, nCmd);
830 }
831
832 /*
833 ** COMMAND: commands
834 **
835 ** Usage: %fossil commands ?--test? ?--all? ?--aux?
836 **
837 ** List available commands. If the --test option is used list only unsupported
838 ** commands intended for testing and debugging. With --all, show all commands
839 ** including test debugging commands. With --aux, show only the auxiliary
840 ** and less often used commands, and/or command aliases.
841 */
842 void cmd_command_list(void){
843 int cmdFlags = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
844 if( find_option("all",0,0)!=0 ){
845 cmdFlags |= CMDFLAG_TEST;
846 }else if( find_option("test",0,0)!=0 ){
847 cmdFlags = CMDFLAG_TEST;
848 }else if( find_option("aux",0,0)!=0 ){
849 cmdFlags = CMDFLAG_2ND_TIER;
850 }else{
851 fossil_print("Use --test or --all to see test and debug commands.\n");
852 }
853 command_list(0, cmdFlags);
854 }
855
856
857 /*
858 ** COMMAND: test-list-webpage
@@ -873,32 +884,39 @@
884
885 /*
886 ** COMMAND: help
887 **
888 ** Usage: %fossil help COMMAND
889 ** or: %fossil COMMAND -help
890 **
891 ** Display information on how to use COMMAND. To display a list of
892 ** available commands use:
893 **
894 ** %fossil commands
895 */
896 void help_cmd(void){
897 int rc, idx;
898 const char *z;
899 if( g.argc<3 ){
900 z = fossil_nameofexe();
901 fossil_print(
902 "Usage: %s help COMMAND\n"
903 "Common COMMANDs: (use \"%s commands\" for a complete list)\n",
904 z, z);
905 command_list(0, CMDFLAG_1ST_TIER);
906 version_cmd();
907 return;
908 }
909 rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
910 if( rc==1 ){
911 fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
912 command_list(0, 0xff);
913 fossil_exit(1);
914 }else if( rc==2 ){
915 fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
916 g.argv[2]);
917 command_list(g.argv[2], 0xff);
918 fossil_exit(1);
919 }
920 z = aCmdHelp[idx];
921 if( z==0 ){
922 fossil_fatal("no help available for the %s command",
@@ -1285,11 +1303,11 @@
1303 */
1304 cgi_reply();
1305 }
1306
1307 /*
1308 ** COMMAND: cgi*
1309 **
1310 ** Usage: %fossil ?cgi? SCRIPT
1311 **
1312 ** The SCRIPT argument is the name of a file that is the CGI script
1313 ** that is being run. The command name, "cgi", may be omitted if
@@ -1472,11 +1490,11 @@
1490 **
1491 ** fossil http REPOSITORY INFILE OUTFILE IPADDR
1492 **
1493 ** The argv==6 form is used by the win32 server only.
1494 **
1495 ** COMMAND: http*
1496 **
1497 ** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
1498 **
1499 ** Handle a single HTTP request appearing on stdin. The resulting webpage
1500 ** is delivered on stdout. This method is used to launch an HTTP request
@@ -1573,11 +1591,11 @@
1591 }
1592 #endif
1593 #endif
1594
1595 /*
1596 ** COMMAND: server*
1597 ** COMMAND: ui
1598 **
1599 ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
1600 ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
1601 **
1602
+45 -27
--- src/main.c
+++ src/main.c
@@ -409,14 +409,17 @@
409409
for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
410410
if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
411411
zCmdName = "cgi";
412412
g.isHTTP = 1;
413413
}else if( argc<2 ){
414
- fossil_fatal("Usage: %s COMMAND ...\n"
415
- "\"%s help\" for a list of available commands\n"
416
- "\"%s help COMMAND\" for specific details\n",
417
- argv[0], argv[0], argv[0]);
414
+ fossil_print(
415
+ "Usage: %s COMMAND ...\n"
416
+ " or: %s help -- for a list of common commands\n"
417
+ " or: %s help COMMMAND -- for help with the named command\n"
418
+ " or: %s commands -- for a list of all commands\n",
419
+ argv[0], argv[0], argv[0], argv[0]);
420
+ fossil_exit(1);
418421
}else{
419422
g.isHTTP = 0;
420423
g.fQuiet = find_option("quiet", 0, 0)!=0;
421424
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
422425
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
@@ -453,14 +456,15 @@
453456
for(i=0; i<count(aCommand); i++){
454457
if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){
455458
blob_appendf(&couldbe, " %s", aCommand[i].zName);
456459
}
457460
}
458
- fossil_fatal("%s: ambiguous command prefix: %s\n"
461
+ fossil_print("%s: ambiguous command prefix: %s\n"
459462
"%s: could be any of:%s\n"
460463
"%s: use \"help\" for more information\n",
461464
argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]);
465
+ fossil_exit(1);
462466
}
463467
if(rc){
464468
fossil_fatal("%s: unrecoverable error while initializing JSON CGI bits: "
465469
"cson error code #%d (%s)\n",
466470
argv[0], rc, cson_rc_string(rc));
@@ -810,38 +814,45 @@
810814
}
811815
812816
/*
813817
** List of commands starting with zPrefix, or all commands if zPrefix is NULL.
814818
*/
815
-static void cmd_cmd_list(const char *zPrefix){
819
+static void command_list(const char *zPrefix, int cmdMask){
816820
int i, nCmd;
817821
int nPrefix = zPrefix ? strlen(zPrefix) : 0;
818822
const char *aCmd[count(aCommand)];
819823
for(i=nCmd=0; i<count(aCommand); i++){
820824
const char *z = aCommand[i].zName;
821
- if( memcmp(z,"test",4)==0 ) continue;
825
+ if( (aCommand[i].cmdFlags & cmdMask)==0 ) continue;
822826
if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue;
823827
aCmd[nCmd++] = aCommand[i].zName;
824828
}
825829
multi_column_list(aCmd, nCmd);
826830
}
827831
828832
/*
829
-** COMMAND: test-commands
833
+** COMMAND: commands
830834
**
831
-** Usage: %fossil test-commands
835
+** Usage: %fossil commands ?--test? ?--all? ?--aux?
832836
**
833
-** List all commands used for testing and debugging.
837
+** List available commands. If the --test option is used list only unsupported
838
+** commands intended for testing and debugging. With --all, show all commands
839
+** including test debugging commands. With --aux, show only the auxiliary
840
+** and less often used commands, and/or command aliases.
834841
*/
835
-void cmd_test_cmd_list(void){
836
- int i, nCmd;
837
- const char *aCmd[count(aCommand)];
838
- for(i=nCmd=0; i<count(aCommand); i++){
839
- if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
840
- aCmd[nCmd++] = aCommand[i].zName;
841
- }
842
- multi_column_list(aCmd, nCmd);
842
+void cmd_command_list(void){
843
+ int cmdFlags = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
844
+ if( find_option("all",0,0)!=0 ){
845
+ cmdFlags |= CMDFLAG_TEST;
846
+ }else if( find_option("test",0,0)!=0 ){
847
+ cmdFlags = CMDFLAG_TEST;
848
+ }else if( find_option("aux",0,0)!=0 ){
849
+ cmdFlags = CMDFLAG_2ND_TIER;
850
+ }else{
851
+ fossil_print("Use --test or --all to see test and debug commands.\n");
852
+ }
853
+ command_list(0, cmdFlags);
843854
}
844855
845856
846857
/*
847858
** COMMAND: test-list-webpage
@@ -873,32 +884,39 @@
873884
874885
/*
875886
** COMMAND: help
876887
**
877888
** Usage: %fossil help COMMAND
889
+** or: %fossil COMMAND -help
890
+**
891
+** Display information on how to use COMMAND. To display a list of
892
+** available commands use:
878893
**
879
-** Display information on how to use COMMAND
894
+** %fossil commands
880895
*/
881896
void help_cmd(void){
882897
int rc, idx;
883898
const char *z;
884899
if( g.argc<3 ){
885
- fossil_print("Usage: %s help COMMAND.\nAvailable COMMANDs:\n",
886
- fossil_nameofexe());
887
- cmd_cmd_list(0);
900
+ z = fossil_nameofexe();
901
+ fossil_print(
902
+ "Usage: %s help COMMAND\n"
903
+ "Common COMMANDs: (use \"%s commands\" for a complete list)\n",
904
+ z, z);
905
+ command_list(0, CMDFLAG_1ST_TIER);
888906
version_cmd();
889907
return;
890908
}
891909
rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
892910
if( rc==1 ){
893911
fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
894
- cmd_cmd_list(0);
912
+ command_list(0, 0xff);
895913
fossil_exit(1);
896914
}else if( rc==2 ){
897915
fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
898916
g.argv[2]);
899
- cmd_cmd_list(g.argv[2]);
917
+ command_list(g.argv[2], 0xff);
900918
fossil_exit(1);
901919
}
902920
z = aCmdHelp[idx];
903921
if( z==0 ){
904922
fossil_fatal("no help available for the %s command",
@@ -1285,11 +1303,11 @@
12851303
*/
12861304
cgi_reply();
12871305
}
12881306
12891307
/*
1290
-** COMMAND: cgi
1308
+** COMMAND: cgi*
12911309
**
12921310
** Usage: %fossil ?cgi? SCRIPT
12931311
**
12941312
** The SCRIPT argument is the name of a file that is the CGI script
12951313
** that is being run. The command name, "cgi", may be omitted if
@@ -1472,11 +1490,11 @@
14721490
**
14731491
** fossil http REPOSITORY INFILE OUTFILE IPADDR
14741492
**
14751493
** The argv==6 form is used by the win32 server only.
14761494
**
1477
-** COMMAND: http
1495
+** COMMAND: http*
14781496
**
14791497
** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
14801498
**
14811499
** Handle a single HTTP request appearing on stdin. The resulting webpage
14821500
** is delivered on stdout. This method is used to launch an HTTP request
@@ -1573,11 +1591,11 @@
15731591
}
15741592
#endif
15751593
#endif
15761594
15771595
/*
1578
-** COMMAND: server
1596
+** COMMAND: server*
15791597
** COMMAND: ui
15801598
**
15811599
** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
15821600
** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
15831601
**
15841602
--- src/main.c
+++ src/main.c
@@ -409,14 +409,17 @@
409 for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
410 if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
411 zCmdName = "cgi";
412 g.isHTTP = 1;
413 }else if( argc<2 ){
414 fossil_fatal("Usage: %s COMMAND ...\n"
415 "\"%s help\" for a list of available commands\n"
416 "\"%s help COMMAND\" for specific details\n",
417 argv[0], argv[0], argv[0]);
 
 
 
418 }else{
419 g.isHTTP = 0;
420 g.fQuiet = find_option("quiet", 0, 0)!=0;
421 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
422 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
@@ -453,14 +456,15 @@
453 for(i=0; i<count(aCommand); i++){
454 if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){
455 blob_appendf(&couldbe, " %s", aCommand[i].zName);
456 }
457 }
458 fossil_fatal("%s: ambiguous command prefix: %s\n"
459 "%s: could be any of:%s\n"
460 "%s: use \"help\" for more information\n",
461 argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]);
 
462 }
463 if(rc){
464 fossil_fatal("%s: unrecoverable error while initializing JSON CGI bits: "
465 "cson error code #%d (%s)\n",
466 argv[0], rc, cson_rc_string(rc));
@@ -810,38 +814,45 @@
810 }
811
812 /*
813 ** List of commands starting with zPrefix, or all commands if zPrefix is NULL.
814 */
815 static void cmd_cmd_list(const char *zPrefix){
816 int i, nCmd;
817 int nPrefix = zPrefix ? strlen(zPrefix) : 0;
818 const char *aCmd[count(aCommand)];
819 for(i=nCmd=0; i<count(aCommand); i++){
820 const char *z = aCommand[i].zName;
821 if( memcmp(z,"test",4)==0 ) continue;
822 if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue;
823 aCmd[nCmd++] = aCommand[i].zName;
824 }
825 multi_column_list(aCmd, nCmd);
826 }
827
828 /*
829 ** COMMAND: test-commands
830 **
831 ** Usage: %fossil test-commands
832 **
833 ** List all commands used for testing and debugging.
 
 
 
834 */
835 void cmd_test_cmd_list(void){
836 int i, nCmd;
837 const char *aCmd[count(aCommand)];
838 for(i=nCmd=0; i<count(aCommand); i++){
839 if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
840 aCmd[nCmd++] = aCommand[i].zName;
841 }
842 multi_column_list(aCmd, nCmd);
 
 
 
 
843 }
844
845
846 /*
847 ** COMMAND: test-list-webpage
@@ -873,32 +884,39 @@
873
874 /*
875 ** COMMAND: help
876 **
877 ** Usage: %fossil help COMMAND
 
 
 
 
878 **
879 ** Display information on how to use COMMAND
880 */
881 void help_cmd(void){
882 int rc, idx;
883 const char *z;
884 if( g.argc<3 ){
885 fossil_print("Usage: %s help COMMAND.\nAvailable COMMANDs:\n",
886 fossil_nameofexe());
887 cmd_cmd_list(0);
 
 
 
888 version_cmd();
889 return;
890 }
891 rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
892 if( rc==1 ){
893 fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
894 cmd_cmd_list(0);
895 fossil_exit(1);
896 }else if( rc==2 ){
897 fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
898 g.argv[2]);
899 cmd_cmd_list(g.argv[2]);
900 fossil_exit(1);
901 }
902 z = aCmdHelp[idx];
903 if( z==0 ){
904 fossil_fatal("no help available for the %s command",
@@ -1285,11 +1303,11 @@
1285 */
1286 cgi_reply();
1287 }
1288
1289 /*
1290 ** COMMAND: cgi
1291 **
1292 ** Usage: %fossil ?cgi? SCRIPT
1293 **
1294 ** The SCRIPT argument is the name of a file that is the CGI script
1295 ** that is being run. The command name, "cgi", may be omitted if
@@ -1472,11 +1490,11 @@
1472 **
1473 ** fossil http REPOSITORY INFILE OUTFILE IPADDR
1474 **
1475 ** The argv==6 form is used by the win32 server only.
1476 **
1477 ** COMMAND: http
1478 **
1479 ** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
1480 **
1481 ** Handle a single HTTP request appearing on stdin. The resulting webpage
1482 ** is delivered on stdout. This method is used to launch an HTTP request
@@ -1573,11 +1591,11 @@
1573 }
1574 #endif
1575 #endif
1576
1577 /*
1578 ** COMMAND: server
1579 ** COMMAND: ui
1580 **
1581 ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
1582 ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
1583 **
1584
--- src/main.c
+++ src/main.c
@@ -409,14 +409,17 @@
409 for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
410 if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
411 zCmdName = "cgi";
412 g.isHTTP = 1;
413 }else if( argc<2 ){
414 fossil_print(
415 "Usage: %s COMMAND ...\n"
416 " or: %s help -- for a list of common commands\n"
417 " or: %s help COMMMAND -- for help with the named command\n"
418 " or: %s commands -- for a list of all commands\n",
419 argv[0], argv[0], argv[0], argv[0]);
420 fossil_exit(1);
421 }else{
422 g.isHTTP = 0;
423 g.fQuiet = find_option("quiet", 0, 0)!=0;
424 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
425 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
@@ -453,14 +456,15 @@
456 for(i=0; i<count(aCommand); i++){
457 if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){
458 blob_appendf(&couldbe, " %s", aCommand[i].zName);
459 }
460 }
461 fossil_print("%s: ambiguous command prefix: %s\n"
462 "%s: could be any of:%s\n"
463 "%s: use \"help\" for more information\n",
464 argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]);
465 fossil_exit(1);
466 }
467 if(rc){
468 fossil_fatal("%s: unrecoverable error while initializing JSON CGI bits: "
469 "cson error code #%d (%s)\n",
470 argv[0], rc, cson_rc_string(rc));
@@ -810,38 +814,45 @@
814 }
815
816 /*
817 ** List of commands starting with zPrefix, or all commands if zPrefix is NULL.
818 */
819 static void command_list(const char *zPrefix, int cmdMask){
820 int i, nCmd;
821 int nPrefix = zPrefix ? strlen(zPrefix) : 0;
822 const char *aCmd[count(aCommand)];
823 for(i=nCmd=0; i<count(aCommand); i++){
824 const char *z = aCommand[i].zName;
825 if( (aCommand[i].cmdFlags & cmdMask)==0 ) continue;
826 if( zPrefix && memcmp(zPrefix, z, nPrefix)!=0 ) continue;
827 aCmd[nCmd++] = aCommand[i].zName;
828 }
829 multi_column_list(aCmd, nCmd);
830 }
831
832 /*
833 ** COMMAND: commands
834 **
835 ** Usage: %fossil commands ?--test? ?--all? ?--aux?
836 **
837 ** List available commands. If the --test option is used list only unsupported
838 ** commands intended for testing and debugging. With --all, show all commands
839 ** including test debugging commands. With --aux, show only the auxiliary
840 ** and less often used commands, and/or command aliases.
841 */
842 void cmd_command_list(void){
843 int cmdFlags = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
844 if( find_option("all",0,0)!=0 ){
845 cmdFlags |= CMDFLAG_TEST;
846 }else if( find_option("test",0,0)!=0 ){
847 cmdFlags = CMDFLAG_TEST;
848 }else if( find_option("aux",0,0)!=0 ){
849 cmdFlags = CMDFLAG_2ND_TIER;
850 }else{
851 fossil_print("Use --test or --all to see test and debug commands.\n");
852 }
853 command_list(0, cmdFlags);
854 }
855
856
857 /*
858 ** COMMAND: test-list-webpage
@@ -873,32 +884,39 @@
884
885 /*
886 ** COMMAND: help
887 **
888 ** Usage: %fossil help COMMAND
889 ** or: %fossil COMMAND -help
890 **
891 ** Display information on how to use COMMAND. To display a list of
892 ** available commands use:
893 **
894 ** %fossil commands
895 */
896 void help_cmd(void){
897 int rc, idx;
898 const char *z;
899 if( g.argc<3 ){
900 z = fossil_nameofexe();
901 fossil_print(
902 "Usage: %s help COMMAND\n"
903 "Common COMMANDs: (use \"%s commands\" for a complete list)\n",
904 z, z);
905 command_list(0, CMDFLAG_1ST_TIER);
906 version_cmd();
907 return;
908 }
909 rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
910 if( rc==1 ){
911 fossil_print("unknown command: %s\nAvailable commands:\n", g.argv[2]);
912 command_list(0, 0xff);
913 fossil_exit(1);
914 }else if( rc==2 ){
915 fossil_print("ambiguous command prefix: %s\nMatching commands:\n",
916 g.argv[2]);
917 command_list(g.argv[2], 0xff);
918 fossil_exit(1);
919 }
920 z = aCmdHelp[idx];
921 if( z==0 ){
922 fossil_fatal("no help available for the %s command",
@@ -1285,11 +1303,11 @@
1303 */
1304 cgi_reply();
1305 }
1306
1307 /*
1308 ** COMMAND: cgi*
1309 **
1310 ** Usage: %fossil ?cgi? SCRIPT
1311 **
1312 ** The SCRIPT argument is the name of a file that is the CGI script
1313 ** that is being run. The command name, "cgi", may be omitted if
@@ -1472,11 +1490,11 @@
1490 **
1491 ** fossil http REPOSITORY INFILE OUTFILE IPADDR
1492 **
1493 ** The argv==6 form is used by the win32 server only.
1494 **
1495 ** COMMAND: http*
1496 **
1497 ** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
1498 **
1499 ** Handle a single HTTP request appearing on stdin. The resulting webpage
1500 ** is delivered on stdout. This method is used to launch an HTTP request
@@ -1573,11 +1591,11 @@
1591 }
1592 #endif
1593 #endif
1594
1595 /*
1596 ** COMMAND: server*
1597 ** COMMAND: ui
1598 **
1599 ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
1600 ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
1601 **
1602
+22 -7
--- src/manifest.c
+++ src/manifest.c
@@ -1334,18 +1334,33 @@
13341334
}
13351335
}
13361336
}
13371337
if( pParent->zBaseline && pChild->zBaseline ){
13381338
/* Both parent and child are delta manifests. Look for files that
1339
- ** are marked as deleted in the parent but which reappear in the child
1340
- ** and show such files as being added in the child. */
1339
+ ** are deleted or modified in the parent but which reappear or revert
1340
+ ** to baseline in the child and show such files as being added or changed
1341
+ ** in the child. */
13411342
for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){
1342
- if( pParentFile->zUuid ) continue;
1343
- pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1344
- if( pChildFile ){
1345
- add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1346
- isPublic, manifest_file_mperm(pChildFile));
1343
+ if( pParentFile->zUuid ){
1344
+ pChildFile = manifest_file_seek_base(pChild, pParentFile->zName);
1345
+ if( pChildFile==0 ){
1346
+ /* The child file reverts to baseline. Show this as a change */
1347
+ pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1348
+ if( pChildFile ){
1349
+ add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1350
+ pChildFile->zName, 0, isPublic,
1351
+ manifest_file_mperm(pChildFile));
1352
+ }
1353
+ }
1354
+ }else{
1355
+ pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1356
+ if( pChildFile ){
1357
+ /* File resurrected in the child after having been deleted in
1358
+ ** the parent. Show this as an added file. */
1359
+ add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1360
+ isPublic, manifest_file_mperm(pChildFile));
1361
+ }
13471362
}
13481363
}
13491364
}else if( pChild->zBaseline==0 ){
13501365
/* pChild is a baseline. Look for files that are present in pParent
13511366
** but are missing from pChild and mark them as having been deleted. */
13521367
--- src/manifest.c
+++ src/manifest.c
@@ -1334,18 +1334,33 @@
1334 }
1335 }
1336 }
1337 if( pParent->zBaseline && pChild->zBaseline ){
1338 /* Both parent and child are delta manifests. Look for files that
1339 ** are marked as deleted in the parent but which reappear in the child
1340 ** and show such files as being added in the child. */
 
1341 for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){
1342 if( pParentFile->zUuid ) continue;
1343 pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1344 if( pChildFile ){
1345 add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1346 isPublic, manifest_file_mperm(pChildFile));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1347 }
1348 }
1349 }else if( pChild->zBaseline==0 ){
1350 /* pChild is a baseline. Look for files that are present in pParent
1351 ** but are missing from pChild and mark them as having been deleted. */
1352
--- src/manifest.c
+++ src/manifest.c
@@ -1334,18 +1334,33 @@
1334 }
1335 }
1336 }
1337 if( pParent->zBaseline && pChild->zBaseline ){
1338 /* Both parent and child are delta manifests. Look for files that
1339 ** are deleted or modified in the parent but which reappear or revert
1340 ** to baseline in the child and show such files as being added or changed
1341 ** in the child. */
1342 for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){
1343 if( pParentFile->zUuid ){
1344 pChildFile = manifest_file_seek_base(pChild, pParentFile->zName);
1345 if( pChildFile==0 ){
1346 /* The child file reverts to baseline. Show this as a change */
1347 pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1348 if( pChildFile ){
1349 add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1350 pChildFile->zName, 0, isPublic,
1351 manifest_file_mperm(pChildFile));
1352 }
1353 }
1354 }else{
1355 pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1356 if( pChildFile ){
1357 /* File resurrected in the child after having been deleted in
1358 ** the parent. Show this as an added file. */
1359 add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1360 isPublic, manifest_file_mperm(pChildFile));
1361 }
1362 }
1363 }
1364 }else if( pChild->zBaseline==0 ){
1365 /* pChild is a baseline. Look for files that are present in pParent
1366 ** but are missing from pChild and mark them as having been deleted. */
1367
+3 -2
--- src/md5.c
+++ src/md5.c
@@ -421,14 +421,15 @@
421421
return 0;
422422
}
423423
424424
425425
/*
426
-** COMMAND: test-md5sum
426
+** COMMAND: md5sum*
427
+** Usage: %fossil md5sum FILES....
427428
**
428429
** Compute an MD5 checksum of all files named on the command-line.
429
-** If an file is named "-" then take its content from standard input.
430
+** If a file is named "-" then content is read from standard input.
430431
*/
431432
void md5sum_test(void){
432433
int i;
433434
Blob in;
434435
Blob cksum;
435436
--- src/md5.c
+++ src/md5.c
@@ -421,14 +421,15 @@
421 return 0;
422 }
423
424
425 /*
426 ** COMMAND: test-md5sum
 
427 **
428 ** Compute an MD5 checksum of all files named on the command-line.
429 ** If an file is named "-" then take its content from standard input.
430 */
431 void md5sum_test(void){
432 int i;
433 Blob in;
434 Blob cksum;
435
--- src/md5.c
+++ src/md5.c
@@ -421,14 +421,15 @@
421 return 0;
422 }
423
424
425 /*
426 ** COMMAND: md5sum*
427 ** Usage: %fossil md5sum FILES....
428 **
429 ** Compute an MD5 checksum of all files named on the command-line.
430 ** If a file is named "-" then content is read from standard input.
431 */
432 void md5sum_test(void){
433 int i;
434 Blob in;
435 Blob cksum;
436
+29 -7
--- src/mkindex.c
+++ src/mkindex.c
@@ -36,11 +36,13 @@
3636
** We also scan for comments lines of this form:
3737
**
3838
** COMMAND: cmdname
3939
**
4040
** These entries build a constant table used to map command names into
41
-** functions.
41
+** functions. If cmdname ends with "*" then the command is a second-tier
42
+** command that is not displayed by the "fossil help" command. The
43
+** final "*" is not considered to be part of the command name.
4244
**
4345
** Comment text following COMMAND: through the end of the comment is
4446
** understood to be help text for the command specified. This help
4547
** text is accumulated and a table containing the text for each command
4648
** is generated. That table is used implement the "fossil help" command
@@ -224,28 +226,48 @@
224226
printf(
225227
"typedef struct NameMap NameMap;\n"
226228
"struct NameMap {\n"
227229
" const char *zName;\n"
228230
" void (*xFunc)(void);\n"
231
+ " char cmdFlags;\n"
229232
"};\n"
233
+ "#define CMDFLAG_1ST_TIER 0x01\n"
234
+ "#define CMDFLAG_2ND_TIER 0x02\n"
235
+ "#define CMDFLAG_TEST 0x04\n"
230236
"static const NameMap aWebpage[] = {\n"
231237
);
232238
for(i=0; i<nFixed && aEntry[i].eType==0; i++){
233
- printf(" { \"%s\",%*s %s },\n",
234
- aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "",
235
- aEntry[i].zFunc
239
+ const char *z = aEntry[i].zPath;
240
+ int n = strlen(z);
241
+ printf(" { \"%s\",%*s %s,%*s 1 },\n",
242
+ z,
243
+ 25-n, "",
244
+ aEntry[i].zFunc,
245
+ (int)(35-strlen(aEntry[i].zFunc)), ""
236246
);
237247
}
238248
printf("};\n");
239249
nType0 = i;
240250
printf(
241251
"static const NameMap aCommand[] = {\n"
242252
);
243253
for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){
244
- printf(" { \"%s\",%*s %s },\n",
245
- aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "",
246
- aEntry[i].zFunc
254
+ const char *z = aEntry[i].zPath;
255
+ int n = strlen(z);
256
+ int cmdFlags = 0x01;
257
+ if( z[n-1]=='*' ){
258
+ n--;
259
+ cmdFlags = 0x02;
260
+ }else if( memcmp(z, "test-", 5)==0 ){
261
+ cmdFlags = 0x04;
262
+ }
263
+ printf(" { \"%.*s\",%*s %s,%*s %d },\n",
264
+ n, z,
265
+ 25-n, "",
266
+ aEntry[i].zFunc,
267
+ (int)(35-strlen(aEntry[i].zFunc)), "",
268
+ cmdFlags
247269
);
248270
}
249271
printf("};\n");
250272
for(i=nType0; i<nFixed; i++){
251273
char *z = aEntry[i].zHelp;
252274
--- src/mkindex.c
+++ src/mkindex.c
@@ -36,11 +36,13 @@
36 ** We also scan for comments lines of this form:
37 **
38 ** COMMAND: cmdname
39 **
40 ** These entries build a constant table used to map command names into
41 ** functions.
 
 
42 **
43 ** Comment text following COMMAND: through the end of the comment is
44 ** understood to be help text for the command specified. This help
45 ** text is accumulated and a table containing the text for each command
46 ** is generated. That table is used implement the "fossil help" command
@@ -224,28 +226,48 @@
224 printf(
225 "typedef struct NameMap NameMap;\n"
226 "struct NameMap {\n"
227 " const char *zName;\n"
228 " void (*xFunc)(void);\n"
 
229 "};\n"
 
 
 
230 "static const NameMap aWebpage[] = {\n"
231 );
232 for(i=0; i<nFixed && aEntry[i].eType==0; i++){
233 printf(" { \"%s\",%*s %s },\n",
234 aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "",
235 aEntry[i].zFunc
 
 
 
 
236 );
237 }
238 printf("};\n");
239 nType0 = i;
240 printf(
241 "static const NameMap aCommand[] = {\n"
242 );
243 for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){
244 printf(" { \"%s\",%*s %s },\n",
245 aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "",
246 aEntry[i].zFunc
 
 
 
 
 
 
 
 
 
 
 
 
247 );
248 }
249 printf("};\n");
250 for(i=nType0; i<nFixed; i++){
251 char *z = aEntry[i].zHelp;
252
--- src/mkindex.c
+++ src/mkindex.c
@@ -36,11 +36,13 @@
36 ** We also scan for comments lines of this form:
37 **
38 ** COMMAND: cmdname
39 **
40 ** These entries build a constant table used to map command names into
41 ** functions. If cmdname ends with "*" then the command is a second-tier
42 ** command that is not displayed by the "fossil help" command. The
43 ** final "*" is not considered to be part of the command name.
44 **
45 ** Comment text following COMMAND: through the end of the comment is
46 ** understood to be help text for the command specified. This help
47 ** text is accumulated and a table containing the text for each command
48 ** is generated. That table is used implement the "fossil help" command
@@ -224,28 +226,48 @@
226 printf(
227 "typedef struct NameMap NameMap;\n"
228 "struct NameMap {\n"
229 " const char *zName;\n"
230 " void (*xFunc)(void);\n"
231 " char cmdFlags;\n"
232 "};\n"
233 "#define CMDFLAG_1ST_TIER 0x01\n"
234 "#define CMDFLAG_2ND_TIER 0x02\n"
235 "#define CMDFLAG_TEST 0x04\n"
236 "static const NameMap aWebpage[] = {\n"
237 );
238 for(i=0; i<nFixed && aEntry[i].eType==0; i++){
239 const char *z = aEntry[i].zPath;
240 int n = strlen(z);
241 printf(" { \"%s\",%*s %s,%*s 1 },\n",
242 z,
243 25-n, "",
244 aEntry[i].zFunc,
245 (int)(35-strlen(aEntry[i].zFunc)), ""
246 );
247 }
248 printf("};\n");
249 nType0 = i;
250 printf(
251 "static const NameMap aCommand[] = {\n"
252 );
253 for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){
254 const char *z = aEntry[i].zPath;
255 int n = strlen(z);
256 int cmdFlags = 0x01;
257 if( z[n-1]=='*' ){
258 n--;
259 cmdFlags = 0x02;
260 }else if( memcmp(z, "test-", 5)==0 ){
261 cmdFlags = 0x04;
262 }
263 printf(" { \"%.*s\",%*s %s,%*s %d },\n",
264 n, z,
265 25-n, "",
266 aEntry[i].zFunc,
267 (int)(35-strlen(aEntry[i].zFunc)), "",
268 cmdFlags
269 );
270 }
271 printf("};\n");
272 for(i=nType0; i<nFixed; i++){
273 char *z = aEntry[i].zHelp;
274
+329 -260
--- 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,34 +364,101 @@
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
if(!zName && fossil_has_json()){
372372
zName = json_find_option_cstr(zParamName,NULL,NULL);
373373
}
374374
if( zName==0 || zName[0]==0 ) return 0;
375
- blob_init(&name, zName, -1);
376
- rc = name_to_uuid(&name, -1, "*");
377
- if( rc==1 ){
378
- blob_reset(&name);
379
- for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
380
- if( zName[i]==0 ){
381
- rid = atoi(zName);
382
- if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
383
- return rid;
384
- }
385
- }
386
- return 0;
387
- }else if( rc==2 ){
388
- cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
389
- return 0;
390
- }else{
391
- rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
392
- blob_reset(&name);
393
- }
394
- return rid;
375
+ rid = symbolic_name_to_rid(zName, "*");
376
+ if( rid<0 ){
377
+ cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
378
+ rid = 0;
379
+ }
380
+ return rid;
381
+}
382
+
383
+/*
384
+** COMMAND: whatis*
385
+** Usage: %fossil whatis NAME
386
+**
387
+** Resolve the symbol NAME into its canonical 40-character SHA1-hash
388
+** artifact name and provide a description of what role that artifact
389
+** plays.
390
+*/
391
+void whatis_cmd(void){
392
+ int rid;
393
+ const char *zName;
394
+ int fExtra;
395
+ db_find_and_open_repository(0,0);
396
+ fExtra = find_option("verbose","v",0)!=0;
397
+ if( g.argc!=3 ) usage("whatis NAME");
398
+ zName = g.argv[2];
399
+ rid = symbolic_name_to_rid(zName, 0);
400
+ if( rid<0 ){
401
+ fossil_print("Ambiguous artifact name prefix: %s\n", zName);
402
+ }else if( rid==0 ){
403
+ fossil_print("Unknown artifact: %s\n", zName);
404
+ }else{
405
+ Stmt q;
406
+ db_prepare(&q, "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr"
407
+ " FROM blob, rcvfrom"
408
+ " WHERE rid=%d"
409
+ " AND rcvfrom.rcvid=blob.rcvid",
410
+ rid);
411
+ if( db_step(&q)==SQLITE_ROW ){
412
+ if( fExtra ){
413
+ fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
414
+ fossil_print("size: %d bytes\n", db_column_int(&q,1));
415
+ fossil_print("received: %s from %s\n",
416
+ db_column_text(&q, 2),
417
+ db_column_text(&q, 3));
418
+ }else{
419
+ fossil_print("artifact: %s\n", db_column_text(&q,0));
420
+ fossil_print("size: %d bytes\n", db_column_int(&q,1));
421
+ }
422
+ }
423
+ db_finalize(&q);
424
+ db_prepare(&q,
425
+ "SELECT type, datetime(mtime,'localtime'),"
426
+ " coalesce(euser,user), coalesce(ecomment,comment)"
427
+ " FROM event WHERE objid=%d", rid);
428
+ if( db_step(&q)==SQLITE_ROW ){
429
+ const char *zType;
430
+ switch( db_column_text(&q,0)[0] ){
431
+ case 'c': zType = "Check-in"; break;
432
+ case 'w': zType = "Wiki-edit"; break;
433
+ case 'e': zType = "Event"; break;
434
+ case 't': zType = "Ticket-change"; break;
435
+ case 'g': zType = "Tag-change"; break;
436
+ }
437
+ fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
438
+ db_column_text(&q, 1));
439
+ fossil_print("comment: ");
440
+ comment_print(db_column_text(&q,3), 10, 78);
441
+ }
442
+ db_finalize(&q);
443
+ db_prepare(&q,
444
+ "SELECT filename.name, blob.uuid, datetime(event.mtime,'localtime'),"
445
+ " coalesce(euser,user), coalesce(ecomment,comment)"
446
+ " FROM mlink, filename, blob, event"
447
+ " WHERE mlink.fid=%d"
448
+ " AND filename.fnid=mlink.fnid"
449
+ " AND event.objid=mlink.mid"
450
+ " AND blob.rid=mlink.mid"
451
+ " ORDER BY event.mtime DESC /*sort*/",
452
+ rid);
453
+ while( db_step(&q)==SQLITE_ROW ){
454
+ fossil_print("file: %s\n", db_column_text(&q,0));
455
+ fossil_print(" part of [%.10s] by %s on %s\n",
456
+ db_column_text(&q, 1),
457
+ db_column_text(&q, 3),
458
+ db_column_text(&q, 2));
459
+ fossil_print(" ");
460
+ comment_print(db_column_text(&q,4), 10, 78);
461
+ }
462
+ db_finalize(&q);
463
+ }
395464
}
396465
--- 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,34 +364,101 @@
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 if(!zName && fossil_has_json()){
372 zName = json_find_option_cstr(zParamName,NULL,NULL);
373 }
374 if( zName==0 || zName[0]==0 ) return 0;
375 blob_init(&name, zName, -1);
376 rc = name_to_uuid(&name, -1, "*");
377 if( rc==1 ){
378 blob_reset(&name);
379 for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
380 if( zName[i]==0 ){
381 rid = atoi(zName);
382 if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
383 return rid;
384 }
385 }
386 return 0;
387 }else if( rc==2 ){
388 cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
389 return 0;
390 }else{
391 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
392 blob_reset(&name);
393 }
394 return rid;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395 }
396
--- 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,34 +364,101 @@
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 if(!zName && fossil_has_json()){
372 zName = json_find_option_cstr(zParamName,NULL,NULL);
373 }
374 if( zName==0 || zName[0]==0 ) return 0;
375 rid = symbolic_name_to_rid(zName, "*");
376 if( rid<0 ){
377 cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
378 rid = 0;
379 }
380 return rid;
381 }
382
383 /*
384 ** COMMAND: whatis*
385 ** Usage: %fossil whatis NAME
386 **
387 ** Resolve the symbol NAME into its canonical 40-character SHA1-hash
388 ** artifact name and provide a description of what role that artifact
389 ** plays.
390 */
391 void whatis_cmd(void){
392 int rid;
393 const char *zName;
394 int fExtra;
395 db_find_and_open_repository(0,0);
396 fExtra = find_option("verbose","v",0)!=0;
397 if( g.argc!=3 ) usage("whatis NAME");
398 zName = g.argv[2];
399 rid = symbolic_name_to_rid(zName, 0);
400 if( rid<0 ){
401 fossil_print("Ambiguous artifact name prefix: %s\n", zName);
402 }else if( rid==0 ){
403 fossil_print("Unknown artifact: %s\n", zName);
404 }else{
405 Stmt q;
406 db_prepare(&q, "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr"
407 " FROM blob, rcvfrom"
408 " WHERE rid=%d"
409 " AND rcvfrom.rcvid=blob.rcvid",
410 rid);
411 if( db_step(&q)==SQLITE_ROW ){
412 if( fExtra ){
413 fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
414 fossil_print("size: %d bytes\n", db_column_int(&q,1));
415 fossil_print("received: %s from %s\n",
416 db_column_text(&q, 2),
417 db_column_text(&q, 3));
418 }else{
419 fossil_print("artifact: %s\n", db_column_text(&q,0));
420 fossil_print("size: %d bytes\n", db_column_int(&q,1));
421 }
422 }
423 db_finalize(&q);
424 db_prepare(&q,
425 "SELECT type, datetime(mtime,'localtime'),"
426 " coalesce(euser,user), coalesce(ecomment,comment)"
427 " FROM event WHERE objid=%d", rid);
428 if( db_step(&q)==SQLITE_ROW ){
429 const char *zType;
430 switch( db_column_text(&q,0)[0] ){
431 case 'c': zType = "Check-in"; break;
432 case 'w': zType = "Wiki-edit"; break;
433 case 'e': zType = "Event"; break;
434 case 't': zType = "Ticket-change"; break;
435 case 'g': zType = "Tag-change"; break;
436 }
437 fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
438 db_column_text(&q, 1));
439 fossil_print("comment: ");
440 comment_print(db_column_text(&q,3), 10, 78);
441 }
442 db_finalize(&q);
443 db_prepare(&q,
444 "SELECT filename.name, blob.uuid, datetime(event.mtime,'localtime'),"
445 " coalesce(euser,user), coalesce(ecomment,comment)"
446 " FROM mlink, filename, blob, event"
447 " WHERE mlink.fid=%d"
448 " AND filename.fnid=mlink.fnid"
449 " AND event.objid=mlink.mid"
450 " AND blob.rid=mlink.mid"
451 " ORDER BY event.mtime DESC /*sort*/",
452 rid);
453 while( db_step(&q)==SQLITE_ROW ){
454 fossil_print("file: %s\n", db_column_text(&q,0));
455 fossil_print(" part of [%.10s] by %s on %s\n",
456 db_column_text(&q, 1),
457 db_column_text(&q, 3),
458 db_column_text(&q, 2));
459 fossil_print(" ");
460 comment_print(db_column_text(&q,4), 10, 78);
461 }
462 db_finalize(&q);
463 }
464 }
465
+329 -260
--- 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,34 +364,101 @@
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
if(!zName && fossil_has_json()){
372372
zName = json_find_option_cstr(zParamName,NULL,NULL);
373373
}
374374
if( zName==0 || zName[0]==0 ) return 0;
375
- blob_init(&name, zName, -1);
376
- rc = name_to_uuid(&name, -1, "*");
377
- if( rc==1 ){
378
- blob_reset(&name);
379
- for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
380
- if( zName[i]==0 ){
381
- rid = atoi(zName);
382
- if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
383
- return rid;
384
- }
385
- }
386
- return 0;
387
- }else if( rc==2 ){
388
- cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
389
- return 0;
390
- }else{
391
- rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
392
- blob_reset(&name);
393
- }
394
- return rid;
375
+ rid = symbolic_name_to_rid(zName, "*");
376
+ if( rid<0 ){
377
+ cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
378
+ rid = 0;
379
+ }
380
+ return rid;
381
+}
382
+
383
+/*
384
+** COMMAND: whatis*
385
+** Usage: %fossil whatis NAME
386
+**
387
+** Resolve the symbol NAME into its canonical 40-character SHA1-hash
388
+** artifact name and provide a description of what role that artifact
389
+** plays.
390
+*/
391
+void whatis_cmd(void){
392
+ int rid;
393
+ const char *zName;
394
+ int fExtra;
395
+ db_find_and_open_repository(0,0);
396
+ fExtra = find_option("verbose","v",0)!=0;
397
+ if( g.argc!=3 ) usage("whatis NAME");
398
+ zName = g.argv[2];
399
+ rid = symbolic_name_to_rid(zName, 0);
400
+ if( rid<0 ){
401
+ fossil_print("Ambiguous artifact name prefix: %s\n", zName);
402
+ }else if( rid==0 ){
403
+ fossil_print("Unknown artifact: %s\n", zName);
404
+ }else{
405
+ Stmt q;
406
+ db_prepare(&q, "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr"
407
+ " FROM blob, rcvfrom"
408
+ " WHERE rid=%d"
409
+ " AND rcvfrom.rcvid=blob.rcvid",
410
+ rid);
411
+ if( db_step(&q)==SQLITE_ROW ){
412
+ if( fExtra ){
413
+ fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
414
+ fossil_print("size: %d bytes\n", db_column_int(&q,1));
415
+ fossil_print("received: %s from %s\n",
416
+ db_column_text(&q, 2),
417
+ db_column_text(&q, 3));
418
+ }else{
419
+ fossil_print("artifact: %s\n", db_column_text(&q,0));
420
+ fossil_print("size: %d bytes\n", db_column_int(&q,1));
421
+ }
422
+ }
423
+ db_finalize(&q);
424
+ db_prepare(&q,
425
+ "SELECT type, datetime(mtime,'localtime'),"
426
+ " coalesce(euser,user), coalesce(ecomment,comment)"
427
+ " FROM event WHERE objid=%d", rid);
428
+ if( db_step(&q)==SQLITE_ROW ){
429
+ const char *zType;
430
+ switch( db_column_text(&q,0)[0] ){
431
+ case 'c': zType = "Check-in"; break;
432
+ case 'w': zType = "Wiki-edit"; break;
433
+ case 'e': zType = "Event"; break;
434
+ case 't': zType = "Ticket-change"; break;
435
+ case 'g': zType = "Tag-change"; break;
436
+ }
437
+ fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
438
+ db_column_text(&q, 1));
439
+ fossil_print("comment: ");
440
+ comment_print(db_column_text(&q,3), 10, 78);
441
+ }
442
+ db_finalize(&q);
443
+ db_prepare(&q,
444
+ "SELECT filename.name, blob.uuid, datetime(event.mtime,'localtime'),"
445
+ " coalesce(euser,user), coalesce(ecomment,comment)"
446
+ " FROM mlink, filename, blob, event"
447
+ " WHERE mlink.fid=%d"
448
+ " AND filename.fnid=mlink.fnid"
449
+ " AND event.objid=mlink.mid"
450
+ " AND blob.rid=mlink.mid"
451
+ " ORDER BY event.mtime DESC /*sort*/",
452
+ rid);
453
+ while( db_step(&q)==SQLITE_ROW ){
454
+ fossil_print("file: %s\n", db_column_text(&q,0));
455
+ fossil_print(" part of [%.10s] by %s on %s\n",
456
+ db_column_text(&q, 1),
457
+ db_column_text(&q, 3),
458
+ db_column_text(&q, 2));
459
+ fossil_print(" ");
460
+ comment_print(db_column_text(&q,4), 10, 78);
461
+ }
462
+ db_finalize(&q);
463
+ }
395464
}
396465
--- 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,34 +364,101 @@
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 if(!zName && fossil_has_json()){
372 zName = json_find_option_cstr(zParamName,NULL,NULL);
373 }
374 if( zName==0 || zName[0]==0 ) return 0;
375 blob_init(&name, zName, -1);
376 rc = name_to_uuid(&name, -1, "*");
377 if( rc==1 ){
378 blob_reset(&name);
379 for(i=0; zName[i] && fossil_isdigit(zName[i]); i++){}
380 if( zName[i]==0 ){
381 rid = atoi(zName);
382 if( db_exists("SELECT 1 FROM blob WHERE rid=%d", rid) ){
383 return rid;
384 }
385 }
386 return 0;
387 }else if( rc==2 ){
388 cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
389 return 0;
390 }else{
391 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
392 blob_reset(&name);
393 }
394 return rid;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395 }
396
--- 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,34 +364,101 @@
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 if(!zName && fossil_has_json()){
372 zName = json_find_option_cstr(zParamName,NULL,NULL);
373 }
374 if( zName==0 || zName[0]==0 ) return 0;
375 rid = symbolic_name_to_rid(zName, "*");
376 if( rid<0 ){
377 cgi_redirectf("%s/ambiguous/%T?src=%t", g.zTop, zName, g.zPath);
378 rid = 0;
379 }
380 return rid;
381 }
382
383 /*
384 ** COMMAND: whatis*
385 ** Usage: %fossil whatis NAME
386 **
387 ** Resolve the symbol NAME into its canonical 40-character SHA1-hash
388 ** artifact name and provide a description of what role that artifact
389 ** plays.
390 */
391 void whatis_cmd(void){
392 int rid;
393 const char *zName;
394 int fExtra;
395 db_find_and_open_repository(0,0);
396 fExtra = find_option("verbose","v",0)!=0;
397 if( g.argc!=3 ) usage("whatis NAME");
398 zName = g.argv[2];
399 rid = symbolic_name_to_rid(zName, 0);
400 if( rid<0 ){
401 fossil_print("Ambiguous artifact name prefix: %s\n", zName);
402 }else if( rid==0 ){
403 fossil_print("Unknown artifact: %s\n", zName);
404 }else{
405 Stmt q;
406 db_prepare(&q, "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr"
407 " FROM blob, rcvfrom"
408 " WHERE rid=%d"
409 " AND rcvfrom.rcvid=blob.rcvid",
410 rid);
411 if( db_step(&q)==SQLITE_ROW ){
412 if( fExtra ){
413 fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
414 fossil_print("size: %d bytes\n", db_column_int(&q,1));
415 fossil_print("received: %s from %s\n",
416 db_column_text(&q, 2),
417 db_column_text(&q, 3));
418 }else{
419 fossil_print("artifact: %s\n", db_column_text(&q,0));
420 fossil_print("size: %d bytes\n", db_column_int(&q,1));
421 }
422 }
423 db_finalize(&q);
424 db_prepare(&q,
425 "SELECT type, datetime(mtime,'localtime'),"
426 " coalesce(euser,user), coalesce(ecomment,comment)"
427 " FROM event WHERE objid=%d", rid);
428 if( db_step(&q)==SQLITE_ROW ){
429 const char *zType;
430 switch( db_column_text(&q,0)[0] ){
431 case 'c': zType = "Check-in"; break;
432 case 'w': zType = "Wiki-edit"; break;
433 case 'e': zType = "Event"; break;
434 case 't': zType = "Ticket-change"; break;
435 case 'g': zType = "Tag-change"; break;
436 }
437 fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
438 db_column_text(&q, 1));
439 fossil_print("comment: ");
440 comment_print(db_column_text(&q,3), 10, 78);
441 }
442 db_finalize(&q);
443 db_prepare(&q,
444 "SELECT filename.name, blob.uuid, datetime(event.mtime,'localtime'),"
445 " coalesce(euser,user), coalesce(ecomment,comment)"
446 " FROM mlink, filename, blob, event"
447 " WHERE mlink.fid=%d"
448 " AND filename.fnid=mlink.fnid"
449 " AND event.objid=mlink.mid"
450 " AND blob.rid=mlink.mid"
451 " ORDER BY event.mtime DESC /*sort*/",
452 rid);
453 while( db_step(&q)==SQLITE_ROW ){
454 fossil_print("file: %s\n", db_column_text(&q,0));
455 fossil_print(" part of [%.10s] by %s on %s\n",
456 db_column_text(&q, 1),
457 db_column_text(&q, 3),
458 db_column_text(&q, 2));
459 fossil_print(" ");
460 comment_print(db_column_text(&q,4), 10, 78);
461 }
462 db_finalize(&q);
463 }
464 }
465
+9 -5
--- src/rebuild.c
+++ src/rebuild.c
@@ -370,11 +370,15 @@
370370
" WHERE rid IN (SELECT rid FROM shun JOIN blob USING(uuid))"
371371
);
372372
db_multi_exec(
373373
"DELETE FROM config WHERE name IN ('remote-code', 'remote-maxid')"
374374
);
375
- totalSize = db_int(0, "SELECT count(*) FROM blob");
375
+
376
+ /* The following should be count(*) instead of max(rid). max(rid) is
377
+ ** an adequate approximation, however, and is much faster for large
378
+ ** repositories. */
379
+ totalSize = db_int(0, "SELECT max(rid) FROM blob");
376380
incrSize = totalSize/100;
377381
totalSize += incrSize*2;
378382
db_prepare(&s,
379383
"SELECT rid, size FROM blob /*scan*/"
380384
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
@@ -483,11 +487,11 @@
483487
484488
db_end_transaction(0);
485489
}
486490
487491
/*
488
-** COMMAND: rebuild
492
+** COMMAND: rebuild
489493
**
490494
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
491495
**
492496
** Reconstruct the named repository database from the core
493497
** records. Run this command after updating the fossil
@@ -716,11 +720,11 @@
716720
db_finalize(&q);
717721
}
718722
}
719723
720724
/*
721
-** COMMAND: scrub
725
+** COMMAND: scrub*
722726
** %fossil scrub ?OPTIONS? ?REPOSITORY?
723727
**
724728
** The command removes sensitive information (such as passwords) from a
725729
** repository so that the respository can be sent to an untrusted reader.
726730
**
@@ -850,11 +854,11 @@
850854
}
851855
fossil_mbcs_free(zMbcsPath);
852856
}
853857
854858
/*
855
-** COMMAND: reconstruct
859
+** COMMAND: reconstruct*
856860
**
857861
** Usage: %fossil reconstruct FILENAME DIRECTORY
858862
**
859863
** This command studies the artifacts (files) in DIRECTORY and
860864
** reconstructs the fossil record from them. It places the new
@@ -911,11 +915,11 @@
911915
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
912916
fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
913917
}
914918
915919
/*
916
-** COMMAND: deconstruct
920
+** COMMAND: deconstruct*
917921
**
918922
** Usage %fossil deconstruct ?OPTIONS? DESTINATION
919923
**
920924
**
921925
** This command exports all artifacts of a given repository and
922926
--- src/rebuild.c
+++ src/rebuild.c
@@ -370,11 +370,15 @@
370 " WHERE rid IN (SELECT rid FROM shun JOIN blob USING(uuid))"
371 );
372 db_multi_exec(
373 "DELETE FROM config WHERE name IN ('remote-code', 'remote-maxid')"
374 );
375 totalSize = db_int(0, "SELECT count(*) FROM blob");
 
 
 
 
376 incrSize = totalSize/100;
377 totalSize += incrSize*2;
378 db_prepare(&s,
379 "SELECT rid, size FROM blob /*scan*/"
380 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
@@ -483,11 +487,11 @@
483
484 db_end_transaction(0);
485 }
486
487 /*
488 ** COMMAND: rebuild
489 **
490 ** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
491 **
492 ** Reconstruct the named repository database from the core
493 ** records. Run this command after updating the fossil
@@ -716,11 +720,11 @@
716 db_finalize(&q);
717 }
718 }
719
720 /*
721 ** COMMAND: scrub
722 ** %fossil scrub ?OPTIONS? ?REPOSITORY?
723 **
724 ** The command removes sensitive information (such as passwords) from a
725 ** repository so that the respository can be sent to an untrusted reader.
726 **
@@ -850,11 +854,11 @@
850 }
851 fossil_mbcs_free(zMbcsPath);
852 }
853
854 /*
855 ** COMMAND: reconstruct
856 **
857 ** Usage: %fossil reconstruct FILENAME DIRECTORY
858 **
859 ** This command studies the artifacts (files) in DIRECTORY and
860 ** reconstructs the fossil record from them. It places the new
@@ -911,11 +915,11 @@
911 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
912 fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
913 }
914
915 /*
916 ** COMMAND: deconstruct
917 **
918 ** Usage %fossil deconstruct ?OPTIONS? DESTINATION
919 **
920 **
921 ** This command exports all artifacts of a given repository and
922
--- src/rebuild.c
+++ src/rebuild.c
@@ -370,11 +370,15 @@
370 " WHERE rid IN (SELECT rid FROM shun JOIN blob USING(uuid))"
371 );
372 db_multi_exec(
373 "DELETE FROM config WHERE name IN ('remote-code', 'remote-maxid')"
374 );
375
376 /* The following should be count(*) instead of max(rid). max(rid) is
377 ** an adequate approximation, however, and is much faster for large
378 ** repositories. */
379 totalSize = db_int(0, "SELECT max(rid) FROM blob");
380 incrSize = totalSize/100;
381 totalSize += incrSize*2;
382 db_prepare(&s,
383 "SELECT rid, size FROM blob /*scan*/"
384 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
@@ -483,11 +487,11 @@
487
488 db_end_transaction(0);
489 }
490
491 /*
492 ** COMMAND: rebuild
493 **
494 ** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
495 **
496 ** Reconstruct the named repository database from the core
497 ** records. Run this command after updating the fossil
@@ -716,11 +720,11 @@
720 db_finalize(&q);
721 }
722 }
723
724 /*
725 ** COMMAND: scrub*
726 ** %fossil scrub ?OPTIONS? ?REPOSITORY?
727 **
728 ** The command removes sensitive information (such as passwords) from a
729 ** repository so that the respository can be sent to an untrusted reader.
730 **
@@ -850,11 +854,11 @@
854 }
855 fossil_mbcs_free(zMbcsPath);
856 }
857
858 /*
859 ** COMMAND: reconstruct*
860 **
861 ** Usage: %fossil reconstruct FILENAME DIRECTORY
862 **
863 ** This command studies the artifacts (files) in DIRECTORY and
864 ** reconstructs the fossil record from them. It places the new
@@ -911,11 +915,11 @@
915 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
916 fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
917 }
918
919 /*
920 ** COMMAND: deconstruct*
921 **
922 ** Usage %fossil deconstruct ?OPTIONS? DESTINATION
923 **
924 **
925 ** This command exports all artifacts of a given repository and
926
+1 -1
--- src/search.c
+++ src/search.c
@@ -165,11 +165,11 @@
165165
}
166166
167167
/*
168168
** Testing the search function.
169169
**
170
-** COMMAND: search
170
+** COMMAND: search*
171171
** %fossil search pattern...
172172
**
173173
** Search for timeline entries matching the pattern.
174174
*/
175175
void search_cmd(void){
176176
--- src/search.c
+++ src/search.c
@@ -165,11 +165,11 @@
165 }
166
167 /*
168 ** Testing the search function.
169 **
170 ** COMMAND: search
171 ** %fossil search pattern...
172 **
173 ** Search for timeline entries matching the pattern.
174 */
175 void search_cmd(void){
176
--- src/search.c
+++ src/search.c
@@ -165,11 +165,11 @@
165 }
166
167 /*
168 ** Testing the search function.
169 **
170 ** COMMAND: search*
171 ** %fossil search pattern...
172 **
173 ** Search for timeline entries matching the pattern.
174 */
175 void search_cmd(void){
176
+1 -1
--- src/sha1.c
+++ src/sha1.c
@@ -437,11 +437,11 @@
437437
sqlite3_result_text(context, sha1_shared_secret(zPw, zLogin, zProjid), -1,
438438
fossil_free);
439439
}
440440
441441
/*
442
-** COMMAND: sha1sum
442
+** COMMAND: sha1sum*
443443
** %fossil sha1sum FILE...
444444
**
445445
** Compute an SHA1 checksum of all files named on the command-line.
446446
** If an file is named "-" then take its content from standard input.
447447
*/
448448
--- src/sha1.c
+++ src/sha1.c
@@ -437,11 +437,11 @@
437 sqlite3_result_text(context, sha1_shared_secret(zPw, zLogin, zProjid), -1,
438 fossil_free);
439 }
440
441 /*
442 ** COMMAND: sha1sum
443 ** %fossil sha1sum FILE...
444 **
445 ** Compute an SHA1 checksum of all files named on the command-line.
446 ** If an file is named "-" then take its content from standard input.
447 */
448
--- src/sha1.c
+++ src/sha1.c
@@ -437,11 +437,11 @@
437 sqlite3_result_text(context, sha1_shared_secret(zPw, zLogin, zProjid), -1,
438 fossil_free);
439 }
440
441 /*
442 ** COMMAND: sha1sum*
443 ** %fossil sha1sum FILE...
444 **
445 ** Compute an SHA1 checksum of all files named on the command-line.
446 ** If an file is named "-" then take its content from standard input.
447 */
448
+98 -64
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -314,17 +314,10 @@
314314
#endif
315315
#ifdef HAVE_INTTYPES_H
316316
#include <inttypes.h>
317317
#endif
318318
319
-/*
320
-** The number of samples of an index that SQLite takes in order to
321
-** construct a histogram of the table content when running ANALYZE
322
-** and with SQLITE_ENABLE_STAT2
323
-*/
324
-#define SQLITE_INDEX_SAMPLES 10
325
-
326319
/*
327320
** The following macros are used to cast pointers to integers and
328321
** integers to pointers. The way you do this varies from one compiler
329322
** to the next, so we have developed the following set of #if statements
330323
** to generate appropriate macros for a wide range of compilers.
@@ -656,11 +649,11 @@
656649
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657650
** [sqlite_version()] and [sqlite_source_id()].
658651
*/
659652
#define SQLITE_VERSION "3.7.9"
660653
#define SQLITE_VERSION_NUMBER 3007009
661
-#define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
654
+#define SQLITE_SOURCE_ID "2011-10-29 19:25:08 5b82ec6fbbd2f4195ad06dd911de3817373ad5bf"
662655
663656
/*
664657
** CAPI3REF: Run-Time Library Version Numbers
665658
** KEYWORDS: sqlite3_version, sqlite3_sourceid
666659
**
@@ -8792,10 +8785,11 @@
87928785
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
87938786
SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
87948787
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
87958788
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
87968789
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
8790
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *);
87978791
87988792
/* Functions used to truncate the database file. */
87998793
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
88008794
88018795
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
@@ -10189,12 +10183,13 @@
1018910183
IndexSample *aSample; /* Samples of the left-most key */
1019010184
#endif
1019110185
};
1019210186
1019310187
/*
10194
-** Each sample stored in the sqlite_stat2 table is represented in memory
10195
-** using a structure of this type.
10188
+** Each sample stored in the sqlite_stat3 table is represented in memory
10189
+** using a structure of this type. See documentation at the top of the
10190
+** analyze.c source file for additional information.
1019610191
*/
1019710192
struct IndexSample {
1019810193
union {
1019910194
char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */
1020010195
double r; /* Value if eType is SQLITE_FLOAT */
@@ -12293,13 +12288,10 @@
1229312288
"ENABLE_OVERSIZE_CELL_CHECK",
1229412289
#endif
1229512290
#ifdef SQLITE_ENABLE_RTREE
1229612291
"ENABLE_RTREE",
1229712292
#endif
12298
-#ifdef SQLITE_ENABLE_STAT2
12299
- "ENABLE_STAT2",
12300
-#endif
1230112293
#ifdef SQLITE_ENABLE_STAT3
1230212294
"ENABLE_STAT3",
1230312295
#endif
1230412296
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
1230512297
"ENABLE_UNLOCK_NOTIFY",
@@ -12996,10 +12988,11 @@
1299612988
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
1299712989
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
1299812990
SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
1299912991
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
1300012992
SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
12993
+SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
1300112994
1300212995
#ifdef SQLITE_OMIT_MERGE_SORT
1300312996
# define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK
1300412997
# define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK
1300512998
# define sqlite3VdbeSorterClose(Y,Z)
@@ -29483,17 +29476,17 @@
2948329476
** "<path to db>-journal"
2948429477
** "<path to db>-wal"
2948529478
** "<path to db>-journalNN"
2948629479
** "<path to db>-walNN"
2948729480
**
29488
- ** where NN is a 4 digit decimal number. The NN naming schemes are
29481
+ ** where NN is a decimal number. The NN naming schemes are
2948929482
** used by the test_multiplex.c module.
2949029483
*/
2949129484
nDb = sqlite3Strlen30(zPath) - 1;
2949229485
#ifdef SQLITE_ENABLE_8_3_NAMES
29493
- while( nDb>0 && zPath[nDb]!='-' && zPath[nDb]!='/' ) nDb--;
29494
- if( nDb==0 || zPath[nDb]=='/' ) return SQLITE_OK;
29486
+ while( nDb>0 && !sqlite3Isalnum(zPath[nDb]) ) nDb--;
29487
+ if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
2949529488
#else
2949629489
while( zPath[nDb]!='-' ){
2949729490
assert( nDb>0 );
2949829491
assert( zPath[nDb]!='\n' );
2949929492
nDb--;
@@ -44163,10 +44156,17 @@
4416344156
pPager->pWal = 0;
4416444157
}
4416544158
}
4416644159
return rc;
4416744160
}
44161
+
44162
+/*
44163
+** Unless this is an in-memory or temporary database, clear the pager cache.
44164
+*/
44165
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
44166
+ if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
44167
+}
4416844168
4416944169
#ifdef SQLITE_HAS_CODEC
4417044170
/*
4417144171
** This function is called by the wal module when writing page content
4417244172
** into the log file.
@@ -57006,10 +57006,12 @@
5700657006
sqlite3_backup_step(&b, 0x7FFFFFFF);
5700757007
assert( b.rc!=SQLITE_OK );
5700857008
rc = sqlite3_backup_finish(&b);
5700957009
if( rc==SQLITE_OK ){
5701057010
pTo->pBt->pageSizeFixed = 0;
57011
+ }else{
57012
+ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
5701157013
}
5701257014
5701357015
assert( sqlite3BtreeIsInTrans(pTo)==0 );
5701457016
sqlite3BtreeLeave(pFrom);
5701557017
sqlite3BtreeLeave(pTo);
@@ -60480,10 +60482,34 @@
6048060482
** in p->rc. This routine sets that result back to SQLITE_OK.
6048160483
*/
6048260484
SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){
6048360485
p->rc = SQLITE_OK;
6048460486
}
60487
+
60488
+/*
60489
+** Copy the error code and error message belonging to the VDBE passed
60490
+** as the first argument to its database handle (so that they will be
60491
+** returned by calls to sqlite3_errcode() and sqlite3_errmsg()).
60492
+**
60493
+** This function does not clear the VDBE error code or message, just
60494
+** copies them to the database handle.
60495
+*/
60496
+SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
60497
+ sqlite3 *db = p->db;
60498
+ int rc = p->rc;
60499
+ if( p->zErrMsg ){
60500
+ u8 mallocFailed = db->mallocFailed;
60501
+ sqlite3BeginBenignMalloc();
60502
+ sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
60503
+ sqlite3EndBenignMalloc();
60504
+ db->mallocFailed = mallocFailed;
60505
+ db->errCode = rc;
60506
+ }else{
60507
+ sqlite3Error(db, rc, 0);
60508
+ }
60509
+ return rc;
60510
+}
6048560511
6048660512
/*
6048760513
** Clean up a VDBE after execution but do not delete the VDBE just yet.
6048860514
** Write any error messages into *pzErrMsg. Return the result code.
6048960515
**
@@ -60508,22 +60534,13 @@
6050860534
** and error message from the VDBE into the main database structure. But
6050960535
** if the VDBE has just been set to run but has not actually executed any
6051060536
** instructions yet, leave the main database error information unchanged.
6051160537
*/
6051260538
if( p->pc>=0 ){
60513
- if( p->zErrMsg ){
60514
- sqlite3BeginBenignMalloc();
60515
- sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,SQLITE_TRANSIENT);
60516
- sqlite3EndBenignMalloc();
60517
- db->errCode = p->rc;
60518
- sqlite3DbFree(db, p->zErrMsg);
60519
- p->zErrMsg = 0;
60520
- }else if( p->rc ){
60521
- sqlite3Error(db, p->rc, 0);
60522
- }else{
60523
- sqlite3Error(db, SQLITE_OK, 0);
60524
- }
60539
+ sqlite3VdbeTransferError(p);
60540
+ sqlite3DbFree(db, p->zErrMsg);
60541
+ p->zErrMsg = 0;
6052560542
if( p->runOnlyOnce ) p->expired = 1;
6052660543
}else if( p->rc && p->expired ){
6052760544
/* The expired flag was set on the VDBE before the first call
6052860545
** to sqlite3_step(). For consistency (since sqlite3_step() was
6052960546
** called), set the database error in this case as well.
@@ -61865,11 +61882,11 @@
6186561882
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
6186661883
/* If this statement was prepared using sqlite3_prepare_v2(), and an
6186761884
** error has occured, then return the error code in p->rc to the
6186861885
** caller. Set the error code in the database handle to the same value.
6186961886
*/
61870
- rc = db->errCode = p->rc;
61887
+ rc = sqlite3VdbeTransferError(p);
6187161888
}
6187261889
return (rc&db->errMask);
6187361890
}
6187461891
6187561892
/*
@@ -67765,13 +67782,12 @@
6776567782
6776667783
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
6776767784
u.bn.pC = p->apCsr[pOp->p1];
6776867785
assert( u.bn.pC!=0 );
6776967786
u.bn.pCrsr = u.bn.pC->pCursor;
67770
- if( NEVER(u.bn.pCrsr==0) ){
67771
- u.bn.res = 1;
67772
- }else{
67787
+ u.bn.res = 0;
67788
+ if( ALWAYS(u.bn.pCrsr!=0) ){
6777367789
rc = sqlite3BtreeLast(u.bn.pCrsr, &u.bn.res);
6777467790
}
6777567791
u.bn.pC->nullRow = (u8)u.bn.res;
6777667792
u.bn.pC->deferredMoveto = 0;
6777767793
u.bn.pC->rowidIsValid = 0;
@@ -77610,20 +77626,20 @@
7761077626
#ifndef SQLITE_OMIT_ANALYZE
7761177627
7761277628
/*
7761377629
** This routine generates code that opens the sqlite_stat1 table for
7761477630
** writing with cursor iStatCur. If the library was built with the
77615
-** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is
77631
+** SQLITE_ENABLE_STAT3 macro defined, then the sqlite_stat3 table is
7761677632
** opened for writing using cursor (iStatCur+1)
7761777633
**
7761877634
** If the sqlite_stat1 tables does not previously exist, it is created.
77619
-** Similarly, if the sqlite_stat2 table does not exist and the library
77620
-** is compiled with SQLITE_ENABLE_STAT2 defined, it is created.
77635
+** Similarly, if the sqlite_stat3 table does not exist and the library
77636
+** is compiled with SQLITE_ENABLE_STAT3 defined, it is created.
7762177637
**
7762277638
** Argument zWhere may be a pointer to a buffer containing a table name,
7762377639
** or it may be a NULL pointer. If it is not NULL, then all entries in
77624
-** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated
77640
+** the sqlite_stat1 and (if applicable) sqlite_stat3 tables associated
7762577641
** with the named table are deleted. If zWhere==0, then code is generated
7762677642
** to delete all stat table entries.
7762777643
*/
7762877644
static void openStatTable(
7762977645
Parse *pParse, /* Parsing context */
@@ -81404,31 +81420,28 @@
8140481420
}
8140581421
#endif
8140681422
}
8140781423
8140881424
/*
81409
-** Remove entries from the sqlite_stat1 and sqlite_stat2 tables
81425
+** Remove entries from the sqlite_statN tables (for N in (1,2,3))
8141081426
** after a DROP INDEX or DROP TABLE command.
8141181427
*/
8141281428
static void sqlite3ClearStatTables(
8141381429
Parse *pParse, /* The parsing context */
8141481430
int iDb, /* The database number */
8141581431
const char *zType, /* "idx" or "tbl" */
8141681432
const char *zName /* Name of index or table */
8141781433
){
81418
- static const char *azStatTab[] = {
81419
- "sqlite_stat1",
81420
- "sqlite_stat2",
81421
- "sqlite_stat3",
81422
- };
8142381434
int i;
8142481435
const char *zDbName = pParse->db->aDb[iDb].zName;
81425
- for(i=0; i<ArraySize(azStatTab); i++){
81426
- if( sqlite3FindTable(pParse->db, azStatTab[i], zDbName) ){
81436
+ for(i=1; i<=3; i++){
81437
+ char zTab[24];
81438
+ sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
81439
+ if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
8142781440
sqlite3NestedParse(pParse,
8142881441
"DELETE FROM %Q.%s WHERE %s=%Q",
81429
- zDbName, azStatTab[i], zType, zName
81442
+ zDbName, zTab, zType, zName
8143081443
);
8143181444
}
8143281445
}
8143381446
}
8143481447
@@ -89250,12 +89263,14 @@
8925089263
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
8925189264
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
8925289265
int (*busy_timeout)(sqlite3*,int ms);
8925389266
int (*changes)(sqlite3*);
8925489267
int (*close)(sqlite3*);
89255
- int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
89256
- int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
89268
+ int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
89269
+ int eTextRep,const char*));
89270
+ int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
89271
+ int eTextRep,const void*));
8925789272
const void * (*column_blob)(sqlite3_stmt*,int iCol);
8925889273
int (*column_bytes)(sqlite3_stmt*,int iCol);
8925989274
int (*column_bytes16)(sqlite3_stmt*,int iCol);
8926089275
int (*column_count)(sqlite3_stmt*pStmt);
8926189276
const char * (*column_database_name)(sqlite3_stmt*,int);
@@ -89276,14 +89291,22 @@
8927689291
int (*column_type)(sqlite3_stmt*,int iCol);
8927789292
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
8927889293
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
8927989294
int (*complete)(const char*sql);
8928089295
int (*complete16)(const void*sql);
89281
- int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
89282
- int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
89283
- int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
89284
- int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
89296
+ int (*create_collation)(sqlite3*,const char*,int,void*,
89297
+ int(*)(void*,int,const void*,int,const void*));
89298
+ int (*create_collation16)(sqlite3*,const void*,int,void*,
89299
+ int(*)(void*,int,const void*,int,const void*));
89300
+ int (*create_function)(sqlite3*,const char*,int,int,void*,
89301
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
89302
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
89303
+ void (*xFinal)(sqlite3_context*));
89304
+ int (*create_function16)(sqlite3*,const void*,int,int,void*,
89305
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
89306
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
89307
+ void (*xFinal)(sqlite3_context*));
8928589308
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
8928689309
int (*data_count)(sqlite3_stmt*pStmt);
8928789310
sqlite3 * (*db_handle)(sqlite3_stmt*);
8928889311
int (*declare_vtab)(sqlite3*,const char*);
8928989312
int (*enable_shared_cache)(int);
@@ -89324,20 +89347,23 @@
8932489347
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
8932589348
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
8932689349
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
8932789350
void (*result_value)(sqlite3_context*,sqlite3_value*);
8932889351
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
89329
- int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
89352
+ int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
89353
+ const char*,const char*),void*);
8933089354
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
8933189355
char * (*snprintf)(int,char*,const char*,...);
8933289356
int (*step)(sqlite3_stmt*);
89333
- int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
89357
+ int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
89358
+ char const**,char const**,int*,int*,int*);
8933489359
void (*thread_cleanup)(void);
8933589360
int (*total_changes)(sqlite3*);
8933689361
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
8933789362
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
89338
- void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
89363
+ void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
89364
+ sqlite_int64),void*);
8933989365
void * (*user_data)(sqlite3_context*);
8934089366
const void * (*value_blob)(sqlite3_value*);
8934189367
int (*value_bytes)(sqlite3_value*);
8934289368
int (*value_bytes16)(sqlite3_value*);
8934389369
double (*value_double)(sqlite3_value*);
@@ -89355,19 +89381,23 @@
8935589381
/* Added by 3.3.13 */
8935689382
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
8935789383
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
8935889384
int (*clear_bindings)(sqlite3_stmt*);
8935989385
/* Added by 3.4.1 */
89360
- int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *));
89386
+ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
89387
+ void (*xDestroy)(void *));
8936189388
/* Added by 3.5.0 */
8936289389
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
8936389390
int (*blob_bytes)(sqlite3_blob*);
8936489391
int (*blob_close)(sqlite3_blob*);
89365
- int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**);
89392
+ int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
89393
+ int,sqlite3_blob**);
8936689394
int (*blob_read)(sqlite3_blob*,void*,int,int);
8936789395
int (*blob_write)(sqlite3_blob*,const void*,int,int);
89368
- int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
89396
+ int (*create_collation_v2)(sqlite3*,const char*,int,void*,
89397
+ int(*)(void*,int,const void*,int,const void*),
89398
+ void(*)(void*));
8936989399
int (*file_control)(sqlite3*,const char*,int,void*);
8937089400
sqlite3_int64 (*memory_highwater)(int);
8937189401
sqlite3_int64 (*memory_used)(void);
8937289402
sqlite3_mutex *(*mutex_alloc)(int);
8937389403
void (*mutex_enter)(sqlite3_mutex*);
@@ -89399,11 +89429,15 @@
8939989429
int (*backup_pagecount)(sqlite3_backup*);
8940089430
int (*backup_remaining)(sqlite3_backup*);
8940189431
int (*backup_step)(sqlite3_backup*,int);
8940289432
const char *(*compileoption_get)(int);
8940389433
int (*compileoption_used)(const char*);
89404
- int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*));
89434
+ int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
89435
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
89436
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
89437
+ void (*xFinal)(sqlite3_context*),
89438
+ void(*xDestroy)(void*));
8940589439
int (*db_config)(sqlite3*,int,...);
8940689440
sqlite3_mutex *(*db_mutex)(sqlite3*);
8940789441
int (*db_status)(sqlite3*,int,int*,int*,int);
8940889442
int (*extended_errcode)(sqlite3*);
8940989443
void (*log)(int,const char*,...);
@@ -100485,11 +100519,11 @@
100485100519
if( db->aVTrans ){
100486100520
int i;
100487100521
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
100488100522
VTable *pVTab = db->aVTrans[i];
100489100523
const sqlite3_module *pMod = pVTab->pMod->pModule;
100490
- if( pMod->iVersion>=2 ){
100524
+ if( pVTab->pVtab && pMod->iVersion>=2 ){
100491100525
int (*xMethod)(sqlite3_vtab *, int);
100492100526
switch( op ){
100493100527
case SAVEPOINT_BEGIN:
100494100528
xMethod = pMod->xSavepoint;
100495100529
pVTab->iSavepoint = iSavepoint+1;
@@ -100500,11 +100534,11 @@
100500100534
default:
100501100535
xMethod = pMod->xRelease;
100502100536
break;
100503100537
}
100504100538
if( xMethod && pVTab->iSavepoint>iSavepoint ){
100505
- rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint);
100539
+ rc = xMethod(pVTab->pVtab, iSavepoint);
100506100540
}
100507100541
}
100508100542
}
100509100543
}
100510100544
return rc;
@@ -101367,11 +101401,11 @@
101367101401
int iCol = pRight->iColumn;
101368101402
pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
101369101403
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
101370101404
z = (char *)sqlite3_value_text(pVal);
101371101405
}
101372
- sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-31526-56213 */
101406
+ sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
101373101407
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
101374101408
}else if( op==TK_STRING ){
101375101409
z = pRight->u.zToken;
101376101410
}
101377101411
if( z ){
@@ -101385,11 +101419,11 @@
101385101419
pPrefix = sqlite3Expr(db, TK_STRING, z);
101386101420
if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
101387101421
*ppPrefix = pPrefix;
101388101422
if( op==TK_VARIABLE ){
101389101423
Vdbe *v = pParse->pVdbe;
101390
- sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-31526-56213 */
101424
+ sqlite3VdbeSetVarmask(v, pRight->iColumn);
101391101425
if( *pisComplete && pRight->u.zToken[1] ){
101392101426
/* If the rhs of the LIKE expression is a variable, and the current
101393101427
** value of the variable means there is no need to invoke the LIKE
101394101428
** function, then no OP_Variable will be added to the program.
101395101429
** This causes problems for the sqlite3_bind_parameter_name()
@@ -103299,11 +103333,11 @@
103299103333
){
103300103334
if( pExpr->op==TK_VARIABLE
103301103335
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
103302103336
){
103303103337
int iVar = pExpr->iColumn;
103304
- sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-31526-56213 */
103338
+ sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
103305103339
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
103306103340
return SQLITE_OK;
103307103341
}
103308103342
return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
103309103343
}
@@ -103829,11 +103863,11 @@
103829103863
** a table or index. The actual times can vary, with the size of
103830103864
** records being an important factor. Both moves and searches are
103831103865
** slower with larger records, presumably because fewer records fit
103832103866
** on one page and hence more pages have to be fetched.
103833103867
**
103834
- ** The ANALYZE command and the sqlite_stat1 and sqlite_stat2 tables do
103868
+ ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do
103835103869
** not give us data on the relative sizes of table and index records.
103836103870
** So this computation assumes table records are about twice as big
103837103871
** as index records
103838103872
*/
103839103873
if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ){
103840103874
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -314,17 +314,10 @@
314 #endif
315 #ifdef HAVE_INTTYPES_H
316 #include <inttypes.h>
317 #endif
318
319 /*
320 ** The number of samples of an index that SQLite takes in order to
321 ** construct a histogram of the table content when running ANALYZE
322 ** and with SQLITE_ENABLE_STAT2
323 */
324 #define SQLITE_INDEX_SAMPLES 10
325
326 /*
327 ** The following macros are used to cast pointers to integers and
328 ** integers to pointers. The way you do this varies from one compiler
329 ** to the next, so we have developed the following set of #if statements
330 ** to generate appropriate macros for a wide range of compilers.
@@ -656,11 +649,11 @@
656 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657 ** [sqlite_version()] and [sqlite_source_id()].
658 */
659 #define SQLITE_VERSION "3.7.9"
660 #define SQLITE_VERSION_NUMBER 3007009
661 #define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
662
663 /*
664 ** CAPI3REF: Run-Time Library Version Numbers
665 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
666 **
@@ -8792,10 +8785,11 @@
8792 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
8793 SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
8794 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
8795 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
8796 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
 
8797
8798 /* Functions used to truncate the database file. */
8799 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
8800
8801 #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
@@ -10189,12 +10183,13 @@
10189 IndexSample *aSample; /* Samples of the left-most key */
10190 #endif
10191 };
10192
10193 /*
10194 ** Each sample stored in the sqlite_stat2 table is represented in memory
10195 ** using a structure of this type.
 
10196 */
10197 struct IndexSample {
10198 union {
10199 char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */
10200 double r; /* Value if eType is SQLITE_FLOAT */
@@ -12293,13 +12288,10 @@
12293 "ENABLE_OVERSIZE_CELL_CHECK",
12294 #endif
12295 #ifdef SQLITE_ENABLE_RTREE
12296 "ENABLE_RTREE",
12297 #endif
12298 #ifdef SQLITE_ENABLE_STAT2
12299 "ENABLE_STAT2",
12300 #endif
12301 #ifdef SQLITE_ENABLE_STAT3
12302 "ENABLE_STAT3",
12303 #endif
12304 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
12305 "ENABLE_UNLOCK_NOTIFY",
@@ -12996,10 +12988,11 @@
12996 SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
12997 SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
12998 SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
12999 SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
13000 SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
 
13001
13002 #ifdef SQLITE_OMIT_MERGE_SORT
13003 # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK
13004 # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK
13005 # define sqlite3VdbeSorterClose(Y,Z)
@@ -29483,17 +29476,17 @@
29483 ** "<path to db>-journal"
29484 ** "<path to db>-wal"
29485 ** "<path to db>-journalNN"
29486 ** "<path to db>-walNN"
29487 **
29488 ** where NN is a 4 digit decimal number. The NN naming schemes are
29489 ** used by the test_multiplex.c module.
29490 */
29491 nDb = sqlite3Strlen30(zPath) - 1;
29492 #ifdef SQLITE_ENABLE_8_3_NAMES
29493 while( nDb>0 && zPath[nDb]!='-' && zPath[nDb]!='/' ) nDb--;
29494 if( nDb==0 || zPath[nDb]=='/' ) return SQLITE_OK;
29495 #else
29496 while( zPath[nDb]!='-' ){
29497 assert( nDb>0 );
29498 assert( zPath[nDb]!='\n' );
29499 nDb--;
@@ -44163,10 +44156,17 @@
44163 pPager->pWal = 0;
44164 }
44165 }
44166 return rc;
44167 }
 
 
 
 
 
 
 
44168
44169 #ifdef SQLITE_HAS_CODEC
44170 /*
44171 ** This function is called by the wal module when writing page content
44172 ** into the log file.
@@ -57006,10 +57006,12 @@
57006 sqlite3_backup_step(&b, 0x7FFFFFFF);
57007 assert( b.rc!=SQLITE_OK );
57008 rc = sqlite3_backup_finish(&b);
57009 if( rc==SQLITE_OK ){
57010 pTo->pBt->pageSizeFixed = 0;
 
 
57011 }
57012
57013 assert( sqlite3BtreeIsInTrans(pTo)==0 );
57014 sqlite3BtreeLeave(pFrom);
57015 sqlite3BtreeLeave(pTo);
@@ -60480,10 +60482,34 @@
60480 ** in p->rc. This routine sets that result back to SQLITE_OK.
60481 */
60482 SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){
60483 p->rc = SQLITE_OK;
60484 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60485
60486 /*
60487 ** Clean up a VDBE after execution but do not delete the VDBE just yet.
60488 ** Write any error messages into *pzErrMsg. Return the result code.
60489 **
@@ -60508,22 +60534,13 @@
60508 ** and error message from the VDBE into the main database structure. But
60509 ** if the VDBE has just been set to run but has not actually executed any
60510 ** instructions yet, leave the main database error information unchanged.
60511 */
60512 if( p->pc>=0 ){
60513 if( p->zErrMsg ){
60514 sqlite3BeginBenignMalloc();
60515 sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,SQLITE_TRANSIENT);
60516 sqlite3EndBenignMalloc();
60517 db->errCode = p->rc;
60518 sqlite3DbFree(db, p->zErrMsg);
60519 p->zErrMsg = 0;
60520 }else if( p->rc ){
60521 sqlite3Error(db, p->rc, 0);
60522 }else{
60523 sqlite3Error(db, SQLITE_OK, 0);
60524 }
60525 if( p->runOnlyOnce ) p->expired = 1;
60526 }else if( p->rc && p->expired ){
60527 /* The expired flag was set on the VDBE before the first call
60528 ** to sqlite3_step(). For consistency (since sqlite3_step() was
60529 ** called), set the database error in this case as well.
@@ -61865,11 +61882,11 @@
61865 if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
61866 /* If this statement was prepared using sqlite3_prepare_v2(), and an
61867 ** error has occured, then return the error code in p->rc to the
61868 ** caller. Set the error code in the database handle to the same value.
61869 */
61870 rc = db->errCode = p->rc;
61871 }
61872 return (rc&db->errMask);
61873 }
61874
61875 /*
@@ -67765,13 +67782,12 @@
67765
67766 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
67767 u.bn.pC = p->apCsr[pOp->p1];
67768 assert( u.bn.pC!=0 );
67769 u.bn.pCrsr = u.bn.pC->pCursor;
67770 if( NEVER(u.bn.pCrsr==0) ){
67771 u.bn.res = 1;
67772 }else{
67773 rc = sqlite3BtreeLast(u.bn.pCrsr, &u.bn.res);
67774 }
67775 u.bn.pC->nullRow = (u8)u.bn.res;
67776 u.bn.pC->deferredMoveto = 0;
67777 u.bn.pC->rowidIsValid = 0;
@@ -77610,20 +77626,20 @@
77610 #ifndef SQLITE_OMIT_ANALYZE
77611
77612 /*
77613 ** This routine generates code that opens the sqlite_stat1 table for
77614 ** writing with cursor iStatCur. If the library was built with the
77615 ** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is
77616 ** opened for writing using cursor (iStatCur+1)
77617 **
77618 ** If the sqlite_stat1 tables does not previously exist, it is created.
77619 ** Similarly, if the sqlite_stat2 table does not exist and the library
77620 ** is compiled with SQLITE_ENABLE_STAT2 defined, it is created.
77621 **
77622 ** Argument zWhere may be a pointer to a buffer containing a table name,
77623 ** or it may be a NULL pointer. If it is not NULL, then all entries in
77624 ** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated
77625 ** with the named table are deleted. If zWhere==0, then code is generated
77626 ** to delete all stat table entries.
77627 */
77628 static void openStatTable(
77629 Parse *pParse, /* Parsing context */
@@ -81404,31 +81420,28 @@
81404 }
81405 #endif
81406 }
81407
81408 /*
81409 ** Remove entries from the sqlite_stat1 and sqlite_stat2 tables
81410 ** after a DROP INDEX or DROP TABLE command.
81411 */
81412 static void sqlite3ClearStatTables(
81413 Parse *pParse, /* The parsing context */
81414 int iDb, /* The database number */
81415 const char *zType, /* "idx" or "tbl" */
81416 const char *zName /* Name of index or table */
81417 ){
81418 static const char *azStatTab[] = {
81419 "sqlite_stat1",
81420 "sqlite_stat2",
81421 "sqlite_stat3",
81422 };
81423 int i;
81424 const char *zDbName = pParse->db->aDb[iDb].zName;
81425 for(i=0; i<ArraySize(azStatTab); i++){
81426 if( sqlite3FindTable(pParse->db, azStatTab[i], zDbName) ){
 
 
81427 sqlite3NestedParse(pParse,
81428 "DELETE FROM %Q.%s WHERE %s=%Q",
81429 zDbName, azStatTab[i], zType, zName
81430 );
81431 }
81432 }
81433 }
81434
@@ -89250,12 +89263,14 @@
89250 int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
89251 int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
89252 int (*busy_timeout)(sqlite3*,int ms);
89253 int (*changes)(sqlite3*);
89254 int (*close)(sqlite3*);
89255 int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
89256 int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
 
 
89257 const void * (*column_blob)(sqlite3_stmt*,int iCol);
89258 int (*column_bytes)(sqlite3_stmt*,int iCol);
89259 int (*column_bytes16)(sqlite3_stmt*,int iCol);
89260 int (*column_count)(sqlite3_stmt*pStmt);
89261 const char * (*column_database_name)(sqlite3_stmt*,int);
@@ -89276,14 +89291,22 @@
89276 int (*column_type)(sqlite3_stmt*,int iCol);
89277 sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
89278 void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
89279 int (*complete)(const char*sql);
89280 int (*complete16)(const void*sql);
89281 int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
89282 int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
89283 int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
89284 int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
 
 
 
 
 
 
 
 
89285 int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
89286 int (*data_count)(sqlite3_stmt*pStmt);
89287 sqlite3 * (*db_handle)(sqlite3_stmt*);
89288 int (*declare_vtab)(sqlite3*,const char*);
89289 int (*enable_shared_cache)(int);
@@ -89324,20 +89347,23 @@
89324 void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
89325 void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
89326 void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
89327 void (*result_value)(sqlite3_context*,sqlite3_value*);
89328 void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
89329 int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
 
89330 void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
89331 char * (*snprintf)(int,char*,const char*,...);
89332 int (*step)(sqlite3_stmt*);
89333 int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
 
89334 void (*thread_cleanup)(void);
89335 int (*total_changes)(sqlite3*);
89336 void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
89337 int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
89338 void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
 
89339 void * (*user_data)(sqlite3_context*);
89340 const void * (*value_blob)(sqlite3_value*);
89341 int (*value_bytes)(sqlite3_value*);
89342 int (*value_bytes16)(sqlite3_value*);
89343 double (*value_double)(sqlite3_value*);
@@ -89355,19 +89381,23 @@
89355 /* Added by 3.3.13 */
89356 int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
89357 int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
89358 int (*clear_bindings)(sqlite3_stmt*);
89359 /* Added by 3.4.1 */
89360 int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *));
 
89361 /* Added by 3.5.0 */
89362 int (*bind_zeroblob)(sqlite3_stmt*,int,int);
89363 int (*blob_bytes)(sqlite3_blob*);
89364 int (*blob_close)(sqlite3_blob*);
89365 int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**);
 
89366 int (*blob_read)(sqlite3_blob*,void*,int,int);
89367 int (*blob_write)(sqlite3_blob*,const void*,int,int);
89368 int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
 
 
89369 int (*file_control)(sqlite3*,const char*,int,void*);
89370 sqlite3_int64 (*memory_highwater)(int);
89371 sqlite3_int64 (*memory_used)(void);
89372 sqlite3_mutex *(*mutex_alloc)(int);
89373 void (*mutex_enter)(sqlite3_mutex*);
@@ -89399,11 +89429,15 @@
89399 int (*backup_pagecount)(sqlite3_backup*);
89400 int (*backup_remaining)(sqlite3_backup*);
89401 int (*backup_step)(sqlite3_backup*,int);
89402 const char *(*compileoption_get)(int);
89403 int (*compileoption_used)(const char*);
89404 int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*));
 
 
 
 
89405 int (*db_config)(sqlite3*,int,...);
89406 sqlite3_mutex *(*db_mutex)(sqlite3*);
89407 int (*db_status)(sqlite3*,int,int*,int*,int);
89408 int (*extended_errcode)(sqlite3*);
89409 void (*log)(int,const char*,...);
@@ -100485,11 +100519,11 @@
100485 if( db->aVTrans ){
100486 int i;
100487 for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
100488 VTable *pVTab = db->aVTrans[i];
100489 const sqlite3_module *pMod = pVTab->pMod->pModule;
100490 if( pMod->iVersion>=2 ){
100491 int (*xMethod)(sqlite3_vtab *, int);
100492 switch( op ){
100493 case SAVEPOINT_BEGIN:
100494 xMethod = pMod->xSavepoint;
100495 pVTab->iSavepoint = iSavepoint+1;
@@ -100500,11 +100534,11 @@
100500 default:
100501 xMethod = pMod->xRelease;
100502 break;
100503 }
100504 if( xMethod && pVTab->iSavepoint>iSavepoint ){
100505 rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint);
100506 }
100507 }
100508 }
100509 }
100510 return rc;
@@ -101367,11 +101401,11 @@
101367 int iCol = pRight->iColumn;
101368 pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
101369 if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
101370 z = (char *)sqlite3_value_text(pVal);
101371 }
101372 sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-31526-56213 */
101373 assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
101374 }else if( op==TK_STRING ){
101375 z = pRight->u.zToken;
101376 }
101377 if( z ){
@@ -101385,11 +101419,11 @@
101385 pPrefix = sqlite3Expr(db, TK_STRING, z);
101386 if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
101387 *ppPrefix = pPrefix;
101388 if( op==TK_VARIABLE ){
101389 Vdbe *v = pParse->pVdbe;
101390 sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-31526-56213 */
101391 if( *pisComplete && pRight->u.zToken[1] ){
101392 /* If the rhs of the LIKE expression is a variable, and the current
101393 ** value of the variable means there is no need to invoke the LIKE
101394 ** function, then no OP_Variable will be added to the program.
101395 ** This causes problems for the sqlite3_bind_parameter_name()
@@ -103299,11 +103333,11 @@
103299 ){
103300 if( pExpr->op==TK_VARIABLE
103301 || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
103302 ){
103303 int iVar = pExpr->iColumn;
103304 sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-31526-56213 */
103305 *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
103306 return SQLITE_OK;
103307 }
103308 return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
103309 }
@@ -103829,11 +103863,11 @@
103829 ** a table or index. The actual times can vary, with the size of
103830 ** records being an important factor. Both moves and searches are
103831 ** slower with larger records, presumably because fewer records fit
103832 ** on one page and hence more pages have to be fetched.
103833 **
103834 ** The ANALYZE command and the sqlite_stat1 and sqlite_stat2 tables do
103835 ** not give us data on the relative sizes of table and index records.
103836 ** So this computation assumes table records are about twice as big
103837 ** as index records
103838 */
103839 if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ){
103840
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -314,17 +314,10 @@
314 #endif
315 #ifdef HAVE_INTTYPES_H
316 #include <inttypes.h>
317 #endif
318
 
 
 
 
 
 
 
319 /*
320 ** The following macros are used to cast pointers to integers and
321 ** integers to pointers. The way you do this varies from one compiler
322 ** to the next, so we have developed the following set of #if statements
323 ** to generate appropriate macros for a wide range of compilers.
@@ -656,11 +649,11 @@
649 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
650 ** [sqlite_version()] and [sqlite_source_id()].
651 */
652 #define SQLITE_VERSION "3.7.9"
653 #define SQLITE_VERSION_NUMBER 3007009
654 #define SQLITE_SOURCE_ID "2011-10-29 19:25:08 5b82ec6fbbd2f4195ad06dd911de3817373ad5bf"
655
656 /*
657 ** CAPI3REF: Run-Time Library Version Numbers
658 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
659 **
@@ -8792,10 +8785,11 @@
8785 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
8786 SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
8787 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
8788 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
8789 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
8790 SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *);
8791
8792 /* Functions used to truncate the database file. */
8793 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
8794
8795 #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
@@ -10189,12 +10183,13 @@
10183 IndexSample *aSample; /* Samples of the left-most key */
10184 #endif
10185 };
10186
10187 /*
10188 ** Each sample stored in the sqlite_stat3 table is represented in memory
10189 ** using a structure of this type. See documentation at the top of the
10190 ** analyze.c source file for additional information.
10191 */
10192 struct IndexSample {
10193 union {
10194 char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */
10195 double r; /* Value if eType is SQLITE_FLOAT */
@@ -12293,13 +12288,10 @@
12288 "ENABLE_OVERSIZE_CELL_CHECK",
12289 #endif
12290 #ifdef SQLITE_ENABLE_RTREE
12291 "ENABLE_RTREE",
12292 #endif
 
 
 
12293 #ifdef SQLITE_ENABLE_STAT3
12294 "ENABLE_STAT3",
12295 #endif
12296 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
12297 "ENABLE_UNLOCK_NOTIFY",
@@ -12996,10 +12988,11 @@
12988 SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
12989 SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
12990 SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
12991 SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
12992 SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
12993 SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
12994
12995 #ifdef SQLITE_OMIT_MERGE_SORT
12996 # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK
12997 # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK
12998 # define sqlite3VdbeSorterClose(Y,Z)
@@ -29483,17 +29476,17 @@
29476 ** "<path to db>-journal"
29477 ** "<path to db>-wal"
29478 ** "<path to db>-journalNN"
29479 ** "<path to db>-walNN"
29480 **
29481 ** where NN is a decimal number. The NN naming schemes are
29482 ** used by the test_multiplex.c module.
29483 */
29484 nDb = sqlite3Strlen30(zPath) - 1;
29485 #ifdef SQLITE_ENABLE_8_3_NAMES
29486 while( nDb>0 && !sqlite3Isalnum(zPath[nDb]) ) nDb--;
29487 if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
29488 #else
29489 while( zPath[nDb]!='-' ){
29490 assert( nDb>0 );
29491 assert( zPath[nDb]!='\n' );
29492 nDb--;
@@ -44163,10 +44156,17 @@
44156 pPager->pWal = 0;
44157 }
44158 }
44159 return rc;
44160 }
44161
44162 /*
44163 ** Unless this is an in-memory or temporary database, clear the pager cache.
44164 */
44165 SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
44166 if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
44167 }
44168
44169 #ifdef SQLITE_HAS_CODEC
44170 /*
44171 ** This function is called by the wal module when writing page content
44172 ** into the log file.
@@ -57006,10 +57006,12 @@
57006 sqlite3_backup_step(&b, 0x7FFFFFFF);
57007 assert( b.rc!=SQLITE_OK );
57008 rc = sqlite3_backup_finish(&b);
57009 if( rc==SQLITE_OK ){
57010 pTo->pBt->pageSizeFixed = 0;
57011 }else{
57012 sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
57013 }
57014
57015 assert( sqlite3BtreeIsInTrans(pTo)==0 );
57016 sqlite3BtreeLeave(pFrom);
57017 sqlite3BtreeLeave(pTo);
@@ -60480,10 +60482,34 @@
60482 ** in p->rc. This routine sets that result back to SQLITE_OK.
60483 */
60484 SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){
60485 p->rc = SQLITE_OK;
60486 }
60487
60488 /*
60489 ** Copy the error code and error message belonging to the VDBE passed
60490 ** as the first argument to its database handle (so that they will be
60491 ** returned by calls to sqlite3_errcode() and sqlite3_errmsg()).
60492 **
60493 ** This function does not clear the VDBE error code or message, just
60494 ** copies them to the database handle.
60495 */
60496 SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
60497 sqlite3 *db = p->db;
60498 int rc = p->rc;
60499 if( p->zErrMsg ){
60500 u8 mallocFailed = db->mallocFailed;
60501 sqlite3BeginBenignMalloc();
60502 sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
60503 sqlite3EndBenignMalloc();
60504 db->mallocFailed = mallocFailed;
60505 db->errCode = rc;
60506 }else{
60507 sqlite3Error(db, rc, 0);
60508 }
60509 return rc;
60510 }
60511
60512 /*
60513 ** Clean up a VDBE after execution but do not delete the VDBE just yet.
60514 ** Write any error messages into *pzErrMsg. Return the result code.
60515 **
@@ -60508,22 +60534,13 @@
60534 ** and error message from the VDBE into the main database structure. But
60535 ** if the VDBE has just been set to run but has not actually executed any
60536 ** instructions yet, leave the main database error information unchanged.
60537 */
60538 if( p->pc>=0 ){
60539 sqlite3VdbeTransferError(p);
60540 sqlite3DbFree(db, p->zErrMsg);
60541 p->zErrMsg = 0;
 
 
 
 
 
 
 
 
 
60542 if( p->runOnlyOnce ) p->expired = 1;
60543 }else if( p->rc && p->expired ){
60544 /* The expired flag was set on the VDBE before the first call
60545 ** to sqlite3_step(). For consistency (since sqlite3_step() was
60546 ** called), set the database error in this case as well.
@@ -61865,11 +61882,11 @@
61882 if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
61883 /* If this statement was prepared using sqlite3_prepare_v2(), and an
61884 ** error has occured, then return the error code in p->rc to the
61885 ** caller. Set the error code in the database handle to the same value.
61886 */
61887 rc = sqlite3VdbeTransferError(p);
61888 }
61889 return (rc&db->errMask);
61890 }
61891
61892 /*
@@ -67765,13 +67782,12 @@
67782
67783 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
67784 u.bn.pC = p->apCsr[pOp->p1];
67785 assert( u.bn.pC!=0 );
67786 u.bn.pCrsr = u.bn.pC->pCursor;
67787 u.bn.res = 0;
67788 if( ALWAYS(u.bn.pCrsr!=0) ){
 
67789 rc = sqlite3BtreeLast(u.bn.pCrsr, &u.bn.res);
67790 }
67791 u.bn.pC->nullRow = (u8)u.bn.res;
67792 u.bn.pC->deferredMoveto = 0;
67793 u.bn.pC->rowidIsValid = 0;
@@ -77610,20 +77626,20 @@
77626 #ifndef SQLITE_OMIT_ANALYZE
77627
77628 /*
77629 ** This routine generates code that opens the sqlite_stat1 table for
77630 ** writing with cursor iStatCur. If the library was built with the
77631 ** SQLITE_ENABLE_STAT3 macro defined, then the sqlite_stat3 table is
77632 ** opened for writing using cursor (iStatCur+1)
77633 **
77634 ** If the sqlite_stat1 tables does not previously exist, it is created.
77635 ** Similarly, if the sqlite_stat3 table does not exist and the library
77636 ** is compiled with SQLITE_ENABLE_STAT3 defined, it is created.
77637 **
77638 ** Argument zWhere may be a pointer to a buffer containing a table name,
77639 ** or it may be a NULL pointer. If it is not NULL, then all entries in
77640 ** the sqlite_stat1 and (if applicable) sqlite_stat3 tables associated
77641 ** with the named table are deleted. If zWhere==0, then code is generated
77642 ** to delete all stat table entries.
77643 */
77644 static void openStatTable(
77645 Parse *pParse, /* Parsing context */
@@ -81404,31 +81420,28 @@
81420 }
81421 #endif
81422 }
81423
81424 /*
81425 ** Remove entries from the sqlite_statN tables (for N in (1,2,3))
81426 ** after a DROP INDEX or DROP TABLE command.
81427 */
81428 static void sqlite3ClearStatTables(
81429 Parse *pParse, /* The parsing context */
81430 int iDb, /* The database number */
81431 const char *zType, /* "idx" or "tbl" */
81432 const char *zName /* Name of index or table */
81433 ){
 
 
 
 
 
81434 int i;
81435 const char *zDbName = pParse->db->aDb[iDb].zName;
81436 for(i=1; i<=3; i++){
81437 char zTab[24];
81438 sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
81439 if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
81440 sqlite3NestedParse(pParse,
81441 "DELETE FROM %Q.%s WHERE %s=%Q",
81442 zDbName, zTab, zType, zName
81443 );
81444 }
81445 }
81446 }
81447
@@ -89250,12 +89263,14 @@
89263 int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
89264 int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
89265 int (*busy_timeout)(sqlite3*,int ms);
89266 int (*changes)(sqlite3*);
89267 int (*close)(sqlite3*);
89268 int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
89269 int eTextRep,const char*));
89270 int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
89271 int eTextRep,const void*));
89272 const void * (*column_blob)(sqlite3_stmt*,int iCol);
89273 int (*column_bytes)(sqlite3_stmt*,int iCol);
89274 int (*column_bytes16)(sqlite3_stmt*,int iCol);
89275 int (*column_count)(sqlite3_stmt*pStmt);
89276 const char * (*column_database_name)(sqlite3_stmt*,int);
@@ -89276,14 +89291,22 @@
89291 int (*column_type)(sqlite3_stmt*,int iCol);
89292 sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
89293 void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
89294 int (*complete)(const char*sql);
89295 int (*complete16)(const void*sql);
89296 int (*create_collation)(sqlite3*,const char*,int,void*,
89297 int(*)(void*,int,const void*,int,const void*));
89298 int (*create_collation16)(sqlite3*,const void*,int,void*,
89299 int(*)(void*,int,const void*,int,const void*));
89300 int (*create_function)(sqlite3*,const char*,int,int,void*,
89301 void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
89302 void (*xStep)(sqlite3_context*,int,sqlite3_value**),
89303 void (*xFinal)(sqlite3_context*));
89304 int (*create_function16)(sqlite3*,const void*,int,int,void*,
89305 void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
89306 void (*xStep)(sqlite3_context*,int,sqlite3_value**),
89307 void (*xFinal)(sqlite3_context*));
89308 int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
89309 int (*data_count)(sqlite3_stmt*pStmt);
89310 sqlite3 * (*db_handle)(sqlite3_stmt*);
89311 int (*declare_vtab)(sqlite3*,const char*);
89312 int (*enable_shared_cache)(int);
@@ -89324,20 +89347,23 @@
89347 void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
89348 void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
89349 void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
89350 void (*result_value)(sqlite3_context*,sqlite3_value*);
89351 void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
89352 int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
89353 const char*,const char*),void*);
89354 void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
89355 char * (*snprintf)(int,char*,const char*,...);
89356 int (*step)(sqlite3_stmt*);
89357 int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
89358 char const**,char const**,int*,int*,int*);
89359 void (*thread_cleanup)(void);
89360 int (*total_changes)(sqlite3*);
89361 void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
89362 int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
89363 void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
89364 sqlite_int64),void*);
89365 void * (*user_data)(sqlite3_context*);
89366 const void * (*value_blob)(sqlite3_value*);
89367 int (*value_bytes)(sqlite3_value*);
89368 int (*value_bytes16)(sqlite3_value*);
89369 double (*value_double)(sqlite3_value*);
@@ -89355,19 +89381,23 @@
89381 /* Added by 3.3.13 */
89382 int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
89383 int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
89384 int (*clear_bindings)(sqlite3_stmt*);
89385 /* Added by 3.4.1 */
89386 int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
89387 void (*xDestroy)(void *));
89388 /* Added by 3.5.0 */
89389 int (*bind_zeroblob)(sqlite3_stmt*,int,int);
89390 int (*blob_bytes)(sqlite3_blob*);
89391 int (*blob_close)(sqlite3_blob*);
89392 int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
89393 int,sqlite3_blob**);
89394 int (*blob_read)(sqlite3_blob*,void*,int,int);
89395 int (*blob_write)(sqlite3_blob*,const void*,int,int);
89396 int (*create_collation_v2)(sqlite3*,const char*,int,void*,
89397 int(*)(void*,int,const void*,int,const void*),
89398 void(*)(void*));
89399 int (*file_control)(sqlite3*,const char*,int,void*);
89400 sqlite3_int64 (*memory_highwater)(int);
89401 sqlite3_int64 (*memory_used)(void);
89402 sqlite3_mutex *(*mutex_alloc)(int);
89403 void (*mutex_enter)(sqlite3_mutex*);
@@ -89399,11 +89429,15 @@
89429 int (*backup_pagecount)(sqlite3_backup*);
89430 int (*backup_remaining)(sqlite3_backup*);
89431 int (*backup_step)(sqlite3_backup*,int);
89432 const char *(*compileoption_get)(int);
89433 int (*compileoption_used)(const char*);
89434 int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
89435 void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
89436 void (*xStep)(sqlite3_context*,int,sqlite3_value**),
89437 void (*xFinal)(sqlite3_context*),
89438 void(*xDestroy)(void*));
89439 int (*db_config)(sqlite3*,int,...);
89440 sqlite3_mutex *(*db_mutex)(sqlite3*);
89441 int (*db_status)(sqlite3*,int,int*,int*,int);
89442 int (*extended_errcode)(sqlite3*);
89443 void (*log)(int,const char*,...);
@@ -100485,11 +100519,11 @@
100519 if( db->aVTrans ){
100520 int i;
100521 for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
100522 VTable *pVTab = db->aVTrans[i];
100523 const sqlite3_module *pMod = pVTab->pMod->pModule;
100524 if( pVTab->pVtab && pMod->iVersion>=2 ){
100525 int (*xMethod)(sqlite3_vtab *, int);
100526 switch( op ){
100527 case SAVEPOINT_BEGIN:
100528 xMethod = pMod->xSavepoint;
100529 pVTab->iSavepoint = iSavepoint+1;
@@ -100500,11 +100534,11 @@
100534 default:
100535 xMethod = pMod->xRelease;
100536 break;
100537 }
100538 if( xMethod && pVTab->iSavepoint>iSavepoint ){
100539 rc = xMethod(pVTab->pVtab, iSavepoint);
100540 }
100541 }
100542 }
100543 }
100544 return rc;
@@ -101367,11 +101401,11 @@
101401 int iCol = pRight->iColumn;
101402 pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
101403 if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
101404 z = (char *)sqlite3_value_text(pVal);
101405 }
101406 sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
101407 assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
101408 }else if( op==TK_STRING ){
101409 z = pRight->u.zToken;
101410 }
101411 if( z ){
@@ -101385,11 +101419,11 @@
101419 pPrefix = sqlite3Expr(db, TK_STRING, z);
101420 if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
101421 *ppPrefix = pPrefix;
101422 if( op==TK_VARIABLE ){
101423 Vdbe *v = pParse->pVdbe;
101424 sqlite3VdbeSetVarmask(v, pRight->iColumn);
101425 if( *pisComplete && pRight->u.zToken[1] ){
101426 /* If the rhs of the LIKE expression is a variable, and the current
101427 ** value of the variable means there is no need to invoke the LIKE
101428 ** function, then no OP_Variable will be added to the program.
101429 ** This causes problems for the sqlite3_bind_parameter_name()
@@ -103299,11 +103333,11 @@
103333 ){
103334 if( pExpr->op==TK_VARIABLE
103335 || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
103336 ){
103337 int iVar = pExpr->iColumn;
103338 sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
103339 *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
103340 return SQLITE_OK;
103341 }
103342 return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
103343 }
@@ -103829,11 +103863,11 @@
103863 ** a table or index. The actual times can vary, with the size of
103864 ** records being an important factor. Both moves and searches are
103865 ** slower with larger records, presumably because fewer records fit
103866 ** on one page and hence more pages have to be fetched.
103867 **
103868 ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do
103869 ** not give us data on the relative sizes of table and index records.
103870 ** So this computation assumes table records are about twice as big
103871 ** as index records
103872 */
103873 if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ){
103874
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.7.9"
111111
#define SQLITE_VERSION_NUMBER 3007009
112
-#define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
112
+#define SQLITE_SOURCE_ID "2011-10-29 19:25:08 5b82ec6fbbd2f4195ad06dd911de3817373ad5bf"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
118118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.9"
111 #define SQLITE_VERSION_NUMBER 3007009
112 #define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.9"
111 #define SQLITE_VERSION_NUMBER 3007009
112 #define SQLITE_SOURCE_ID "2011-10-29 19:25:08 5b82ec6fbbd2f4195ad06dd911de3817373ad5bf"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
+56 -26
--- src/stash.c
+++ src/stash.c
@@ -170,11 +170,11 @@
170170
int i;
171171
for(i=3; i<g.argc; i++){
172172
stash_add_file_or_dir(stashid, vid, g.argv[i]);
173173
}
174174
}else{
175
- stash_add_file_or_dir(stashid, vid, ".");
175
+ stash_add_file_or_dir(stashid, vid, g.zLocalRoot);
176176
}
177177
return stashid;
178178
}
179179
180180
/*
@@ -258,12 +258,13 @@
258258
file_delete(zOPath);
259259
}
260260
}
261261
db_finalize(&q);
262262
if( nConflict ){
263
- fossil_print("WARNING: %d merge conflicts - see messages above for details.\n",
264
- nConflict);
263
+ fossil_print(
264
+ "WARNING: %d merge conflicts - see messages above for details.\n",
265
+ nConflict);
265266
}
266267
}
267268
268269
/*
269270
** Show the diffs associate with a single stash.
@@ -363,35 +364,32 @@
363364
**
364365
** Usage: %fossil stash SUBCOMMAND ARGS...
365366
**
366367
** fossil stash
367368
** fossil stash save ?-m COMMENT? ?FILES...?
369
+** fossil stash snapshot ?-m COMMENT? ?FILES...?
368370
**
369371
** Save the current changes in the working tree as a new stash.
370372
** Then revert the changes back to the last check-in. If FILES
371373
** are listed, then only stash and revert the named files. The
372374
** "save" verb can be omitted if and only if there are no other
373
-** arguments.
375
+** arguments. The "snapshot" verb works the same as "save" but
376
+** omits the revert, keeping the check-out unchanged.
374377
**
375
-** fossil stash list
376
-** fossil stash ls
378
+** fossil stash list ?--detail?
379
+** fossil stash ls ?-l?
377380
**
378
-** List all changes sets currently stashed.
381
+** List all changes sets currently stashed. Show information about
382
+** individual files in each changeset if --detail or -l is used.
379383
**
380384
** fossil stash pop
381
-**
382
-** Apply the most recently create stash to the current working
383
-** check-out. Then delete that stash. This is equivalent to
384
-** doing an "apply" and a "drop" against the most recent stash.
385
-** This command is undoable.
386
-**
387385
** fossil stash apply ?STASHID?
388386
**
389
-** Apply the identified stash to the current working check-out.
390
-** If no STASHID is specified, use the most recent stash. Unlike
391
-** the "pop" command, the stash is retained so that it can be used
392
-** again. This command is undoable.
387
+** Apply STASHID or the most recently create stash to the current
388
+** working check-out. The "pop" command deletes that changeset from
389
+** the stash after applying it but the "apply" command retains the
390
+** changeset.
393391
**
394392
** fossil stash goto ?STASHID?
395393
**
396394
** Update to the baseline checkout for STASHID then apply the
397395
** changes of STASHID. Keep STASHID so that it can be reused
@@ -401,15 +399,10 @@
401399
** fossil stash rm ?STASHID? ?--all?
402400
**
403401
** Forget everything about STASHID. Forget the whole stash if the
404402
** --all flag is used. Individual drops are undoable but --all is not.
405403
**
406
-** fossil stash snapshot ?-m COMMENT? ?FILES...?
407
-**
408
-** Save the current changes in the working tree as a new stash
409
-** but, unlike "save", do not revert those changes.
410
-**
411404
** fossil stash diff ?STASHID?
412405
** fossil stash gdiff ?STASHID?
413406
**
414407
** Show diffs of the current working directory and what that
415408
** directory would be if STASHID were applied.
@@ -455,40 +448,71 @@
455448
}else
456449
if( memcmp(zCmd, "snapshot", nCmd)==0 ){
457450
stash_create();
458451
}else
459452
if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
460
- Stmt q;
453
+ Stmt q, q2;
461454
int n = 0;
455
+ int fDetail = find_option("detail","l",0)!=0;
462456
verify_all_options();
463457
db_prepare(&q,
464458
"SELECT stashid, (SELECT uuid FROM blob WHERE rid=vid),"
465459
" comment, datetime(ctime) FROM stash"
466460
" ORDER BY ctime DESC"
467461
);
462
+ if( fDetail ){
463
+ db_prepare(&q2, "SELECT isAdded, isRemoved, origname, newname"
464
+ " FROM stashfile WHERE stashid=$id");
465
+ }
468466
while( db_step(&q)==SQLITE_ROW ){
467
+ int stashid = db_column_int(&q, 0);
469468
const char *zCom;
470469
n++;
471470
fossil_print("%5d: [%.14s] on %s\n",
472
- db_column_int(&q, 0),
471
+ stashid,
473472
db_column_text(&q, 1),
474473
db_column_text(&q, 3)
475474
);
476475
zCom = db_column_text(&q, 2);
477476
if( zCom && zCom[0] ){
478477
fossil_print(" ");
479478
comment_print(zCom, 7, 79);
480479
}
480
+ if( fDetail ){
481
+ db_bind_int(&q2, "$id", stashid);
482
+ while( db_step(&q2)==SQLITE_ROW ){
483
+ int isAdded = db_column_int(&q2, 0);
484
+ int isRemoved = db_column_int(&q2, 1);
485
+ const char *zOrig = db_column_text(&q2, 2);
486
+ const char *zNew = db_column_text(&q2, 3);
487
+ if( isAdded ){
488
+ fossil_print(" ADD %s\n", zNew);
489
+ }else if( isRemoved ){
490
+ fossil_print(" REMOVE %s\n", zOrig);
491
+ }else if( fossil_strcmp(zOrig,zNew)!=0 ){
492
+ fossil_print(" RENAME %s -> %s\n", zOrig, zNew);
493
+ }else{
494
+ fossil_print(" EDIT %s\n", zOrig);
495
+ }
496
+ }
497
+ db_reset(&q2);
498
+ }
481499
}
482500
db_finalize(&q);
501
+ if( fDetail ) db_finalize(&q2);
483502
if( n==0 ) fossil_print("empty stash\n");
484503
}else
485504
if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){
486505
int allFlag = find_option("all", 0, 0)!=0;
487
- if( g.argc>4 ) usage("apply STASHID");
506
+ if( g.argc>4 ) usage("drop STASHID");
488507
if( allFlag ){
489
- db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;");
508
+ Blob ans;
509
+ blob_zero(&ans);
510
+ prompt_user("This action is not undoable. Continue (y/N)? ", &ans);
511
+ if( blob_str(&ans)[0]=='y' ){
512
+ db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;");
513
+ }
490514
}else{
491515
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
492516
undo_begin();
493517
undo_save_stash(stashid);
494518
stash_drop(stashid);
@@ -537,11 +561,17 @@
537561
const char *zDiffCmd = db_get("gdiff-command", 0);
538562
int diffFlags = diff_options();
539563
if( g.argc>4 ) usage("diff STASHID");
540564
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
541565
stash_diff(stashid, zDiffCmd, diffFlags);
566
+ }else
567
+ if( memcmp(zCmd, "help", nCmd)==0 ){
568
+ g.argv[1] = "help";
569
+ g.argv[2] = "stash";
570
+ g.argc = 3;
571
+ help_cmd();
542572
}else
543573
{
544574
usage("SUBCOMMAND ARGS...");
545575
}
546576
db_end_transaction(0);
547577
}
548578
--- src/stash.c
+++ src/stash.c
@@ -170,11 +170,11 @@
170 int i;
171 for(i=3; i<g.argc; i++){
172 stash_add_file_or_dir(stashid, vid, g.argv[i]);
173 }
174 }else{
175 stash_add_file_or_dir(stashid, vid, ".");
176 }
177 return stashid;
178 }
179
180 /*
@@ -258,12 +258,13 @@
258 file_delete(zOPath);
259 }
260 }
261 db_finalize(&q);
262 if( nConflict ){
263 fossil_print("WARNING: %d merge conflicts - see messages above for details.\n",
264 nConflict);
 
265 }
266 }
267
268 /*
269 ** Show the diffs associate with a single stash.
@@ -363,35 +364,32 @@
363 **
364 ** Usage: %fossil stash SUBCOMMAND ARGS...
365 **
366 ** fossil stash
367 ** fossil stash save ?-m COMMENT? ?FILES...?
 
368 **
369 ** Save the current changes in the working tree as a new stash.
370 ** Then revert the changes back to the last check-in. If FILES
371 ** are listed, then only stash and revert the named files. The
372 ** "save" verb can be omitted if and only if there are no other
373 ** arguments.
 
374 **
375 ** fossil stash list
376 ** fossil stash ls
377 **
378 ** List all changes sets currently stashed.
 
379 **
380 ** fossil stash pop
381 **
382 ** Apply the most recently create stash to the current working
383 ** check-out. Then delete that stash. This is equivalent to
384 ** doing an "apply" and a "drop" against the most recent stash.
385 ** This command is undoable.
386 **
387 ** fossil stash apply ?STASHID?
388 **
389 ** Apply the identified stash to the current working check-out.
390 ** If no STASHID is specified, use the most recent stash. Unlike
391 ** the "pop" command, the stash is retained so that it can be used
392 ** again. This command is undoable.
393 **
394 ** fossil stash goto ?STASHID?
395 **
396 ** Update to the baseline checkout for STASHID then apply the
397 ** changes of STASHID. Keep STASHID so that it can be reused
@@ -401,15 +399,10 @@
401 ** fossil stash rm ?STASHID? ?--all?
402 **
403 ** Forget everything about STASHID. Forget the whole stash if the
404 ** --all flag is used. Individual drops are undoable but --all is not.
405 **
406 ** fossil stash snapshot ?-m COMMENT? ?FILES...?
407 **
408 ** Save the current changes in the working tree as a new stash
409 ** but, unlike "save", do not revert those changes.
410 **
411 ** fossil stash diff ?STASHID?
412 ** fossil stash gdiff ?STASHID?
413 **
414 ** Show diffs of the current working directory and what that
415 ** directory would be if STASHID were applied.
@@ -455,40 +448,71 @@
455 }else
456 if( memcmp(zCmd, "snapshot", nCmd)==0 ){
457 stash_create();
458 }else
459 if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
460 Stmt q;
461 int n = 0;
 
462 verify_all_options();
463 db_prepare(&q,
464 "SELECT stashid, (SELECT uuid FROM blob WHERE rid=vid),"
465 " comment, datetime(ctime) FROM stash"
466 " ORDER BY ctime DESC"
467 );
 
 
 
 
468 while( db_step(&q)==SQLITE_ROW ){
 
469 const char *zCom;
470 n++;
471 fossil_print("%5d: [%.14s] on %s\n",
472 db_column_int(&q, 0),
473 db_column_text(&q, 1),
474 db_column_text(&q, 3)
475 );
476 zCom = db_column_text(&q, 2);
477 if( zCom && zCom[0] ){
478 fossil_print(" ");
479 comment_print(zCom, 7, 79);
480 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481 }
482 db_finalize(&q);
 
483 if( n==0 ) fossil_print("empty stash\n");
484 }else
485 if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){
486 int allFlag = find_option("all", 0, 0)!=0;
487 if( g.argc>4 ) usage("apply STASHID");
488 if( allFlag ){
489 db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;");
 
 
 
 
 
490 }else{
491 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
492 undo_begin();
493 undo_save_stash(stashid);
494 stash_drop(stashid);
@@ -537,11 +561,17 @@
537 const char *zDiffCmd = db_get("gdiff-command", 0);
538 int diffFlags = diff_options();
539 if( g.argc>4 ) usage("diff STASHID");
540 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
541 stash_diff(stashid, zDiffCmd, diffFlags);
 
 
 
 
 
 
542 }else
543 {
544 usage("SUBCOMMAND ARGS...");
545 }
546 db_end_transaction(0);
547 }
548
--- src/stash.c
+++ src/stash.c
@@ -170,11 +170,11 @@
170 int i;
171 for(i=3; i<g.argc; i++){
172 stash_add_file_or_dir(stashid, vid, g.argv[i]);
173 }
174 }else{
175 stash_add_file_or_dir(stashid, vid, g.zLocalRoot);
176 }
177 return stashid;
178 }
179
180 /*
@@ -258,12 +258,13 @@
258 file_delete(zOPath);
259 }
260 }
261 db_finalize(&q);
262 if( nConflict ){
263 fossil_print(
264 "WARNING: %d merge conflicts - see messages above for details.\n",
265 nConflict);
266 }
267 }
268
269 /*
270 ** Show the diffs associate with a single stash.
@@ -363,35 +364,32 @@
364 **
365 ** Usage: %fossil stash SUBCOMMAND ARGS...
366 **
367 ** fossil stash
368 ** fossil stash save ?-m COMMENT? ?FILES...?
369 ** fossil stash snapshot ?-m COMMENT? ?FILES...?
370 **
371 ** Save the current changes in the working tree as a new stash.
372 ** Then revert the changes back to the last check-in. If FILES
373 ** are listed, then only stash and revert the named files. The
374 ** "save" verb can be omitted if and only if there are no other
375 ** arguments. The "snapshot" verb works the same as "save" but
376 ** omits the revert, keeping the check-out unchanged.
377 **
378 ** fossil stash list ?--detail?
379 ** fossil stash ls ?-l?
380 **
381 ** List all changes sets currently stashed. Show information about
382 ** individual files in each changeset if --detail or -l is used.
383 **
384 ** fossil stash pop
 
 
 
 
 
 
385 ** fossil stash apply ?STASHID?
386 **
387 ** Apply STASHID or the most recently create stash to the current
388 ** working check-out. The "pop" command deletes that changeset from
389 ** the stash after applying it but the "apply" command retains the
390 ** changeset.
391 **
392 ** fossil stash goto ?STASHID?
393 **
394 ** Update to the baseline checkout for STASHID then apply the
395 ** changes of STASHID. Keep STASHID so that it can be reused
@@ -401,15 +399,10 @@
399 ** fossil stash rm ?STASHID? ?--all?
400 **
401 ** Forget everything about STASHID. Forget the whole stash if the
402 ** --all flag is used. Individual drops are undoable but --all is not.
403 **
 
 
 
 
 
404 ** fossil stash diff ?STASHID?
405 ** fossil stash gdiff ?STASHID?
406 **
407 ** Show diffs of the current working directory and what that
408 ** directory would be if STASHID were applied.
@@ -455,40 +448,71 @@
448 }else
449 if( memcmp(zCmd, "snapshot", nCmd)==0 ){
450 stash_create();
451 }else
452 if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
453 Stmt q, q2;
454 int n = 0;
455 int fDetail = find_option("detail","l",0)!=0;
456 verify_all_options();
457 db_prepare(&q,
458 "SELECT stashid, (SELECT uuid FROM blob WHERE rid=vid),"
459 " comment, datetime(ctime) FROM stash"
460 " ORDER BY ctime DESC"
461 );
462 if( fDetail ){
463 db_prepare(&q2, "SELECT isAdded, isRemoved, origname, newname"
464 " FROM stashfile WHERE stashid=$id");
465 }
466 while( db_step(&q)==SQLITE_ROW ){
467 int stashid = db_column_int(&q, 0);
468 const char *zCom;
469 n++;
470 fossil_print("%5d: [%.14s] on %s\n",
471 stashid,
472 db_column_text(&q, 1),
473 db_column_text(&q, 3)
474 );
475 zCom = db_column_text(&q, 2);
476 if( zCom && zCom[0] ){
477 fossil_print(" ");
478 comment_print(zCom, 7, 79);
479 }
480 if( fDetail ){
481 db_bind_int(&q2, "$id", stashid);
482 while( db_step(&q2)==SQLITE_ROW ){
483 int isAdded = db_column_int(&q2, 0);
484 int isRemoved = db_column_int(&q2, 1);
485 const char *zOrig = db_column_text(&q2, 2);
486 const char *zNew = db_column_text(&q2, 3);
487 if( isAdded ){
488 fossil_print(" ADD %s\n", zNew);
489 }else if( isRemoved ){
490 fossil_print(" REMOVE %s\n", zOrig);
491 }else if( fossil_strcmp(zOrig,zNew)!=0 ){
492 fossil_print(" RENAME %s -> %s\n", zOrig, zNew);
493 }else{
494 fossil_print(" EDIT %s\n", zOrig);
495 }
496 }
497 db_reset(&q2);
498 }
499 }
500 db_finalize(&q);
501 if( fDetail ) db_finalize(&q2);
502 if( n==0 ) fossil_print("empty stash\n");
503 }else
504 if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){
505 int allFlag = find_option("all", 0, 0)!=0;
506 if( g.argc>4 ) usage("drop STASHID");
507 if( allFlag ){
508 Blob ans;
509 blob_zero(&ans);
510 prompt_user("This action is not undoable. Continue (y/N)? ", &ans);
511 if( blob_str(&ans)[0]=='y' ){
512 db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;");
513 }
514 }else{
515 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
516 undo_begin();
517 undo_save_stash(stashid);
518 stash_drop(stashid);
@@ -537,11 +561,17 @@
561 const char *zDiffCmd = db_get("gdiff-command", 0);
562 int diffFlags = diff_options();
563 if( g.argc>4 ) usage("diff STASHID");
564 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
565 stash_diff(stashid, zDiffCmd, diffFlags);
566 }else
567 if( memcmp(zCmd, "help", nCmd)==0 ){
568 g.argv[1] = "help";
569 g.argv[2] = "stash";
570 g.argc = 3;
571 help_cmd();
572 }else
573 {
574 usage("SUBCOMMAND ARGS...");
575 }
576 db_end_transaction(0);
577 }
578
+1 -1
--- src/tar.c
+++ src/tar.c
@@ -523,11 +523,11 @@
523523
blob_reset(&filename);
524524
tar_finish(pTar);
525525
}
526526
527527
/*
528
-** COMMAND: tarball
528
+** COMMAND: tarball*
529529
**
530530
** Usage: %fossil tarball VERSION OUTPUTFILE [--name DIRECTORYNAME]
531531
**
532532
** Generate a compressed tarball for a specified version. If the --name
533533
** option is used, its argument becomes the name of the top-level directory
534534
--- src/tar.c
+++ src/tar.c
@@ -523,11 +523,11 @@
523 blob_reset(&filename);
524 tar_finish(pTar);
525 }
526
527 /*
528 ** COMMAND: tarball
529 **
530 ** Usage: %fossil tarball VERSION OUTPUTFILE [--name DIRECTORYNAME]
531 **
532 ** Generate a compressed tarball for a specified version. If the --name
533 ** option is used, its argument becomes the name of the top-level directory
534
--- src/tar.c
+++ src/tar.c
@@ -523,11 +523,11 @@
523 blob_reset(&filename);
524 tar_finish(pTar);
525 }
526
527 /*
528 ** COMMAND: tarball*
529 **
530 ** Usage: %fossil tarball VERSION OUTPUTFILE [--name DIRECTORYNAME]
531 **
532 ** Generate a compressed tarball for a specified version. If the --name
533 ** option is used, its argument becomes the name of the top-level directory
534
+1 -1
--- src/tkt.c
+++ src/tkt.c
@@ -837,11 +837,11 @@
837837
}
838838
@ </ol>
839839
}
840840
841841
/*
842
-** COMMAND: ticket
842
+** COMMAND: ticket*
843843
** Usage: %fossil ticket SUBCOMMAND ...
844844
**
845845
** Run various subcommands to control tickets
846846
**
847847
** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
848848
--- src/tkt.c
+++ src/tkt.c
@@ -837,11 +837,11 @@
837 }
838 @ </ol>
839 }
840
841 /*
842 ** COMMAND: ticket
843 ** Usage: %fossil ticket SUBCOMMAND ...
844 **
845 ** Run various subcommands to control tickets
846 **
847 ** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
848
--- src/tkt.c
+++ src/tkt.c
@@ -837,11 +837,11 @@
837 }
838 @ </ol>
839 }
840
841 /*
842 ** COMMAND: ticket*
843 ** Usage: %fossil ticket SUBCOMMAND ...
844 **
845 ** Run various subcommands to control tickets
846 **
847 ** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
848
+1 -1
--- src/tkt.c
+++ src/tkt.c
@@ -837,11 +837,11 @@
837837
}
838838
@ </ol>
839839
}
840840
841841
/*
842
-** COMMAND: ticket
842
+** COMMAND: ticket*
843843
** Usage: %fossil ticket SUBCOMMAND ...
844844
**
845845
** Run various subcommands to control tickets
846846
**
847847
** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
848848
--- src/tkt.c
+++ src/tkt.c
@@ -837,11 +837,11 @@
837 }
838 @ </ol>
839 }
840
841 /*
842 ** COMMAND: ticket
843 ** Usage: %fossil ticket SUBCOMMAND ...
844 **
845 ** Run various subcommands to control tickets
846 **
847 ** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
848
--- src/tkt.c
+++ src/tkt.c
@@ -837,11 +837,11 @@
837 }
838 @ </ol>
839 }
840
841 /*
842 ** COMMAND: ticket*
843 ** Usage: %fossil ticket SUBCOMMAND ...
844 **
845 ** Run various subcommands to control tickets
846 **
847 ** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
848
+1 -1
--- src/undo.c
+++ src/undo.c
@@ -348,11 +348,11 @@
348348
undo_all_filesystem(0);
349349
}
350350
351351
/*
352352
** COMMAND: undo
353
-** COMMAND: redo
353
+** COMMAND: redo*
354354
**
355355
** Usage: %fossil undo ?--explain? ?FILENAME...?
356356
** or: %fossil redo ?--explain? ?FILENAME...?
357357
**
358358
** Undo the changes to the working checkout caused by the most recent
359359
--- src/undo.c
+++ src/undo.c
@@ -348,11 +348,11 @@
348 undo_all_filesystem(0);
349 }
350
351 /*
352 ** COMMAND: undo
353 ** COMMAND: redo
354 **
355 ** Usage: %fossil undo ?--explain? ?FILENAME...?
356 ** or: %fossil redo ?--explain? ?FILENAME...?
357 **
358 ** Undo the changes to the working checkout caused by the most recent
359
--- src/undo.c
+++ src/undo.c
@@ -348,11 +348,11 @@
348 undo_all_filesystem(0);
349 }
350
351 /*
352 ** COMMAND: undo
353 ** COMMAND: redo*
354 **
355 ** Usage: %fossil undo ?--explain? ?FILENAME...?
356 ** or: %fossil redo ?--explain? ?FILENAME...?
357 **
358 ** Undo the changes to the working checkout caused by the most recent
359
+1 -1
--- src/user.c
+++ src/user.c
@@ -142,11 +142,11 @@
142142
}
143143
}
144144
145145
146146
/*
147
-** COMMAND: user
147
+** COMMAND: user*
148148
**
149149
** Usage: %fossil user SUBCOMMAND ... ?-R|--repository FILE?
150150
**
151151
** Run various subcommands on users of the open repository or of
152152
** the repository identified by the -R or --repository option.
153153
--- src/user.c
+++ src/user.c
@@ -142,11 +142,11 @@
142 }
143 }
144
145
146 /*
147 ** COMMAND: user
148 **
149 ** Usage: %fossil user SUBCOMMAND ... ?-R|--repository FILE?
150 **
151 ** Run various subcommands on users of the open repository or of
152 ** the repository identified by the -R or --repository option.
153
--- src/user.c
+++ src/user.c
@@ -142,11 +142,11 @@
142 }
143 }
144
145
146 /*
147 ** COMMAND: user*
148 **
149 ** Usage: %fossil user SUBCOMMAND ... ?-R|--repository FILE?
150 **
151 ** Run various subcommands on users of the open repository or of
152 ** the repository identified by the -R or --repository option.
153
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -839,11 +839,11 @@
839839
db_end_transaction(0);
840840
return 1;
841841
}
842842
843843
/*
844
-** COMMAND: wiki
844
+** COMMAND: wiki*
845845
**
846846
** Usage: %fossil wiki (export|create|commit|list) WikiName
847847
**
848848
** Run various subcommands to work with wiki entries.
849849
**
850850
--- src/wiki.c
+++ src/wiki.c
@@ -839,11 +839,11 @@
839 db_end_transaction(0);
840 return 1;
841 }
842
843 /*
844 ** COMMAND: wiki
845 **
846 ** Usage: %fossil wiki (export|create|commit|list) WikiName
847 **
848 ** Run various subcommands to work with wiki entries.
849 **
850
--- src/wiki.c
+++ src/wiki.c
@@ -839,11 +839,11 @@
839 db_end_transaction(0);
840 return 1;
841 }
842
843 /*
844 ** COMMAND: wiki*
845 **
846 ** Usage: %fossil wiki (export|create|commit|list) WikiName
847 **
848 ** Run various subcommands to work with wiki entries.
849 **
850
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -839,11 +839,11 @@
839839
db_end_transaction(0);
840840
return 1;
841841
}
842842
843843
/*
844
-** COMMAND: wiki
844
+** COMMAND: wiki*
845845
**
846846
** Usage: %fossil wiki (export|create|commit|list) WikiName
847847
**
848848
** Run various subcommands to work with wiki entries.
849849
**
850850
--- src/wiki.c
+++ src/wiki.c
@@ -839,11 +839,11 @@
839 db_end_transaction(0);
840 return 1;
841 }
842
843 /*
844 ** COMMAND: wiki
845 **
846 ** Usage: %fossil wiki (export|create|commit|list) WikiName
847 **
848 ** Run various subcommands to work with wiki entries.
849 **
850
--- src/wiki.c
+++ src/wiki.c
@@ -839,11 +839,11 @@
839 db_end_transaction(0);
840 return 1;
841 }
842
843 /*
844 ** COMMAND: wiki*
845 **
846 ** Usage: %fossil wiki (export|create|commit|list) WikiName
847 **
848 ** Run various subcommands to work with wiki entries.
849 **
850
+1 -1
--- src/winhttp.c
+++ src/winhttp.c
@@ -432,11 +432,11 @@
432432
}
433433
return 0;
434434
}
435435
436436
/*
437
-** COMMAND: winsrv
437
+** COMMAND: winsrv*
438438
** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS?
439439
**
440440
** Where METHOD is one of: create delete show start stop.
441441
**
442442
** The winsrv command manages Fossil as a Windows service. This allows
443443
--- src/winhttp.c
+++ src/winhttp.c
@@ -432,11 +432,11 @@
432 }
433 return 0;
434 }
435
436 /*
437 ** COMMAND: winsrv
438 ** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS?
439 **
440 ** Where METHOD is one of: create delete show start stop.
441 **
442 ** The winsrv command manages Fossil as a Windows service. This allows
443
--- src/winhttp.c
+++ src/winhttp.c
@@ -432,11 +432,11 @@
432 }
433 return 0;
434 }
435
436 /*
437 ** COMMAND: winsrv*
438 ** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS?
439 **
440 ** Where METHOD is one of: create delete show start stop.
441 **
442 ** The winsrv command manages Fossil as a Windows service. This allows
443
+2
--- src/xfer.c
+++ src/xfer.c
@@ -637,15 +637,17 @@
637637
Stmt q;
638638
int nUncl;
639639
int nRow = 0;
640640
int rid;
641641
642
+#if 0
642643
/* We should not ever get any private artifacts in the unclustered table.
643644
** But if we do (because of a bug) now is a good time to delete them. */
644645
db_multi_exec(
645646
"DELETE FROM unclustered WHERE rid IN (SELECT rid FROM private)"
646647
);
648
+#endif
647649
648650
nUncl = db_int(0, "SELECT count(*) FROM unclustered /*scan*/"
649651
" WHERE NOT EXISTS(SELECT 1 FROM phantom"
650652
" WHERE rid=unclustered.rid)");
651653
if( nUncl>=100 ){
652654
--- src/xfer.c
+++ src/xfer.c
@@ -637,15 +637,17 @@
637 Stmt q;
638 int nUncl;
639 int nRow = 0;
640 int rid;
641
 
642 /* We should not ever get any private artifacts in the unclustered table.
643 ** But if we do (because of a bug) now is a good time to delete them. */
644 db_multi_exec(
645 "DELETE FROM unclustered WHERE rid IN (SELECT rid FROM private)"
646 );
 
647
648 nUncl = db_int(0, "SELECT count(*) FROM unclustered /*scan*/"
649 " WHERE NOT EXISTS(SELECT 1 FROM phantom"
650 " WHERE rid=unclustered.rid)");
651 if( nUncl>=100 ){
652
--- src/xfer.c
+++ src/xfer.c
@@ -637,15 +637,17 @@
637 Stmt q;
638 int nUncl;
639 int nRow = 0;
640 int rid;
641
642 #if 0
643 /* We should not ever get any private artifacts in the unclustered table.
644 ** But if we do (because of a bug) now is a good time to delete them. */
645 db_multi_exec(
646 "DELETE FROM unclustered WHERE rid IN (SELECT rid FROM private)"
647 );
648 #endif
649
650 nUncl = db_int(0, "SELECT count(*) FROM unclustered /*scan*/"
651 " WHERE NOT EXISTS(SELECT 1 FROM phantom"
652 " WHERE rid=unclustered.rid)");
653 if( nUncl>=100 ){
654
+1 -1
--- src/zip.c
+++ src/zip.c
@@ -377,11 +377,11 @@
377377
blob_reset(&filename);
378378
zip_close(pZip);
379379
}
380380
381381
/*
382
-** COMMAND: zip
382
+** COMMAND: zip*
383383
**
384384
** Usage: %fossil zip VERSION OUTPUTFILE [--name DIRECTORYNAME]
385385
**
386386
** Generate a ZIP archive for a specified version. If the --name option is
387387
** used, it argument becomes the name of the top-level directory in the
388388
--- src/zip.c
+++ src/zip.c
@@ -377,11 +377,11 @@
377 blob_reset(&filename);
378 zip_close(pZip);
379 }
380
381 /*
382 ** COMMAND: zip
383 **
384 ** Usage: %fossil zip VERSION OUTPUTFILE [--name DIRECTORYNAME]
385 **
386 ** Generate a ZIP archive for a specified version. If the --name option is
387 ** used, it argument becomes the name of the top-level directory in the
388
--- src/zip.c
+++ src/zip.c
@@ -377,11 +377,11 @@
377 blob_reset(&filename);
378 zip_close(pZip);
379 }
380
381 /*
382 ** COMMAND: zip*
383 **
384 ** Usage: %fossil zip VERSION OUTPUTFILE [--name DIRECTORYNAME]
385 **
386 ** Generate a ZIP archive for a specified version. If the --name option is
387 ** used, it argument becomes the name of the top-level directory in the
388
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -126,23 +126,24 @@
126126
* <i>YYYY-MM-DD HH:MM</i>
127127
* <i>YYYY-MM-DD HH:MM:SS</i>
128128
129129
The space between the day and the year can optionally be
130130
replaced by an uppercase <b>T</b> and the entire timestamp can
131
-optionally be followed by "<b>utc</b>".
131
+optionally be followed by "<b>z</b>" or "<b>Z</b>".
132132
133133
In its default configuration, Fossil interprets and displays all dates
134134
in Universal Coordinated Time (UTC). This tends to work the best for
135135
distributed projects where participants are scattered around the globe.
136136
But there is an option on the Admin/Timeline page of the web-interface to
137
-switch to local time. The "<b>utc</b>" suffix on an timestamp check-in
137
+switch to local time. The "<b>Z</b>" suffix on an timestamp check-in
138138
name is meaningless if Fossil is in the default mode of using UTC for
139139
everything, but if Fossil has been switched to localtime mode, then the
140
-"<b>utc</b>" suffix means to interpret that particular timestamp using
140
+"<b>Z</b>" suffix means to interpret that particular timestamp using
141141
UTC instead localtime.
142142
143
-As an example, consider the homepage for the Fossil website itself:
143
+For an example of how timestamps are useful,
144
+consider the homepage for the Fossil website itself:
144145
145146
<blockquote>
146147
http://www.fossil-scm.org/fossil/doc/<b>trunk</b>/www/index.wiki
147148
</blockquote>
148149
149150
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -126,23 +126,24 @@
126 * <i>YYYY-MM-DD HH:MM</i>
127 * <i>YYYY-MM-DD HH:MM:SS</i>
128
129 The space between the day and the year can optionally be
130 replaced by an uppercase <b>T</b> and the entire timestamp can
131 optionally be followed by "<b>utc</b>".
132
133 In its default configuration, Fossil interprets and displays all dates
134 in Universal Coordinated Time (UTC). This tends to work the best for
135 distributed projects where participants are scattered around the globe.
136 But there is an option on the Admin/Timeline page of the web-interface to
137 switch to local time. The "<b>utc</b>" suffix on an timestamp check-in
138 name is meaningless if Fossil is in the default mode of using UTC for
139 everything, but if Fossil has been switched to localtime mode, then the
140 "<b>utc</b>" suffix means to interpret that particular timestamp using
141 UTC instead localtime.
142
143 As an example, consider the homepage for the Fossil website itself:
 
144
145 <blockquote>
146 http://www.fossil-scm.org/fossil/doc/<b>trunk</b>/www/index.wiki
147 </blockquote>
148
149
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -126,23 +126,24 @@
126 * <i>YYYY-MM-DD HH:MM</i>
127 * <i>YYYY-MM-DD HH:MM:SS</i>
128
129 The space between the day and the year can optionally be
130 replaced by an uppercase <b>T</b> and the entire timestamp can
131 optionally be followed by "<b>z</b>" or "<b>Z</b>".
132
133 In its default configuration, Fossil interprets and displays all dates
134 in Universal Coordinated Time (UTC). This tends to work the best for
135 distributed projects where participants are scattered around the globe.
136 But there is an option on the Admin/Timeline page of the web-interface to
137 switch to local time. The "<b>Z</b>" suffix on an timestamp check-in
138 name is meaningless if Fossil is in the default mode of using UTC for
139 everything, but if Fossil has been switched to localtime mode, then the
140 "<b>Z</b>" suffix means to interpret that particular timestamp using
141 UTC instead localtime.
142
143 For an example of how timestamps are useful,
144 consider the homepage for the Fossil website itself:
145
146 <blockquote>
147 http://www.fossil-scm.org/fossil/doc/<b>trunk</b>/www/index.wiki
148 </blockquote>
149
150

Keyboard Shortcuts

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