Fossil SCM

Merge trunk.

andygoth 2015-04-29 16:54 andygoth-versioned-open merge
Commit 25a7cd1e0fdb00f85183e837063f524afd7c4e20
D .fossil-settings/keep-glob
-4
--- a/.fossil-settings/keep-glob
+++ b/.fossil-settings/keep-glob
@@ -1,4 +0,0 @@
1
-compat/openssl*
2
-compat/tcl*
3
-ts
4
-aut
--- a/.fossil-settings/keep-glob
+++ b/.fossil-settings/keep-glob
@@ -1,4 +0,0 @@
1 compat/openssl*
2 compat/tcl*
3 ts
4 aut
--- a/.fossil-settings/keep-glob
+++ b/.fossil-settings/keep-glob
@@ -1,4 +0,0 @@
 
 
 
 
+1 -1
--- src/allrepo.c
+++ src/allrepo.c
@@ -275,11 +275,11 @@
275275
useCheckouts = find_option("ckout","c",0)!=0;
276276
verify_all_options();
277277
db_begin_transaction();
278278
for(j=3; j<g.argc; j++, blob_reset(&sql), blob_reset(&fn)){
279279
file_canonical_name(g.argv[j], &fn, 0);
280
- blob_append_sql(&sql,
280
+ blob_append_sql(&sql,
281281
"DELETE FROM global_config WHERE name GLOB '%s:%q'",
282282
useCheckouts?"ckout":"repo", blob_str(&fn)
283283
);
284284
if( dryRunFlag ){
285285
fossil_print("%s\n", blob_sql_text(&sql));
286286
--- src/allrepo.c
+++ src/allrepo.c
@@ -275,11 +275,11 @@
275 useCheckouts = find_option("ckout","c",0)!=0;
276 verify_all_options();
277 db_begin_transaction();
278 for(j=3; j<g.argc; j++, blob_reset(&sql), blob_reset(&fn)){
279 file_canonical_name(g.argv[j], &fn, 0);
280 blob_append_sql(&sql,
281 "DELETE FROM global_config WHERE name GLOB '%s:%q'",
282 useCheckouts?"ckout":"repo", blob_str(&fn)
283 );
284 if( dryRunFlag ){
285 fossil_print("%s\n", blob_sql_text(&sql));
286
--- src/allrepo.c
+++ src/allrepo.c
@@ -275,11 +275,11 @@
275 useCheckouts = find_option("ckout","c",0)!=0;
276 verify_all_options();
277 db_begin_transaction();
278 for(j=3; j<g.argc; j++, blob_reset(&sql), blob_reset(&fn)){
279 file_canonical_name(g.argv[j], &fn, 0);
280 blob_append_sql(&sql,
281 "DELETE FROM global_config WHERE name GLOB '%s:%q'",
282 useCheckouts?"ckout":"repo", blob_str(&fn)
283 );
284 if( dryRunFlag ){
285 fossil_print("%s\n", blob_sql_text(&sql));
286
+8 -6
--- src/attach.c
+++ src/attach.c
@@ -21,18 +21,18 @@
2121
#include "attach.h"
2222
#include <assert.h>
2323
2424
/*
2525
** WEBPAGE: attachlist
26
+** List attachments.
2627
**
2728
** tkt=TICKETUUID
2829
** page=WIKIPAGE
2930
**
30
-** List attachments.
31
-** Either one of tkt= or page= are supplied or neither. If neither
32
-** are given, all attachments are listed. If one is given, only
33
-** attachments for the designated ticket or wiki page are shown.
31
+** Either one of tkt= or page= are supplied or neither but not both.
32
+** If neither are given, all attachments are listed. If one is given,
33
+** only attachments for the designated ticket or wiki page are shown.
3434
** TICKETUUID must be complete
3535
*/
3636
void attachlist_page(void){
3737
const char *zPage = P("page");
3838
const char *zTkt = P("tkt");
@@ -134,16 +134,18 @@
134134
/*
135135
** WEBPAGE: attachdownload
136136
** WEBPAGE: attachimage
137137
** WEBPAGE: attachview
138138
**
139
+** Download or display an attachment.
140
+** Query parameters:
141
+**
139142
** tkt=TICKETUUID
140143
** page=WIKIPAGE
141144
** file=FILENAME
142145
** attachid=ID
143146
**
144
-** List attachments.
145147
*/
146148
void attachview_page(void){
147149
const char *zPage = P("page");
148150
const char *zTkt = P("tkt");
149151
const char *zFile = P("file");
@@ -223,16 +225,16 @@
223225
}
224226
225227
226228
/*
227229
** WEBPAGE: attachadd
230
+** Add a new attachment.
228231
**
229232
** tkt=TICKETUUID
230233
** page=WIKIPAGE
231234
** from=URL
232235
**
233
-** Add a new attachment.
234236
*/
235237
void attachadd_page(void){
236238
const char *zPage = P("page");
237239
const char *zTkt = P("tkt");
238240
const char *zFrom = P("from");
239241
--- src/attach.c
+++ src/attach.c
@@ -21,18 +21,18 @@
21 #include "attach.h"
22 #include <assert.h>
23
24 /*
25 ** WEBPAGE: attachlist
 
26 **
27 ** tkt=TICKETUUID
28 ** page=WIKIPAGE
29 **
30 ** List attachments.
31 ** Either one of tkt= or page= are supplied or neither. If neither
32 ** are given, all attachments are listed. If one is given, only
33 ** attachments for the designated ticket or wiki page are shown.
34 ** TICKETUUID must be complete
35 */
36 void attachlist_page(void){
37 const char *zPage = P("page");
38 const char *zTkt = P("tkt");
@@ -134,16 +134,18 @@
134 /*
135 ** WEBPAGE: attachdownload
136 ** WEBPAGE: attachimage
137 ** WEBPAGE: attachview
138 **
 
 
 
139 ** tkt=TICKETUUID
140 ** page=WIKIPAGE
141 ** file=FILENAME
142 ** attachid=ID
143 **
144 ** List attachments.
145 */
146 void attachview_page(void){
147 const char *zPage = P("page");
148 const char *zTkt = P("tkt");
149 const char *zFile = P("file");
@@ -223,16 +225,16 @@
223 }
224
225
226 /*
227 ** WEBPAGE: attachadd
 
228 **
229 ** tkt=TICKETUUID
230 ** page=WIKIPAGE
231 ** from=URL
232 **
233 ** Add a new attachment.
234 */
235 void attachadd_page(void){
236 const char *zPage = P("page");
237 const char *zTkt = P("tkt");
238 const char *zFrom = P("from");
239
--- src/attach.c
+++ src/attach.c
@@ -21,18 +21,18 @@
21 #include "attach.h"
22 #include <assert.h>
23
24 /*
25 ** WEBPAGE: attachlist
26 ** List attachments.
27 **
28 ** tkt=TICKETUUID
29 ** page=WIKIPAGE
30 **
31 ** Either one of tkt= or page= are supplied or neither but not both.
32 ** If neither are given, all attachments are listed. If one is given,
33 ** only attachments for the designated ticket or wiki page are shown.
 
34 ** TICKETUUID must be complete
35 */
36 void attachlist_page(void){
37 const char *zPage = P("page");
38 const char *zTkt = P("tkt");
@@ -134,16 +134,18 @@
134 /*
135 ** WEBPAGE: attachdownload
136 ** WEBPAGE: attachimage
137 ** WEBPAGE: attachview
138 **
139 ** Download or display an attachment.
140 ** Query parameters:
141 **
142 ** tkt=TICKETUUID
143 ** page=WIKIPAGE
144 ** file=FILENAME
145 ** attachid=ID
146 **
 
147 */
148 void attachview_page(void){
149 const char *zPage = P("page");
150 const char *zTkt = P("tkt");
151 const char *zFile = P("file");
@@ -223,16 +225,16 @@
225 }
226
227
228 /*
229 ** WEBPAGE: attachadd
230 ** Add a new attachment.
231 **
232 ** tkt=TICKETUUID
233 ** page=WIKIPAGE
234 ** from=URL
235 **
 
236 */
237 void attachadd_page(void){
238 const char *zPage = P("page");
239 const char *zTkt = P("tkt");
240 const char *zFrom = P("from");
241
+22
--- src/blob.c
+++ src/blob.c
@@ -118,10 +118,13 @@
118118
}
119119
120120
121121
/*
122122
** COMMAND: test-isspace
123
+**
124
+** Verify that the fossil_isspace() routine is working correctly but
125
+** testing it on all possible inputs.
123126
*/
124127
void isspace_cmd(void){
125128
int i;
126129
for(i=0; i<=255; i++){
127130
if( i==' ' || i=='\n' || i=='\t' || i=='\v'
@@ -884,10 +887,16 @@
884887
blob_resize(pOut, nOut2+4);
885888
}
886889
887890
/*
888891
** COMMAND: test-compress
892
+**
893
+** Usage: %fossil test-compress INPUTFILE OUTPUTFILE
894
+**
895
+** Run compression on INPUTFILE and write the result into OUTPUTFILE.
896
+**
897
+** This is used to test and debug the blob_compress() routine.
889898
*/
890899
void compress_cmd(void){
891900
Blob f;
892901
if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
893902
blob_read_from_file(&f, g.argv[2]);
@@ -936,10 +945,17 @@
936945
*pOut = temp;
937946
}
938947
939948
/*
940949
** COMMAND: test-compress-2
950
+**
951
+** Usage: %fossil test-compress-2 IN1 IN2 OUT
952
+**
953
+** Read files IN1 and IN2, concatenate the content, compress the
954
+** content, then write results into OUT.
955
+**
956
+** This is used to test and debug the blob_compress2() routine.
941957
*/
942958
void compress2_cmd(void){
943959
Blob f1, f2;
944960
if( g.argc!=5 ) usage("INPUTFILE1 INPUTFILE2 OUTPUTFILE");
945961
blob_read_from_file(&f1, g.argv[2]);
@@ -982,10 +998,16 @@
982998
return 0;
983999
}
9841000
9851001
/*
9861002
** COMMAND: test-uncompress
1003
+**
1004
+** Usage: %fossil test-uncompress IN OUT
1005
+**
1006
+** Read the content of file IN, uncompress that content, and write the
1007
+** result into OUT. This command is intended for testing of the the
1008
+** blob_compress() function.
9871009
*/
9881010
void uncompress_cmd(void){
9891011
Blob f;
9901012
if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
9911013
blob_read_from_file(&f, g.argv[2]);
9921014
--- src/blob.c
+++ src/blob.c
@@ -118,10 +118,13 @@
118 }
119
120
121 /*
122 ** COMMAND: test-isspace
 
 
 
123 */
124 void isspace_cmd(void){
125 int i;
126 for(i=0; i<=255; i++){
127 if( i==' ' || i=='\n' || i=='\t' || i=='\v'
@@ -884,10 +887,16 @@
884 blob_resize(pOut, nOut2+4);
885 }
886
887 /*
888 ** COMMAND: test-compress
 
 
 
 
 
 
889 */
890 void compress_cmd(void){
891 Blob f;
892 if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
893 blob_read_from_file(&f, g.argv[2]);
@@ -936,10 +945,17 @@
936 *pOut = temp;
937 }
938
939 /*
940 ** COMMAND: test-compress-2
 
 
 
 
 
 
 
941 */
942 void compress2_cmd(void){
943 Blob f1, f2;
944 if( g.argc!=5 ) usage("INPUTFILE1 INPUTFILE2 OUTPUTFILE");
945 blob_read_from_file(&f1, g.argv[2]);
@@ -982,10 +998,16 @@
982 return 0;
983 }
984
985 /*
986 ** COMMAND: test-uncompress
 
 
 
 
 
 
987 */
988 void uncompress_cmd(void){
989 Blob f;
990 if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
991 blob_read_from_file(&f, g.argv[2]);
992
--- src/blob.c
+++ src/blob.c
@@ -118,10 +118,13 @@
118 }
119
120
121 /*
122 ** COMMAND: test-isspace
123 **
124 ** Verify that the fossil_isspace() routine is working correctly but
125 ** testing it on all possible inputs.
126 */
127 void isspace_cmd(void){
128 int i;
129 for(i=0; i<=255; i++){
130 if( i==' ' || i=='\n' || i=='\t' || i=='\v'
@@ -884,10 +887,16 @@
887 blob_resize(pOut, nOut2+4);
888 }
889
890 /*
891 ** COMMAND: test-compress
892 **
893 ** Usage: %fossil test-compress INPUTFILE OUTPUTFILE
894 **
895 ** Run compression on INPUTFILE and write the result into OUTPUTFILE.
896 **
897 ** This is used to test and debug the blob_compress() routine.
898 */
899 void compress_cmd(void){
900 Blob f;
901 if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
902 blob_read_from_file(&f, g.argv[2]);
@@ -936,10 +945,17 @@
945 *pOut = temp;
946 }
947
948 /*
949 ** COMMAND: test-compress-2
950 **
951 ** Usage: %fossil test-compress-2 IN1 IN2 OUT
952 **
953 ** Read files IN1 and IN2, concatenate the content, compress the
954 ** content, then write results into OUT.
955 **
956 ** This is used to test and debug the blob_compress2() routine.
957 */
958 void compress2_cmd(void){
959 Blob f1, f2;
960 if( g.argc!=5 ) usage("INPUTFILE1 INPUTFILE2 OUTPUTFILE");
961 blob_read_from_file(&f1, g.argv[2]);
@@ -982,10 +998,16 @@
998 return 0;
999 }
1000
1001 /*
1002 ** COMMAND: test-uncompress
1003 **
1004 ** Usage: %fossil test-uncompress IN OUT
1005 **
1006 ** Read the content of file IN, uncompress that content, and write the
1007 ** result into OUT. This command is intended for testing of the the
1008 ** blob_compress() function.
1009 */
1010 void uncompress_cmd(void){
1011 Blob f;
1012 if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
1013 blob_read_from_file(&f, g.argv[2]);
1014
+4 -1
--- src/branch.c
+++ src/branch.c
@@ -386,11 +386,14 @@
386386
style_footer();
387387
}
388388
389389
/*
390390
** WEBPAGE: brlist
391
-** Show a list of branches
391
+** Show a list of branches. With no query parameters, a sortable table
392
+** is used to show all branches. If query parameters are present a
393
+** fixed bullet list is shown.
394
+**
392395
** Query parameters:
393396
**
394397
** all Show all branches
395398
** closed Show only closed branches
396399
** open Show only open branches (default behavior)
397400
--- src/branch.c
+++ src/branch.c
@@ -386,11 +386,14 @@
386 style_footer();
387 }
388
389 /*
390 ** WEBPAGE: brlist
391 ** Show a list of branches
 
 
 
392 ** Query parameters:
393 **
394 ** all Show all branches
395 ** closed Show only closed branches
396 ** open Show only open branches (default behavior)
397
--- src/branch.c
+++ src/branch.c
@@ -386,11 +386,14 @@
386 style_footer();
387 }
388
389 /*
390 ** WEBPAGE: brlist
391 ** Show a list of branches. With no query parameters, a sortable table
392 ** is used to show all branches. If query parameters are present a
393 ** fixed bullet list is shown.
394 **
395 ** Query parameters:
396 **
397 ** all Show all branches
398 ** closed Show only closed branches
399 ** open Show only open branches (default behavior)
400
+18
--- src/browse.c
+++ src/browse.c
@@ -105,14 +105,21 @@
105105
106106
107107
/*
108108
** WEBPAGE: dir
109109
**
110
+** Show the files and subdirectories within a single directory of the
111
+** source tree. Only files for a single check-in are shown if the ci=
112
+** query parameter is present. If ci= is missing, the union of files
113
+** across all check-ins is shown.
114
+**
110115
** Query parameters:
111116
**
112117
** name=PATH Directory to display. Optional. Top-level if missing
113118
** ci=LABEL Show only files in this check-in. Optional.
119
+** type=TYPE TYPE=flat: use this display
120
+** TYPE=tree: use the /tree display instead
114121
*/
115122
void page_dir(void){
116123
char *zD = fossil_strdup(P("name"));
117124
int nD = zD ? strlen(zD)+1 : 0;
118125
int mxLen;
@@ -503,13 +510,21 @@
503510
}
504511
505512
506513
/*
507514
** WEBPAGE: tree
515
+**
516
+** Show the files using a tree-view. If the ci= query parameter is present
517
+** then show only the files for the check-in identified. If ci= is omitted,
518
+** then show the union of files over all check-ins.
519
+**
520
+** The type=tree query parameter is required or else the /dir format is
521
+** used.
508522
**
509523
** Query parameters:
510524
**
525
+** type=tree Required to prevent use of /dir format
511526
** name=PATH Directory to display. Optional
512527
** ci=LABEL Show only files in this check-in. Optional.
513528
** re=REGEXP Show only files matching REGEXP. Optional.
514529
** expand Begin with the tree fully expanded.
515530
** nofiles Show directories (folders) only. Omit files.
@@ -985,10 +1000,13 @@
9851000
db_finalize(&q);
9861001
}
9871002
9881003
/*
9891004
** WEBPAGE: fileage
1005
+**
1006
+** Show all files in a single check-in (identified by the name= query
1007
+** parameter) in order of increasing age.
9901008
**
9911009
** Parameters:
9921010
** name=VERSION Selects the check-in version (default=tip).
9931011
** glob=STRING Only shows files matching this glob pattern
9941012
** (e.g. *.c or *.txt).
9951013
--- src/browse.c
+++ src/browse.c
@@ -105,14 +105,21 @@
105
106
107 /*
108 ** WEBPAGE: dir
109 **
 
 
 
 
 
110 ** Query parameters:
111 **
112 ** name=PATH Directory to display. Optional. Top-level if missing
113 ** ci=LABEL Show only files in this check-in. Optional.
 
 
114 */
115 void page_dir(void){
116 char *zD = fossil_strdup(P("name"));
117 int nD = zD ? strlen(zD)+1 : 0;
118 int mxLen;
@@ -503,13 +510,21 @@
503 }
504
505
506 /*
507 ** WEBPAGE: tree
 
 
 
 
 
 
 
508 **
509 ** Query parameters:
510 **
 
511 ** name=PATH Directory to display. Optional
512 ** ci=LABEL Show only files in this check-in. Optional.
513 ** re=REGEXP Show only files matching REGEXP. Optional.
514 ** expand Begin with the tree fully expanded.
515 ** nofiles Show directories (folders) only. Omit files.
@@ -985,10 +1000,13 @@
985 db_finalize(&q);
986 }
987
988 /*
989 ** WEBPAGE: fileage
 
 
 
990 **
991 ** Parameters:
992 ** name=VERSION Selects the check-in version (default=tip).
993 ** glob=STRING Only shows files matching this glob pattern
994 ** (e.g. *.c or *.txt).
995
--- src/browse.c
+++ src/browse.c
@@ -105,14 +105,21 @@
105
106
107 /*
108 ** WEBPAGE: dir
109 **
110 ** Show the files and subdirectories within a single directory of the
111 ** source tree. Only files for a single check-in are shown if the ci=
112 ** query parameter is present. If ci= is missing, the union of files
113 ** across all check-ins is shown.
114 **
115 ** Query parameters:
116 **
117 ** name=PATH Directory to display. Optional. Top-level if missing
118 ** ci=LABEL Show only files in this check-in. Optional.
119 ** type=TYPE TYPE=flat: use this display
120 ** TYPE=tree: use the /tree display instead
121 */
122 void page_dir(void){
123 char *zD = fossil_strdup(P("name"));
124 int nD = zD ? strlen(zD)+1 : 0;
125 int mxLen;
@@ -503,13 +510,21 @@
510 }
511
512
513 /*
514 ** WEBPAGE: tree
515 **
516 ** Show the files using a tree-view. If the ci= query parameter is present
517 ** then show only the files for the check-in identified. If ci= is omitted,
518 ** then show the union of files over all check-ins.
519 **
520 ** The type=tree query parameter is required or else the /dir format is
521 ** used.
522 **
523 ** Query parameters:
524 **
525 ** type=tree Required to prevent use of /dir format
526 ** name=PATH Directory to display. Optional
527 ** ci=LABEL Show only files in this check-in. Optional.
528 ** re=REGEXP Show only files matching REGEXP. Optional.
529 ** expand Begin with the tree fully expanded.
530 ** nofiles Show directories (folders) only. Omit files.
@@ -985,10 +1000,13 @@
1000 db_finalize(&q);
1001 }
1002
1003 /*
1004 ** WEBPAGE: fileage
1005 **
1006 ** Show all files in a single check-in (identified by the name= query
1007 ** parameter) in order of increasing age.
1008 **
1009 ** Parameters:
1010 ** name=VERSION Selects the check-in version (default=tip).
1011 ** glob=STRING Only shows files matching this glob pattern
1012 ** (e.g. *.c or *.txt).
1013
+2 -1
--- src/cache.c
+++ src/cache.c
@@ -330,11 +330,11 @@
330330
}
331331
332332
/*
333333
** WEBPAGE: cachestat
334334
**
335
-** Show information about the webpage cache
335
+** Show information about the webpage cache. Requires Admin privilege.
336336
*/
337337
void cache_page(void){
338338
sqlite3 *db;
339339
sqlite3_stmt *pStmt;
340340
char zBuf[100];
@@ -380,10 +380,11 @@
380380
**
381381
** Usage: /cacheget?key=KEY
382382
**
383383
** Download a single entry for the cache, identified by KEY.
384384
** This page is normally a hyperlink from the /cachestat page.
385
+** Requires Admin privilege.
385386
*/
386387
void cache_getpage(void){
387388
const char *zKey;
388389
Blob content;
389390
390391
--- src/cache.c
+++ src/cache.c
@@ -330,11 +330,11 @@
330 }
331
332 /*
333 ** WEBPAGE: cachestat
334 **
335 ** Show information about the webpage cache
336 */
337 void cache_page(void){
338 sqlite3 *db;
339 sqlite3_stmt *pStmt;
340 char zBuf[100];
@@ -380,10 +380,11 @@
380 **
381 ** Usage: /cacheget?key=KEY
382 **
383 ** Download a single entry for the cache, identified by KEY.
384 ** This page is normally a hyperlink from the /cachestat page.
 
385 */
386 void cache_getpage(void){
387 const char *zKey;
388 Blob content;
389
390
--- src/cache.c
+++ src/cache.c
@@ -330,11 +330,11 @@
330 }
331
332 /*
333 ** WEBPAGE: cachestat
334 **
335 ** Show information about the webpage cache. Requires Admin privilege.
336 */
337 void cache_page(void){
338 sqlite3 *db;
339 sqlite3_stmt *pStmt;
340 char zBuf[100];
@@ -380,10 +380,11 @@
380 **
381 ** Usage: /cacheget?key=KEY
382 **
383 ** Download a single entry for the cache, identified by KEY.
384 ** This page is normally a hyperlink from the /cachestat page.
385 ** Requires Admin privilege.
386 */
387 void cache_getpage(void){
388 const char *zKey;
389 Blob content;
390
391
--- src/captcha.c
+++ src/captcha.c
@@ -414,10 +414,12 @@
414414
}
415415
#endif /* CAPTCHA==3 */
416416
417417
/*
418418
** COMMAND: test-captcha
419
+**
420
+** Render an ASCII-art captcha for numbers given on the command line.
419421
*/
420422
void test_captcha(void){
421423
int i;
422424
unsigned int v;
423425
char *z;
@@ -551,10 +553,13 @@
551553
@ </td></tr></table></div>
552554
}
553555
554556
/*
555557
** WEBPAGE: test-captcha
558
+** Test the captcha-generator by rendering the value of the name= query
559
+** parameter using ascii-art. If name= is omitted, show a random 16-digit
560
+** hexadecimal number.
556561
*/
557562
void captcha_test(void){
558563
const char *zPw = P("name");
559564
if( zPw==0 || zPw[0]==0 ){
560565
u64 x;
561566
--- src/captcha.c
+++ src/captcha.c
@@ -414,10 +414,12 @@
414 }
415 #endif /* CAPTCHA==3 */
416
417 /*
418 ** COMMAND: test-captcha
 
 
419 */
420 void test_captcha(void){
421 int i;
422 unsigned int v;
423 char *z;
@@ -551,10 +553,13 @@
551 @ </td></tr></table></div>
552 }
553
554 /*
555 ** WEBPAGE: test-captcha
 
 
 
556 */
557 void captcha_test(void){
558 const char *zPw = P("name");
559 if( zPw==0 || zPw[0]==0 ){
560 u64 x;
561
--- src/captcha.c
+++ src/captcha.c
@@ -414,10 +414,12 @@
414 }
415 #endif /* CAPTCHA==3 */
416
417 /*
418 ** COMMAND: test-captcha
419 **
420 ** Render an ASCII-art captcha for numbers given on the command line.
421 */
422 void test_captcha(void){
423 int i;
424 unsigned int v;
425 char *z;
@@ -551,10 +553,13 @@
553 @ </td></tr></table></div>
554 }
555
556 /*
557 ** WEBPAGE: test-captcha
558 ** Test the captcha-generator by rendering the value of the name= query
559 ** parameter using ascii-art. If name= is omitted, show a random 16-digit
560 ** hexadecimal number.
561 */
562 void captcha_test(void){
563 const char *zPw = P("name");
564 if( zPw==0 || zPw[0]==0 ){
565 u64 x;
566
+49 -35
--- src/checkin.c
+++ src/checkin.c
@@ -65,11 +65,12 @@
6565
6666
db_prepare(&q,
6767
"SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
6868
" FROM vfile "
6969
" WHERE is_selected(id) %s"
70
- " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1 /*scan*/",
70
+ " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
71
+ " ORDER BY 1 /*scan*/",
7172
blob_sql_text(&where)
7273
);
7374
blob_zero(&rewrittenPathname);
7475
while( db_step(&q)==SQLITE_ROW ){
7576
const char *zPathname = db_column_text(&q,0);
@@ -264,19 +265,20 @@
264265
if( vid ){
265266
show_common_info(vid, "checkout:", 1, 1);
266267
}
267268
db_record_repository_filename(0);
268269
print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
270
+ leaf_ambiguity_warning(vid, vid);
269271
}
270272
271273
/*
272274
** Take care of -r version of ls command
273275
*/
274276
static void ls_cmd_rev(
275277
const char *zRev, /* Revision string given */
276278
int verboseFlag, /* Verbose flag given */
277
- int showAge, /* Age flag given */
279
+ int showAge, /* Age flag given */
278280
int timeOrder /* Order by time flag given */
279281
){
280282
Stmt q;
281283
char *zOrderBy = "pathname COLLATE nocase";
282284
char *zName;
@@ -308,11 +310,11 @@
308310
309311
rid = symbolic_name_to_rid(zRev, "ci");
310312
if( rid==0 ){
311313
fossil_fatal("not a valid check-in: %s", zRev);
312314
}
313
-
315
+
314316
if( timeOrder ){
315317
zOrderBy = "mtime DESC";
316318
}
317319
318320
compute_fileage(rid,0);
@@ -333,11 +335,11 @@
333335
fossil_print("%s %7d %s\n", zTime, size, zFile);
334336
}else if( showAge ){
335337
fossil_print("%s %s\n", zTime, zFile);
336338
}else{
337339
fossil_print("%s\n", zFile);
338
- }
340
+ }
339341
}
340342
db_finalize(&q);
341343
}
342344
343345
/*
@@ -615,30 +617,30 @@
615617
db_finalize(&q);
616618
}
617619
618620
/*
619621
** COMMAND: clean
620
-** Usage: %fossil clean ?OPTIONS? ?PATH1 ...?
622
+** Usage: %fossil clean ?OPTIONS? ?PATH ...?
621623
**
622624
** Delete all "extra" files in the source tree. "Extra" files are
623625
** files that are not officially part of the checkout. This operation
624
-** cannot be undone. If paths are specified, only the directories or
625
-** files specified will be considered for cleaning.
626
-**
627
-** You will be prompted before removing each eligible file unless the
628
-** --force flag is in use or it matches the --clean option. The
629
-** GLOBPATTERN specified by the "ignore-glob" setting is used if the
630
-** --ignore option is omitted, the same with "clean-glob" and --clean
631
-** as well as "keep-glob" and --keep. If you are sure you wish to
632
-** remove all "extra" files except the ones specified with --ignore
633
-** and --keep, you can specify the optional -f|--force flag and no
634
-** prompts will be issued. If a file matches both --keep and --clean,
635
-** --keep takes precedence.
636
-**
637
-** Files and subdirectories whose names begin with "." are
638
-** normally kept. They are handled if the "--dotfiles" option
639
-** is used.
626
+** cannot be undone. If one or more PATH arguments appear, then only
627
+** the files named, or files contained with directories named, will be
628
+** removed.
629
+**
630
+** Prompted are issued to confirm the removal of each file, unless
631
+** the --force flag is used or unless the file matches glob pattern
632
+** specified by the --clean option. No file that matches glob patterns
633
+** specified by --ignore or --keep will ever be deleted. The default
634
+** values for --clean, --ignore, and --keep are determined by the
635
+** (versionable) clean-glob, ignore-glob, and keep-glob settings.
636
+** Files and subdirectories whose names begin with "." are automatically
637
+** ignored unless the --dotfiles option is used.
638
+**
639
+** The --verily option ignores the keep-glob and ignore-glob settings
640
+** and turns on --force, --dotfiles, and --emptydirs. Use the --verily
641
+** option when you really want to clean up everything.
640642
**
641643
** Options:
642644
** --allckouts Check for empty directories within any checkouts
643645
** that may be nested within the current one. This
644646
** option should be used with great care because the
@@ -656,27 +658,31 @@
656658
** argument. Matching files, if any, are removed
657659
** prior to checking for any empty directories;
658660
** therefore, directories that contain only files
659661
** that were removed will be removed as well.
660662
** -f|--force Remove files without prompting.
661
-** --verily Shorthand for: -f --emptydirs --dotfiles
663
+** -x|--verily Remove everything that is not a managed file or
664
+** the repository itself. Implies -f --emptydirs
665
+** --dotfiles. Disregard keep-glob and ignore-glob.
662666
** --clean <CSG> Never prompt for files matching this
663667
** comma separated list of glob patterns.
664668
** --ignore <CSG> Ignore files matching patterns from the
665669
** comma separated list of glob patterns.
666670
** --keep <CSG> Keep files matching this comma separated
667671
** list of glob patterns.
668
-** -n|--dry-run If given, display instead of run actions.
672
+** -n|--dry-run Delete nothing, but display what would have been
673
+** deleted.
669674
** --temp Remove only Fossil-generated temporary files.
670675
** -v|--verbose Show all files as they are removed.
671676
**
672677
** See also: addremove, extras, status
673678
*/
674679
void clean_cmd(void){
675680
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
676681
int emptyDirsFlag, dirsOnlyFlag;
677682
unsigned scanFlags = 0;
683
+ int verilyFlag = 0;
678684
const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
679685
Glob *pIgnore, *pKeep, *pClean;
680686
int nRoot;
681687
682688
dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -695,22 +701,23 @@
695701
zIgnoreFlag = find_option("ignore",0,1);
696702
verboseFlag = find_option("verbose","v",0)!=0;
697703
zKeepFlag = find_option("keep",0,1);
698704
zCleanFlag = find_option("clean",0,1);
699705
db_must_be_within_tree();
700
- if( find_option("verily",0,0)!=0 ){
701
- allFileFlag = allDirFlag = 1;
706
+ if( find_option("verily","x",0)!=0 ){
707
+ verilyFlag = allFileFlag = allDirFlag = 1;
702708
emptyDirsFlag = 1;
703709
scanFlags |= SCAN_ALL;
710
+ zCleanFlag = 0;
704711
}
705
- if( zIgnoreFlag==0 ){
712
+ if( zIgnoreFlag==0 && !verilyFlag ){
706713
zIgnoreFlag = db_get("ignore-glob", 0);
707714
}
708
- if( zKeepFlag==0 ){
715
+ if( zKeepFlag==0 && !verilyFlag ){
709716
zKeepFlag = db_get("keep-glob", 0);
710717
}
711
- if( zCleanFlag==0 ){
718
+ if( zCleanFlag==0 && !verilyFlag ){
712719
zCleanFlag = db_get("clean-glob", 0);
713720
}
714721
if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
715722
verify_all_options();
716723
pIgnore = glob_create(zIgnoreFlag);
@@ -949,14 +956,16 @@
949956
#else
950957
blob_init(&prompt, zInit, -1);
951958
#endif
952959
blob_append(&prompt,
953960
"\n"
954
- "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
961
+ "# Enter a commit message for this check-in."
962
+ " Lines beginning with # are ignored.\n"
955963
"#\n", -1
956964
);
957
- blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
965
+ blob_appendf(&prompt, "# user: %s\n",
966
+ p->zUserOvrd ? p->zUserOvrd : login_name());
958967
if( p->zBranch && p->zBranch[0] ){
959968
blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
960969
}else{
961970
char *zTags = info_tags_of_checkin(parent_rid, 1);
962971
if( zTags || p->azTag ){
@@ -1041,11 +1050,12 @@
10411050
fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
10421051
result = 1;
10431052
}
10441053
blob_reset(&fname);
10451054
}
1046
- g.aCommitFile = fossil_malloc( (bag_count(&toCommit)+1) * sizeof(g.aCommitFile[0]) );
1055
+ g.aCommitFile = fossil_malloc( (bag_count(&toCommit)+1) *
1056
+ sizeof(g.aCommitFile[0]) );
10471057
for(ii=bag_first(&toCommit); ii>0; ii=bag_next(&toCommit, ii)){
10481058
g.aCommitFile[jj++] = ii;
10491059
}
10501060
g.aCommitFile[jj] = 0;
10511061
bag_clear(&toCommit);
@@ -1269,11 +1279,13 @@
12691279
free(zParentUuid);
12701280
db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
12711281
while( db_step(&q)==SQLITE_ROW ){
12721282
char *zMergeUuid;
12731283
int mid = db_column_int(&q, 0);
1274
- if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1284
+ if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ){
1285
+ continue;
1286
+ }
12751287
zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
12761288
if( zMergeUuid ){
12771289
blob_appendf(pOut, " %s", zMergeUuid);
12781290
if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
12791291
free(zMergeUuid);
@@ -1380,11 +1392,11 @@
13801392
int fBinary; /* does the blob content appear to be binary? */
13811393
int lookFlags; /* output flags from looks_like_utf8/utf16() */
13821394
int fHasAnyCr; /* the blob contains one or more CR chars */
13831395
int fHasLoneCrOnly; /* all detected line endings are CR only */
13841396
int fHasCrLfOnly; /* all detected line endings are CR/LF pairs */
1385
- int fHasInvalidUtf8 = 0;/* contains byte-sequence which is invalid for UTF-8 */
1397
+ int fHasInvalidUtf8 = 0;/* contains invalid UTF-8 */
13861398
char *zMsg; /* Warning message */
13871399
Blob fname; /* Relative pathname of the file */
13881400
static int allOk = 0; /* Set to true to disable this routine */
13891401
13901402
if( allOk ) return 0;
@@ -1459,11 +1471,12 @@
14591471
zWarning = "Unicode";
14601472
zDisable = "\"encoding-glob\" setting";
14611473
}
14621474
file_relative_name(zFilename, &fname, 0);
14631475
zMsg = mprintf(
1464
- "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
1476
+ "%s contains %s. Use --no-warnings or the %s to"
1477
+ " disable this warning.\n"
14651478
"Commit anyhow (a=all/%sy/N)? ",
14661479
blob_str(&fname), zWarning, zDisable, zConvert);
14671480
prompt_user(zMsg, &ans);
14681481
fossil_free(zMsg);
14691482
cReply = blob_str(&ans)[0];
@@ -1659,11 +1672,12 @@
16591672
sCiInfo.closeFlag = find_option("close",0,0)!=0;
16601673
sCiInfo.integrateFlag = find_option("integrate",0,0)!=0;
16611674
sCiInfo.zMimetype = find_option("mimetype",0,1);
16621675
while( (zTag = find_option("tag",0,1))!=0 ){
16631676
if( zTag[0]==0 ) continue;
1664
- sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2));
1677
+ sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag,
1678
+ sizeof(char*)*(nTag+2));
16651679
sCiInfo.azTag[nTag++] = zTag;
16661680
sCiInfo.azTag[nTag] = 0;
16671681
}
16681682
zComFile = find_option("message-file", "M", 1);
16691683
if( find_option("private",0,0) ){
16701684
--- src/checkin.c
+++ src/checkin.c
@@ -65,11 +65,12 @@
65
66 db_prepare(&q,
67 "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
68 " FROM vfile "
69 " WHERE is_selected(id) %s"
70 " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1 /*scan*/",
 
71 blob_sql_text(&where)
72 );
73 blob_zero(&rewrittenPathname);
74 while( db_step(&q)==SQLITE_ROW ){
75 const char *zPathname = db_column_text(&q,0);
@@ -264,19 +265,20 @@
264 if( vid ){
265 show_common_info(vid, "checkout:", 1, 1);
266 }
267 db_record_repository_filename(0);
268 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
 
269 }
270
271 /*
272 ** Take care of -r version of ls command
273 */
274 static void ls_cmd_rev(
275 const char *zRev, /* Revision string given */
276 int verboseFlag, /* Verbose flag given */
277 int showAge, /* Age flag given */
278 int timeOrder /* Order by time flag given */
279 ){
280 Stmt q;
281 char *zOrderBy = "pathname COLLATE nocase";
282 char *zName;
@@ -308,11 +310,11 @@
308
309 rid = symbolic_name_to_rid(zRev, "ci");
310 if( rid==0 ){
311 fossil_fatal("not a valid check-in: %s", zRev);
312 }
313
314 if( timeOrder ){
315 zOrderBy = "mtime DESC";
316 }
317
318 compute_fileage(rid,0);
@@ -333,11 +335,11 @@
333 fossil_print("%s %7d %s\n", zTime, size, zFile);
334 }else if( showAge ){
335 fossil_print("%s %s\n", zTime, zFile);
336 }else{
337 fossil_print("%s\n", zFile);
338 }
339 }
340 db_finalize(&q);
341 }
342
343 /*
@@ -615,30 +617,30 @@
615 db_finalize(&q);
616 }
617
618 /*
619 ** COMMAND: clean
620 ** Usage: %fossil clean ?OPTIONS? ?PATH1 ...?
621 **
622 ** Delete all "extra" files in the source tree. "Extra" files are
623 ** files that are not officially part of the checkout. This operation
624 ** cannot be undone. If paths are specified, only the directories or
625 ** files specified will be considered for cleaning.
626 **
627 ** You will be prompted before removing each eligible file unless the
628 ** --force flag is in use or it matches the --clean option. The
629 ** GLOBPATTERN specified by the "ignore-glob" setting is used if the
630 ** --ignore option is omitted, the same with "clean-glob" and --clean
631 ** as well as "keep-glob" and --keep. If you are sure you wish to
632 ** remove all "extra" files except the ones specified with --ignore
633 ** and --keep, you can specify the optional -f|--force flag and no
634 ** prompts will be issued. If a file matches both --keep and --clean,
635 ** --keep takes precedence.
636 **
637 ** Files and subdirectories whose names begin with "." are
638 ** normally kept. They are handled if the "--dotfiles" option
639 ** is used.
640 **
641 ** Options:
642 ** --allckouts Check for empty directories within any checkouts
643 ** that may be nested within the current one. This
644 ** option should be used with great care because the
@@ -656,27 +658,31 @@
656 ** argument. Matching files, if any, are removed
657 ** prior to checking for any empty directories;
658 ** therefore, directories that contain only files
659 ** that were removed will be removed as well.
660 ** -f|--force Remove files without prompting.
661 ** --verily Shorthand for: -f --emptydirs --dotfiles
 
 
662 ** --clean <CSG> Never prompt for files matching this
663 ** comma separated list of glob patterns.
664 ** --ignore <CSG> Ignore files matching patterns from the
665 ** comma separated list of glob patterns.
666 ** --keep <CSG> Keep files matching this comma separated
667 ** list of glob patterns.
668 ** -n|--dry-run If given, display instead of run actions.
 
669 ** --temp Remove only Fossil-generated temporary files.
670 ** -v|--verbose Show all files as they are removed.
671 **
672 ** See also: addremove, extras, status
673 */
674 void clean_cmd(void){
675 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
676 int emptyDirsFlag, dirsOnlyFlag;
677 unsigned scanFlags = 0;
 
678 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
679 Glob *pIgnore, *pKeep, *pClean;
680 int nRoot;
681
682 dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -695,22 +701,23 @@
695 zIgnoreFlag = find_option("ignore",0,1);
696 verboseFlag = find_option("verbose","v",0)!=0;
697 zKeepFlag = find_option("keep",0,1);
698 zCleanFlag = find_option("clean",0,1);
699 db_must_be_within_tree();
700 if( find_option("verily",0,0)!=0 ){
701 allFileFlag = allDirFlag = 1;
702 emptyDirsFlag = 1;
703 scanFlags |= SCAN_ALL;
 
704 }
705 if( zIgnoreFlag==0 ){
706 zIgnoreFlag = db_get("ignore-glob", 0);
707 }
708 if( zKeepFlag==0 ){
709 zKeepFlag = db_get("keep-glob", 0);
710 }
711 if( zCleanFlag==0 ){
712 zCleanFlag = db_get("clean-glob", 0);
713 }
714 if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
715 verify_all_options();
716 pIgnore = glob_create(zIgnoreFlag);
@@ -949,14 +956,16 @@
949 #else
950 blob_init(&prompt, zInit, -1);
951 #endif
952 blob_append(&prompt,
953 "\n"
954 "# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
 
955 "#\n", -1
956 );
957 blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
 
958 if( p->zBranch && p->zBranch[0] ){
959 blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
960 }else{
961 char *zTags = info_tags_of_checkin(parent_rid, 1);
962 if( zTags || p->azTag ){
@@ -1041,11 +1050,12 @@
1041 fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
1042 result = 1;
1043 }
1044 blob_reset(&fname);
1045 }
1046 g.aCommitFile = fossil_malloc( (bag_count(&toCommit)+1) * sizeof(g.aCommitFile[0]) );
 
1047 for(ii=bag_first(&toCommit); ii>0; ii=bag_next(&toCommit, ii)){
1048 g.aCommitFile[jj++] = ii;
1049 }
1050 g.aCommitFile[jj] = 0;
1051 bag_clear(&toCommit);
@@ -1269,11 +1279,13 @@
1269 free(zParentUuid);
1270 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1271 while( db_step(&q)==SQLITE_ROW ){
1272 char *zMergeUuid;
1273 int mid = db_column_int(&q, 0);
1274 if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
 
 
1275 zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1276 if( zMergeUuid ){
1277 blob_appendf(pOut, " %s", zMergeUuid);
1278 if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1279 free(zMergeUuid);
@@ -1380,11 +1392,11 @@
1380 int fBinary; /* does the blob content appear to be binary? */
1381 int lookFlags; /* output flags from looks_like_utf8/utf16() */
1382 int fHasAnyCr; /* the blob contains one or more CR chars */
1383 int fHasLoneCrOnly; /* all detected line endings are CR only */
1384 int fHasCrLfOnly; /* all detected line endings are CR/LF pairs */
1385 int fHasInvalidUtf8 = 0;/* contains byte-sequence which is invalid for UTF-8 */
1386 char *zMsg; /* Warning message */
1387 Blob fname; /* Relative pathname of the file */
1388 static int allOk = 0; /* Set to true to disable this routine */
1389
1390 if( allOk ) return 0;
@@ -1459,11 +1471,12 @@
1459 zWarning = "Unicode";
1460 zDisable = "\"encoding-glob\" setting";
1461 }
1462 file_relative_name(zFilename, &fname, 0);
1463 zMsg = mprintf(
1464 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
 
1465 "Commit anyhow (a=all/%sy/N)? ",
1466 blob_str(&fname), zWarning, zDisable, zConvert);
1467 prompt_user(zMsg, &ans);
1468 fossil_free(zMsg);
1469 cReply = blob_str(&ans)[0];
@@ -1659,11 +1672,12 @@
1659 sCiInfo.closeFlag = find_option("close",0,0)!=0;
1660 sCiInfo.integrateFlag = find_option("integrate",0,0)!=0;
1661 sCiInfo.zMimetype = find_option("mimetype",0,1);
1662 while( (zTag = find_option("tag",0,1))!=0 ){
1663 if( zTag[0]==0 ) continue;
1664 sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2));
 
1665 sCiInfo.azTag[nTag++] = zTag;
1666 sCiInfo.azTag[nTag] = 0;
1667 }
1668 zComFile = find_option("message-file", "M", 1);
1669 if( find_option("private",0,0) ){
1670
--- src/checkin.c
+++ src/checkin.c
@@ -65,11 +65,12 @@
65
66 db_prepare(&q,
67 "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
68 " FROM vfile "
69 " WHERE is_selected(id) %s"
70 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
71 " ORDER BY 1 /*scan*/",
72 blob_sql_text(&where)
73 );
74 blob_zero(&rewrittenPathname);
75 while( db_step(&q)==SQLITE_ROW ){
76 const char *zPathname = db_column_text(&q,0);
@@ -264,19 +265,20 @@
265 if( vid ){
266 show_common_info(vid, "checkout:", 1, 1);
267 }
268 db_record_repository_filename(0);
269 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
270 leaf_ambiguity_warning(vid, vid);
271 }
272
273 /*
274 ** Take care of -r version of ls command
275 */
276 static void ls_cmd_rev(
277 const char *zRev, /* Revision string given */
278 int verboseFlag, /* Verbose flag given */
279 int showAge, /* Age flag given */
280 int timeOrder /* Order by time flag given */
281 ){
282 Stmt q;
283 char *zOrderBy = "pathname COLLATE nocase";
284 char *zName;
@@ -308,11 +310,11 @@
310
311 rid = symbolic_name_to_rid(zRev, "ci");
312 if( rid==0 ){
313 fossil_fatal("not a valid check-in: %s", zRev);
314 }
315
316 if( timeOrder ){
317 zOrderBy = "mtime DESC";
318 }
319
320 compute_fileage(rid,0);
@@ -333,11 +335,11 @@
335 fossil_print("%s %7d %s\n", zTime, size, zFile);
336 }else if( showAge ){
337 fossil_print("%s %s\n", zTime, zFile);
338 }else{
339 fossil_print("%s\n", zFile);
340 }
341 }
342 db_finalize(&q);
343 }
344
345 /*
@@ -615,30 +617,30 @@
617 db_finalize(&q);
618 }
619
620 /*
621 ** COMMAND: clean
622 ** Usage: %fossil clean ?OPTIONS? ?PATH ...?
623 **
624 ** Delete all "extra" files in the source tree. "Extra" files are
625 ** files that are not officially part of the checkout. This operation
626 ** cannot be undone. If one or more PATH arguments appear, then only
627 ** the files named, or files contained with directories named, will be
628 ** removed.
629 **
630 ** Prompted are issued to confirm the removal of each file, unless
631 ** the --force flag is used or unless the file matches glob pattern
632 ** specified by the --clean option. No file that matches glob patterns
633 ** specified by --ignore or --keep will ever be deleted. The default
634 ** values for --clean, --ignore, and --keep are determined by the
635 ** (versionable) clean-glob, ignore-glob, and keep-glob settings.
636 ** Files and subdirectories whose names begin with "." are automatically
637 ** ignored unless the --dotfiles option is used.
638 **
639 ** The --verily option ignores the keep-glob and ignore-glob settings
640 ** and turns on --force, --dotfiles, and --emptydirs. Use the --verily
641 ** option when you really want to clean up everything.
642 **
643 ** Options:
644 ** --allckouts Check for empty directories within any checkouts
645 ** that may be nested within the current one. This
646 ** option should be used with great care because the
@@ -656,27 +658,31 @@
658 ** argument. Matching files, if any, are removed
659 ** prior to checking for any empty directories;
660 ** therefore, directories that contain only files
661 ** that were removed will be removed as well.
662 ** -f|--force Remove files without prompting.
663 ** -x|--verily Remove everything that is not a managed file or
664 ** the repository itself. Implies -f --emptydirs
665 ** --dotfiles. Disregard keep-glob and ignore-glob.
666 ** --clean <CSG> Never prompt for files matching this
667 ** comma separated list of glob patterns.
668 ** --ignore <CSG> Ignore files matching patterns from the
669 ** comma separated list of glob patterns.
670 ** --keep <CSG> Keep files matching this comma separated
671 ** list of glob patterns.
672 ** -n|--dry-run Delete nothing, but display what would have been
673 ** deleted.
674 ** --temp Remove only Fossil-generated temporary files.
675 ** -v|--verbose Show all files as they are removed.
676 **
677 ** See also: addremove, extras, status
678 */
679 void clean_cmd(void){
680 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
681 int emptyDirsFlag, dirsOnlyFlag;
682 unsigned scanFlags = 0;
683 int verilyFlag = 0;
684 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
685 Glob *pIgnore, *pKeep, *pClean;
686 int nRoot;
687
688 dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -695,22 +701,23 @@
701 zIgnoreFlag = find_option("ignore",0,1);
702 verboseFlag = find_option("verbose","v",0)!=0;
703 zKeepFlag = find_option("keep",0,1);
704 zCleanFlag = find_option("clean",0,1);
705 db_must_be_within_tree();
706 if( find_option("verily","x",0)!=0 ){
707 verilyFlag = allFileFlag = allDirFlag = 1;
708 emptyDirsFlag = 1;
709 scanFlags |= SCAN_ALL;
710 zCleanFlag = 0;
711 }
712 if( zIgnoreFlag==0 && !verilyFlag ){
713 zIgnoreFlag = db_get("ignore-glob", 0);
714 }
715 if( zKeepFlag==0 && !verilyFlag ){
716 zKeepFlag = db_get("keep-glob", 0);
717 }
718 if( zCleanFlag==0 && !verilyFlag ){
719 zCleanFlag = db_get("clean-glob", 0);
720 }
721 if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
722 verify_all_options();
723 pIgnore = glob_create(zIgnoreFlag);
@@ -949,14 +956,16 @@
956 #else
957 blob_init(&prompt, zInit, -1);
958 #endif
959 blob_append(&prompt,
960 "\n"
961 "# Enter a commit message for this check-in."
962 " Lines beginning with # are ignored.\n"
963 "#\n", -1
964 );
965 blob_appendf(&prompt, "# user: %s\n",
966 p->zUserOvrd ? p->zUserOvrd : login_name());
967 if( p->zBranch && p->zBranch[0] ){
968 blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
969 }else{
970 char *zTags = info_tags_of_checkin(parent_rid, 1);
971 if( zTags || p->azTag ){
@@ -1041,11 +1050,12 @@
1050 fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
1051 result = 1;
1052 }
1053 blob_reset(&fname);
1054 }
1055 g.aCommitFile = fossil_malloc( (bag_count(&toCommit)+1) *
1056 sizeof(g.aCommitFile[0]) );
1057 for(ii=bag_first(&toCommit); ii>0; ii=bag_next(&toCommit, ii)){
1058 g.aCommitFile[jj++] = ii;
1059 }
1060 g.aCommitFile[jj] = 0;
1061 bag_clear(&toCommit);
@@ -1269,11 +1279,13 @@
1279 free(zParentUuid);
1280 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1281 while( db_step(&q)==SQLITE_ROW ){
1282 char *zMergeUuid;
1283 int mid = db_column_int(&q, 0);
1284 if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ){
1285 continue;
1286 }
1287 zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1288 if( zMergeUuid ){
1289 blob_appendf(pOut, " %s", zMergeUuid);
1290 if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1291 free(zMergeUuid);
@@ -1380,11 +1392,11 @@
1392 int fBinary; /* does the blob content appear to be binary? */
1393 int lookFlags; /* output flags from looks_like_utf8/utf16() */
1394 int fHasAnyCr; /* the blob contains one or more CR chars */
1395 int fHasLoneCrOnly; /* all detected line endings are CR only */
1396 int fHasCrLfOnly; /* all detected line endings are CR/LF pairs */
1397 int fHasInvalidUtf8 = 0;/* contains invalid UTF-8 */
1398 char *zMsg; /* Warning message */
1399 Blob fname; /* Relative pathname of the file */
1400 static int allOk = 0; /* Set to true to disable this routine */
1401
1402 if( allOk ) return 0;
@@ -1459,11 +1471,12 @@
1471 zWarning = "Unicode";
1472 zDisable = "\"encoding-glob\" setting";
1473 }
1474 file_relative_name(zFilename, &fname, 0);
1475 zMsg = mprintf(
1476 "%s contains %s. Use --no-warnings or the %s to"
1477 " disable this warning.\n"
1478 "Commit anyhow (a=all/%sy/N)? ",
1479 blob_str(&fname), zWarning, zDisable, zConvert);
1480 prompt_user(zMsg, &ans);
1481 fossil_free(zMsg);
1482 cReply = blob_str(&ans)[0];
@@ -1659,11 +1672,12 @@
1672 sCiInfo.closeFlag = find_option("close",0,0)!=0;
1673 sCiInfo.integrateFlag = find_option("integrate",0,0)!=0;
1674 sCiInfo.zMimetype = find_option("mimetype",0,1);
1675 while( (zTag = find_option("tag",0,1))!=0 ){
1676 if( zTag[0]==0 ) continue;
1677 sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag,
1678 sizeof(char*)*(nTag+2));
1679 sCiInfo.azTag[nTag++] = zTag;
1680 sCiInfo.azTag[nTag] = 0;
1681 }
1682 zComFile = find_option("message-file", "M", 1);
1683 if( find_option("private",0,0) ){
1684
+1 -1
--- src/clone.c
+++ src/clone.c
@@ -206,11 +206,11 @@
206206
rebuild_db(0, 1, 0);
207207
fossil_print("Extra delta compression... "); fflush(stdout);
208208
extra_deltification();
209209
db_end_transaction(0);
210210
fossil_print("\nVacuuming the database... "); fflush(stdout);
211
- if( db_int(0, "PRAGMA page_count")>1000
211
+ if( db_int(0, "PRAGMA page_count")>1000
212212
&& db_int(0, "PRAGMA page_size")<8192 ){
213213
db_multi_exec("PRAGMA page_size=8192;");
214214
}
215215
db_multi_exec("VACUUM");
216216
fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
217217
--- src/clone.c
+++ src/clone.c
@@ -206,11 +206,11 @@
206 rebuild_db(0, 1, 0);
207 fossil_print("Extra delta compression... "); fflush(stdout);
208 extra_deltification();
209 db_end_transaction(0);
210 fossil_print("\nVacuuming the database... "); fflush(stdout);
211 if( db_int(0, "PRAGMA page_count")>1000
212 && db_int(0, "PRAGMA page_size")<8192 ){
213 db_multi_exec("PRAGMA page_size=8192;");
214 }
215 db_multi_exec("VACUUM");
216 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
217
--- src/clone.c
+++ src/clone.c
@@ -206,11 +206,11 @@
206 rebuild_db(0, 1, 0);
207 fossil_print("Extra delta compression... "); fflush(stdout);
208 extra_deltification();
209 db_end_transaction(0);
210 fossil_print("\nVacuuming the database... "); fflush(stdout);
211 if( db_int(0, "PRAGMA page_count")>1000
212 && db_int(0, "PRAGMA page_size")<8192 ){
213 db_multi_exec("PRAGMA page_size=8192;");
214 }
215 db_multi_exec("VACUUM");
216 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
217
+1 -3
--- src/comformat.c
+++ src/comformat.c
@@ -23,13 +23,11 @@
2323
#include <assert.h>
2424
#ifdef _WIN32
2525
# include <windows.h>
2626
#else
2727
# include <termios.h>
28
-# if defined(TIOCGWINSZ)
29
-# include <sys/ioctl.h>
30
-# endif
28
+# include <sys/ioctl.h>
3129
#endif
3230
3331
#if INTERFACE
3432
#define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */
3533
#define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */
3634
--- src/comformat.c
+++ src/comformat.c
@@ -23,13 +23,11 @@
23 #include <assert.h>
24 #ifdef _WIN32
25 # include <windows.h>
26 #else
27 # include <termios.h>
28 # if defined(TIOCGWINSZ)
29 # include <sys/ioctl.h>
30 # endif
31 #endif
32
33 #if INTERFACE
34 #define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */
35 #define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */
36
--- src/comformat.c
+++ src/comformat.c
@@ -23,13 +23,11 @@
23 #include <assert.h>
24 #ifdef _WIN32
25 # include <windows.h>
26 #else
27 # include <termios.h>
28 # include <sys/ioctl.h>
 
 
29 #endif
30
31 #if INTERFACE
32 #define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */
33 #define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */
34
+1 -1
--- src/db.c
+++ src/db.c
@@ -1646,11 +1646,11 @@
16461646
verify_all_options();
16471647
16481648
if( g.argc!=3 ){
16491649
usage("REPOSITORY-NAME");
16501650
}
1651
-
1651
+
16521652
if( -1 != file_size(g.argv[2]) ){
16531653
fossil_fatal("file already exists: %s", g.argv[2]);
16541654
}
16551655
16561656
db_create_repository(g.argv[2]);
16571657
--- src/db.c
+++ src/db.c
@@ -1646,11 +1646,11 @@
1646 verify_all_options();
1647
1648 if( g.argc!=3 ){
1649 usage("REPOSITORY-NAME");
1650 }
1651
1652 if( -1 != file_size(g.argv[2]) ){
1653 fossil_fatal("file already exists: %s", g.argv[2]);
1654 }
1655
1656 db_create_repository(g.argv[2]);
1657
--- src/db.c
+++ src/db.c
@@ -1646,11 +1646,11 @@
1646 verify_all_options();
1647
1648 if( g.argc!=3 ){
1649 usage("REPOSITORY-NAME");
1650 }
1651
1652 if( -1 != file_size(g.argv[2]) ){
1653 fossil_fatal("file already exists: %s", g.argv[2]);
1654 }
1655
1656 db_create_repository(g.argv[2]);
1657
+1 -1
--- src/db.c
+++ src/db.c
@@ -1646,11 +1646,11 @@
16461646
verify_all_options();
16471647
16481648
if( g.argc!=3 ){
16491649
usage("REPOSITORY-NAME");
16501650
}
1651
-
1651
+
16521652
if( -1 != file_size(g.argv[2]) ){
16531653
fossil_fatal("file already exists: %s", g.argv[2]);
16541654
}
16551655
16561656
db_create_repository(g.argv[2]);
16571657
--- src/db.c
+++ src/db.c
@@ -1646,11 +1646,11 @@
1646 verify_all_options();
1647
1648 if( g.argc!=3 ){
1649 usage("REPOSITORY-NAME");
1650 }
1651
1652 if( -1 != file_size(g.argv[2]) ){
1653 fossil_fatal("file already exists: %s", g.argv[2]);
1654 }
1655
1656 db_create_repository(g.argv[2]);
1657
--- src/db.c
+++ src/db.c
@@ -1646,11 +1646,11 @@
1646 verify_all_options();
1647
1648 if( g.argc!=3 ){
1649 usage("REPOSITORY-NAME");
1650 }
1651
1652 if( -1 != file_size(g.argv[2]) ){
1653 fossil_fatal("file already exists: %s", g.argv[2]);
1654 }
1655
1656 db_create_repository(g.argv[2]);
1657
--- src/descendants.c
+++ src/descendants.c
@@ -352,12 +352,13 @@
352352
** The --recompute flag causes the content of the "leaf" table in the
353353
** repository database to be recomputed.
354354
**
355355
** Options:
356356
** -a|--all show ALL leaves
357
-** -c|--closed show only closed leaves
358357
** --bybranch order output by branch name
358
+** -c|--closed show only closed leaves
359
+** -m|--multiple show only cases with multiple leaves on a single branch
359360
** --recompute recompute the "leaf" table in the repository DB
360361
** -W|--width <num> Width of lines (default is to auto-detect). Must be
361362
** >39 or 0 (= no limit, resulting in a single line per
362363
** entry).
363364
**
@@ -368,32 +369,65 @@
368369
Blob sql;
369370
int showAll = find_option("all", "a", 0)!=0;
370371
int showClosed = find_option("closed", "c", 0)!=0;
371372
int recomputeFlag = find_option("recompute",0,0)!=0;
372373
int byBranch = find_option("bybranch",0,0)!=0;
374
+ int multipleFlag = find_option("multiple","m",0)!=0;
373375
const char *zWidth = find_option("width","W",1);
374376
char *zLastBr = 0;
375377
int n, width;
376378
char zLineNo[10];
377379
380
+ if( multipleFlag ) byBranch = 1;
378381
if( zWidth ){
379382
width = atoi(zWidth);
380383
if( (width!=0) && (width<=39) ){
381384
fossil_fatal("-W|--width value must be >39 or 0");
382385
}
383386
}else{
384387
width = -1;
385388
}
386389
db_find_and_open_repository(0,0);
387
-
390
+
388391
/* We should be done with options.. */
389392
verify_all_options();
390393
391394
if( recomputeFlag ) leaf_rebuild();
392395
blob_zero(&sql);
393396
blob_append(&sql, timeline_query_for_tty(), -1);
394
- blob_append_sql(&sql, " AND blob.rid IN leaf");
397
+ if( !multipleFlag ){
398
+ /* The usual case - show all leaves */
399
+ blob_append_sql(&sql, " AND blob.rid IN leaf");
400
+ }else{
401
+ /* Show only leaves where two are more occur in the same branch */
402
+ db_multi_exec(
403
+ "CREATE TEMP TABLE openLeaf(rid INTEGER PRIMARY KEY);"
404
+ "INSERT INTO openLeaf(rid)"
405
+ " SELECT rid FROM leaf"
406
+ " WHERE NOT EXISTS("
407
+ " SELECT 1 FROM tagxref"
408
+ " WHERE tagid=%d AND tagtype>0 AND rid=leaf.rid);",
409
+ TAG_CLOSED
410
+ );
411
+ db_multi_exec(
412
+ "CREATE TEMP TABLE ambiguousBranch(brname TEXT);"
413
+ "INSERT INTO ambiguousBranch(brname)"
414
+ " SELECT (SELECT value FROM tagxref WHERE tagid=%d AND rid=openLeaf.rid)"
415
+ " FROM openLeaf"
416
+ " GROUP BY 1 HAVING count(*)>1;",
417
+ TAG_BRANCH
418
+ );
419
+ db_multi_exec(
420
+ "CREATE TEMP TABLE ambiguousLeaf(rid INTEGER PRIMARY KEY);\n"
421
+ "INSERT INTO ambiguousLeaf(rid)\n"
422
+ " SELECT rid FROM openLeaf\n"
423
+ " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=openLeaf.rid)"
424
+ " IN (SELECT brname FROM ambiguousBranch);",
425
+ TAG_BRANCH
426
+ );
427
+ blob_append_sql(&sql, " AND blob.rid IN ambiguousLeaf");
428
+ }
395429
if( showClosed ){
396430
blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
397431
}else if( !showAll ){
398432
blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
399433
}
@@ -415,10 +449,11 @@
415449
416450
if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
417451
fossil_print("*** %s ***\n", zBr);
418452
fossil_free(zLastBr);
419453
zLastBr = fossil_strdup(zBr);
454
+ if( multipleFlag ) n = 0;
420455
}
421456
n++;
422457
sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
423458
fossil_print("%6s ", zLineNo);
424459
z = mprintf("%s [%S] %s", zDate, zId, zCom);
@@ -430,11 +465,21 @@
430465
}
431466
432467
/*
433468
** WEBPAGE: leaves
434469
**
435
-** Find leaves of all branches.
470
+** Show leaf check-ins in a timeline. By default only open leaves
471
+** are listed.
472
+**
473
+** A "leaf" is a check-in with no children in the same branch. A
474
+** "closed leaf" is a leaf that has a "closed" tag. An "open leaf"
475
+** is a leaf without a "closed" tag.
476
+**
477
+** Query parameters:
478
+**
479
+** all Show all leaves
480
+** closed Show only closed leaves
436481
*/
437482
void leaves_page(void){
438483
Blob sql;
439484
Stmt q;
440485
int showAll = P("all")!=0;
441486
--- src/descendants.c
+++ src/descendants.c
@@ -352,12 +352,13 @@
352 ** The --recompute flag causes the content of the "leaf" table in the
353 ** repository database to be recomputed.
354 **
355 ** Options:
356 ** -a|--all show ALL leaves
357 ** -c|--closed show only closed leaves
358 ** --bybranch order output by branch name
 
 
359 ** --recompute recompute the "leaf" table in the repository DB
360 ** -W|--width <num> Width of lines (default is to auto-detect). Must be
361 ** >39 or 0 (= no limit, resulting in a single line per
362 ** entry).
363 **
@@ -368,32 +369,65 @@
368 Blob sql;
369 int showAll = find_option("all", "a", 0)!=0;
370 int showClosed = find_option("closed", "c", 0)!=0;
371 int recomputeFlag = find_option("recompute",0,0)!=0;
372 int byBranch = find_option("bybranch",0,0)!=0;
 
373 const char *zWidth = find_option("width","W",1);
374 char *zLastBr = 0;
375 int n, width;
376 char zLineNo[10];
377
 
378 if( zWidth ){
379 width = atoi(zWidth);
380 if( (width!=0) && (width<=39) ){
381 fossil_fatal("-W|--width value must be >39 or 0");
382 }
383 }else{
384 width = -1;
385 }
386 db_find_and_open_repository(0,0);
387
388 /* We should be done with options.. */
389 verify_all_options();
390
391 if( recomputeFlag ) leaf_rebuild();
392 blob_zero(&sql);
393 blob_append(&sql, timeline_query_for_tty(), -1);
394 blob_append_sql(&sql, " AND blob.rid IN leaf");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395 if( showClosed ){
396 blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
397 }else if( !showAll ){
398 blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
399 }
@@ -415,10 +449,11 @@
415
416 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
417 fossil_print("*** %s ***\n", zBr);
418 fossil_free(zLastBr);
419 zLastBr = fossil_strdup(zBr);
 
420 }
421 n++;
422 sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
423 fossil_print("%6s ", zLineNo);
424 z = mprintf("%s [%S] %s", zDate, zId, zCom);
@@ -430,11 +465,21 @@
430 }
431
432 /*
433 ** WEBPAGE: leaves
434 **
435 ** Find leaves of all branches.
 
 
 
 
 
 
 
 
 
 
436 */
437 void leaves_page(void){
438 Blob sql;
439 Stmt q;
440 int showAll = P("all")!=0;
441
--- src/descendants.c
+++ src/descendants.c
@@ -352,12 +352,13 @@
352 ** The --recompute flag causes the content of the "leaf" table in the
353 ** repository database to be recomputed.
354 **
355 ** Options:
356 ** -a|--all show ALL leaves
 
357 ** --bybranch order output by branch name
358 ** -c|--closed show only closed leaves
359 ** -m|--multiple show only cases with multiple leaves on a single branch
360 ** --recompute recompute the "leaf" table in the repository DB
361 ** -W|--width <num> Width of lines (default is to auto-detect). Must be
362 ** >39 or 0 (= no limit, resulting in a single line per
363 ** entry).
364 **
@@ -368,32 +369,65 @@
369 Blob sql;
370 int showAll = find_option("all", "a", 0)!=0;
371 int showClosed = find_option("closed", "c", 0)!=0;
372 int recomputeFlag = find_option("recompute",0,0)!=0;
373 int byBranch = find_option("bybranch",0,0)!=0;
374 int multipleFlag = find_option("multiple","m",0)!=0;
375 const char *zWidth = find_option("width","W",1);
376 char *zLastBr = 0;
377 int n, width;
378 char zLineNo[10];
379
380 if( multipleFlag ) byBranch = 1;
381 if( zWidth ){
382 width = atoi(zWidth);
383 if( (width!=0) && (width<=39) ){
384 fossil_fatal("-W|--width value must be >39 or 0");
385 }
386 }else{
387 width = -1;
388 }
389 db_find_and_open_repository(0,0);
390
391 /* We should be done with options.. */
392 verify_all_options();
393
394 if( recomputeFlag ) leaf_rebuild();
395 blob_zero(&sql);
396 blob_append(&sql, timeline_query_for_tty(), -1);
397 if( !multipleFlag ){
398 /* The usual case - show all leaves */
399 blob_append_sql(&sql, " AND blob.rid IN leaf");
400 }else{
401 /* Show only leaves where two are more occur in the same branch */
402 db_multi_exec(
403 "CREATE TEMP TABLE openLeaf(rid INTEGER PRIMARY KEY);"
404 "INSERT INTO openLeaf(rid)"
405 " SELECT rid FROM leaf"
406 " WHERE NOT EXISTS("
407 " SELECT 1 FROM tagxref"
408 " WHERE tagid=%d AND tagtype>0 AND rid=leaf.rid);",
409 TAG_CLOSED
410 );
411 db_multi_exec(
412 "CREATE TEMP TABLE ambiguousBranch(brname TEXT);"
413 "INSERT INTO ambiguousBranch(brname)"
414 " SELECT (SELECT value FROM tagxref WHERE tagid=%d AND rid=openLeaf.rid)"
415 " FROM openLeaf"
416 " GROUP BY 1 HAVING count(*)>1;",
417 TAG_BRANCH
418 );
419 db_multi_exec(
420 "CREATE TEMP TABLE ambiguousLeaf(rid INTEGER PRIMARY KEY);\n"
421 "INSERT INTO ambiguousLeaf(rid)\n"
422 " SELECT rid FROM openLeaf\n"
423 " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=openLeaf.rid)"
424 " IN (SELECT brname FROM ambiguousBranch);",
425 TAG_BRANCH
426 );
427 blob_append_sql(&sql, " AND blob.rid IN ambiguousLeaf");
428 }
429 if( showClosed ){
430 blob_append_sql(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
431 }else if( !showAll ){
432 blob_append_sql(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
433 }
@@ -415,10 +449,11 @@
449
450 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
451 fossil_print("*** %s ***\n", zBr);
452 fossil_free(zLastBr);
453 zLastBr = fossil_strdup(zBr);
454 if( multipleFlag ) n = 0;
455 }
456 n++;
457 sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
458 fossil_print("%6s ", zLineNo);
459 z = mprintf("%s [%S] %s", zDate, zId, zCom);
@@ -430,11 +465,21 @@
465 }
466
467 /*
468 ** WEBPAGE: leaves
469 **
470 ** Show leaf check-ins in a timeline. By default only open leaves
471 ** are listed.
472 **
473 ** A "leaf" is a check-in with no children in the same branch. A
474 ** "closed leaf" is a leaf that has a "closed" tag. An "open leaf"
475 ** is a leaf without a "closed" tag.
476 **
477 ** Query parameters:
478 **
479 ** all Show all leaves
480 ** closed Show only closed leaves
481 */
482 void leaves_page(void){
483 Blob sql;
484 Stmt q;
485 int showAll = P("all")!=0;
486
+17 -1
--- src/diff.c
+++ src/diff.c
@@ -1929,10 +1929,16 @@
19291929
return diffFlags;
19301930
}
19311931
19321932
/*
19331933
** COMMAND: test-rawdiff
1934
+**
1935
+** Usage: %fossil test-rawdiff FILE1 FILE2
1936
+**
1937
+** Show a minimal sequence of Copy/Delete/Insert operations needed to convert
1938
+** FILE1 into FILE2. This command is intended for use in testing and debugging
1939
+** the built-in difference engine of Fossil.
19341940
*/
19351941
void test_rawdiff_cmd(void){
19361942
Blob a, b;
19371943
int r;
19381944
int i;
@@ -2207,17 +2213,27 @@
22072213
/*
22082214
** WEBPAGE: annotate
22092215
** WEBPAGE: blame
22102216
** WEBPAGE: praise
22112217
**
2218
+** URL: /annotate?checkin=ID&filename=FILENAME
2219
+** URL: /blame?checkin=ID&filename=FILENAME
2220
+** URL: /praise?checkin=ID&filename=FILENAME
2221
+**
2222
+** Show the most recent change to each line of a text file. /annotate shows
2223
+** the date of the changes and the check-in SHA1 hash (with a link to the
2224
+** check-in). /blame and /praise also show the user who made the check-in.
2225
+**
22122226
** Query parameters:
22132227
**
22142228
** checkin=ID The manifest ID at which to start the annotation
22152229
** filename=FILENAME The filename.
22162230
** filevers Show file versions rather than check-in versions
2217
-** log=BOOLEAN Show a log of versions analyzed
22182231
** limit=N Limit the search depth to N ancestors
2232
+** log=BOOLEAN Show a log of versions analyzed
2233
+** w Ignore whitespace
2234
+**
22192235
*/
22202236
void annotation_page(void){
22212237
int mid;
22222238
int fnid;
22232239
int i;
22242240
--- src/diff.c
+++ src/diff.c
@@ -1929,10 +1929,16 @@
1929 return diffFlags;
1930 }
1931
1932 /*
1933 ** COMMAND: test-rawdiff
 
 
 
 
 
 
1934 */
1935 void test_rawdiff_cmd(void){
1936 Blob a, b;
1937 int r;
1938 int i;
@@ -2207,17 +2213,27 @@
2207 /*
2208 ** WEBPAGE: annotate
2209 ** WEBPAGE: blame
2210 ** WEBPAGE: praise
2211 **
 
 
 
 
 
 
 
 
2212 ** Query parameters:
2213 **
2214 ** checkin=ID The manifest ID at which to start the annotation
2215 ** filename=FILENAME The filename.
2216 ** filevers Show file versions rather than check-in versions
2217 ** log=BOOLEAN Show a log of versions analyzed
2218 ** limit=N Limit the search depth to N ancestors
 
 
 
2219 */
2220 void annotation_page(void){
2221 int mid;
2222 int fnid;
2223 int i;
2224
--- src/diff.c
+++ src/diff.c
@@ -1929,10 +1929,16 @@
1929 return diffFlags;
1930 }
1931
1932 /*
1933 ** COMMAND: test-rawdiff
1934 **
1935 ** Usage: %fossil test-rawdiff FILE1 FILE2
1936 **
1937 ** Show a minimal sequence of Copy/Delete/Insert operations needed to convert
1938 ** FILE1 into FILE2. This command is intended for use in testing and debugging
1939 ** the built-in difference engine of Fossil.
1940 */
1941 void test_rawdiff_cmd(void){
1942 Blob a, b;
1943 int r;
1944 int i;
@@ -2207,17 +2213,27 @@
2213 /*
2214 ** WEBPAGE: annotate
2215 ** WEBPAGE: blame
2216 ** WEBPAGE: praise
2217 **
2218 ** URL: /annotate?checkin=ID&filename=FILENAME
2219 ** URL: /blame?checkin=ID&filename=FILENAME
2220 ** URL: /praise?checkin=ID&filename=FILENAME
2221 **
2222 ** Show the most recent change to each line of a text file. /annotate shows
2223 ** the date of the changes and the check-in SHA1 hash (with a link to the
2224 ** check-in). /blame and /praise also show the user who made the check-in.
2225 **
2226 ** Query parameters:
2227 **
2228 ** checkin=ID The manifest ID at which to start the annotation
2229 ** filename=FILENAME The filename.
2230 ** filevers Show file versions rather than check-in versions
 
2231 ** limit=N Limit the search depth to N ancestors
2232 ** log=BOOLEAN Show a log of versions analyzed
2233 ** w Ignore whitespace
2234 **
2235 */
2236 void annotation_page(void){
2237 int mid;
2238 int fnid;
2239 int i;
2240
+3 -1
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -835,11 +835,13 @@
835835
}
836836
}
837837
838838
/*
839839
** WEBPAGE: vpatch
840
-** URL vpatch?from=UUID&to=UUID
840
+** URL: /vpatch?from=FROM&to=TO
841
+**
842
+** Show a patch that goes from check-in FROM to check-in TO.
841843
*/
842844
void vpatch_page(void){
843845
const char *zFrom = P("from");
844846
const char *zTo = P("to");
845847
login_check_credentials();
846848
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -835,11 +835,13 @@
835 }
836 }
837
838 /*
839 ** WEBPAGE: vpatch
840 ** URL vpatch?from=UUID&to=UUID
 
 
841 */
842 void vpatch_page(void){
843 const char *zFrom = P("from");
844 const char *zTo = P("to");
845 login_check_credentials();
846
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -835,11 +835,13 @@
835 }
836 }
837
838 /*
839 ** WEBPAGE: vpatch
840 ** URL: /vpatch?from=FROM&to=TO
841 **
842 ** Show a patch that goes from check-in FROM to check-in TO.
843 */
844 void vpatch_page(void){
845 const char *zFrom = P("from");
846 const char *zTo = P("to");
847 login_check_credentials();
848
+10 -3
--- src/doc.c
+++ src/doc.c
@@ -774,11 +774,12 @@
774774
775775
776776
/*
777777
** WEBPAGE: background
778778
**
779
-** Return the background image.
779
+** Return the background image. If no background image is defined, a
780
+** built-in 16x16 pixel white GIF is returned.
780781
*/
781782
void background_page(void){
782783
Blob bgimg;
783784
char *zMime;
784785
@@ -793,15 +794,21 @@
793794
g.isConst = 1;
794795
}
795796
796797
797798
/*
798
-** WEBPAGE: /docsrch
799
+** WEBPAGE: docsrch
800
+**
801
+** Search for documents that match a user-supplied full-text search pattern.
802
+** If no pattern is specified (by the s= query parameter) then the user
803
+** is prompted to enter a search string.
804
+**
805
+** Query parameters:
799806
**
800
-** Search for documents that match a user-supplied pattern.
807
+** s=PATTERN Search for PATTERN
801808
*/
802809
void doc_search_page(void){
803810
login_check_credentials();
804811
style_header("Document Search");
805812
search_screen(SRCH_DOC, 0);
806813
style_footer();
807814
}
808815
--- src/doc.c
+++ src/doc.c
@@ -774,11 +774,12 @@
774
775
776 /*
777 ** WEBPAGE: background
778 **
779 ** Return the background image.
 
780 */
781 void background_page(void){
782 Blob bgimg;
783 char *zMime;
784
@@ -793,15 +794,21 @@
793 g.isConst = 1;
794 }
795
796
797 /*
798 ** WEBPAGE: /docsrch
 
 
 
 
 
 
799 **
800 ** Search for documents that match a user-supplied pattern.
801 */
802 void doc_search_page(void){
803 login_check_credentials();
804 style_header("Document Search");
805 search_screen(SRCH_DOC, 0);
806 style_footer();
807 }
808
--- src/doc.c
+++ src/doc.c
@@ -774,11 +774,12 @@
774
775
776 /*
777 ** WEBPAGE: background
778 **
779 ** Return the background image. If no background image is defined, a
780 ** built-in 16x16 pixel white GIF is returned.
781 */
782 void background_page(void){
783 Blob bgimg;
784 char *zMime;
785
@@ -793,15 +794,21 @@
794 g.isConst = 1;
795 }
796
797
798 /*
799 ** WEBPAGE: docsrch
800 **
801 ** Search for documents that match a user-supplied full-text search pattern.
802 ** If no pattern is specified (by the s= query parameter) then the user
803 ** is prompted to enter a search string.
804 **
805 ** Query parameters:
806 **
807 ** s=PATTERN Search for PATTERN
808 */
809 void doc_search_page(void){
810 login_check_credentials();
811 style_header("Document Search");
812 search_screen(SRCH_DOC, 0);
813 style_footer();
814 }
815
--- src/encode.c
+++ src/encode.c
@@ -606,10 +606,14 @@
606606
/*
607607
** Command to test obscure() and unobscure(). These commands are also useful
608608
** utilities for decoding passwords found in the database.
609609
**
610610
** COMMAND: test-obscure
611
+**
612
+** For each command-line argument X, run both obscure(X) and
613
+** unobscure(obscure(X)) and print the results. This is used for testing
614
+** and debugging of the obscure() and unobscure() functions.
611615
*/
612616
void test_obscure_cmd(void){
613617
int i;
614618
char *z, *z2;
615619
for(i=2; i<g.argc; i++){
616620
--- src/encode.c
+++ src/encode.c
@@ -606,10 +606,14 @@
606 /*
607 ** Command to test obscure() and unobscure(). These commands are also useful
608 ** utilities for decoding passwords found in the database.
609 **
610 ** COMMAND: test-obscure
 
 
 
 
611 */
612 void test_obscure_cmd(void){
613 int i;
614 char *z, *z2;
615 for(i=2; i<g.argc; i++){
616
--- src/encode.c
+++ src/encode.c
@@ -606,10 +606,14 @@
606 /*
607 ** Command to test obscure() and unobscure(). These commands are also useful
608 ** utilities for decoding passwords found in the database.
609 **
610 ** COMMAND: test-obscure
611 **
612 ** For each command-line argument X, run both obscure(X) and
613 ** unobscure(obscure(X)) and print the results. This is used for testing
614 ** and debugging of the obscure() and unobscure() functions.
615 */
616 void test_obscure_cmd(void){
617 int i;
618 char *z, *z2;
619 for(i=2; i<g.argc; i++){
620
--- src/finfo.c
+++ src/finfo.c
@@ -288,10 +288,11 @@
288288
** b=DATE Only show changes before DATE
289289
** n=NUM Show the first NUM changes only
290290
** brbg Background color by branch name
291291
** ubg Background color by user name
292292
** ci=UUID Ancestors of a particular check-in
293
+** showid Show RID values for debugging
293294
*/
294295
void finfo_page(void){
295296
Stmt q;
296297
const char *zFilename;
297298
char zPrevDate[20];
298299
--- src/finfo.c
+++ src/finfo.c
@@ -288,10 +288,11 @@
288 ** b=DATE Only show changes before DATE
289 ** n=NUM Show the first NUM changes only
290 ** brbg Background color by branch name
291 ** ubg Background color by user name
292 ** ci=UUID Ancestors of a particular check-in
 
293 */
294 void finfo_page(void){
295 Stmt q;
296 const char *zFilename;
297 char zPrevDate[20];
298
--- src/finfo.c
+++ src/finfo.c
@@ -288,10 +288,11 @@
288 ** b=DATE Only show changes before DATE
289 ** n=NUM Show the first NUM changes only
290 ** brbg Background color by branch name
291 ** ubg Background color by user name
292 ** ci=UUID Ancestors of a particular check-in
293 ** showid Show RID values for debugging
294 */
295 void finfo_page(void){
296 Stmt q;
297 const char *zFilename;
298 char zPrevDate[20];
299
+19 -24
--- src/info.c
+++ src/info.c
@@ -48,10 +48,11 @@
4848
**
4949
** * The UUID
5050
** * The record ID
5151
** * mtime and ctime
5252
** * who signed it
53
+**
5354
*/
5455
void show_common_info(
5556
int rid, /* The rid for the check-in to display info for */
5657
const char *zUuidName, /* Name of the UUID */
5758
int showComment, /* True to show the check-in comment */
@@ -109,26 +110,10 @@
109110
fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
110111
free(zDate);
111112
}
112113
db_finalize(&q);
113114
}
114
- if( zUuid ){
115
- fossil_print("%-13s ", "leaf:");
116
- if(is_a_leaf(rid)){
117
- if(db_int(0, "SELECT 1 FROM tagxref AS tx"
118
- " WHERE tx.rid=%d"
119
- " AND tx.tagid=%d"
120
- " AND tx.tagtype>0",
121
- rid, TAG_CLOSED)){
122
- fossil_print("%s\n", "closed");
123
- }else{
124
- fossil_print("%s\n", "open");
125
- }
126
- }else{
127
- fossil_print("no\n");
128
- }
129
- }
130115
zTags = info_tags_of_checkin(rid, 0);
131116
if( zTags && zTags[0] ){
132117
fossil_print("tags: %s\n", zTags);
133118
}
134119
free(zTags);
@@ -498,15 +483,16 @@
498483
}
499484
500485
/*
501486
** WEBPAGE: vinfo
502487
** WEBPAGE: ci
503
-** URL: /ci?name=RID|ARTIFACTID
488
+** URL: /ci?name=ARTIFACTID
489
+** URL: /vinfo?name=ARTIFACTID
504490
**
505491
** Display information about a particular check-in.
506492
**
507
-** We also jump here from /info if the name is a version.
493
+** We also jump here from /info if the name is a check-in
508494
**
509495
** If the /ci page is used (instead of /vinfo or /info) then the
510496
** default behavior is to show unified diffs of all file changes.
511497
** With /vinfo and /info, only a list of the changed files are
512498
** shown, without diffs. This behavior is inverted if the
@@ -761,11 +747,11 @@
761747
762748
/*
763749
** WEBPAGE: winfo
764750
** URL: /winfo?name=UUID
765751
**
766
-** Return information about a wiki page.
752
+** Display information about a wiki page.
767753
*/
768754
void winfo_page(void){
769755
int rid;
770756
Manifest *pWiki;
771757
char *zUuid;
@@ -964,20 +950,25 @@
964950
}
965951
966952
967953
/*
968954
** WEBPAGE: vdiff
969
-** URL: /vdiff
955
+** URL: /vdiff?from=TAG&to=TAG
956
+**
957
+** Show the difference between two check-ins identified by the from= and
958
+** to= query parameters.
970959
**
971960
** Query parameters:
972961
**
973962
** from=TAG Left side of the comparison
974963
** to=TAG Right side of the comparison
975964
** branch=TAG Show all changes on a particular branch
976965
** v=BOOLEAN Default true. If false, only list files that have changed
977966
** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
978967
** glob=STRING only diff files matching this glob
968
+** dc=N show N lines of context around each diff
969
+** w ignore whitespace when computing diffs
979970
**
980971
**
981972
** Show all differences between two check-ins.
982973
*/
983974
void vdiff_page(void){
@@ -1410,10 +1401,12 @@
14101401
** is 0. Generate plaintext if "patch" is present.
14111402
**
14121403
** Additional parameters:
14131404
**
14141405
** verbose Show more detail when describing artifacts
1406
+** dc=N Show N lines of context around each diff
1407
+** w Ignore whitespace
14151408
*/
14161409
void diff_page(void){
14171410
int v1, v2;
14181411
int isPatch;
14191412
int sideBySide;
@@ -2037,14 +2030,14 @@
20372030
20382031
/*
20392032
** WEBPAGE: info
20402033
** URL: info/ARTIFACTID
20412034
**
2042
-** The argument is a artifact ID which might be a baseline or a file or
2035
+** The argument is a artifact ID which might be a check-in or a file or
20432036
** a ticket changes or a wiki edit or something else.
20442037
**
2045
-** Figure out what the artifact ID is and jump to it.
2038
+** Figure out what the artifact ID is and display it appropriately.
20462039
*/
20472040
void info_page(void){
20482041
const char *zName;
20492042
Blob uuid;
20502043
int rid;
@@ -2272,17 +2265,19 @@
22722265
return zA[0]==0 && zB[0]==0;
22732266
}
22742267
22752268
/*
22762269
** WEBPAGE: ci_edit
2277
-** URL: ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER
2270
+** URL: /ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER
22782271
**
2279
-** Present a dialog for updating properties of a baseline:
2272
+** Present a dialog for updating properties of a check-in.
22802273
**
22812274
** * The check-in user
22822275
** * The check-in comment
2276
+** * The check-in time and date
22832277
** * The background color.
2278
+** * Add and remove tags
22842279
*/
22852280
void ci_edit_page(void){
22862281
int rid;
22872282
const char *zComment; /* Current comment on the check-in */
22882283
const char *zNewComment; /* Revised check-in comment */
22892284
--- src/info.c
+++ src/info.c
@@ -48,10 +48,11 @@
48 **
49 ** * The UUID
50 ** * The record ID
51 ** * mtime and ctime
52 ** * who signed it
 
53 */
54 void show_common_info(
55 int rid, /* The rid for the check-in to display info for */
56 const char *zUuidName, /* Name of the UUID */
57 int showComment, /* True to show the check-in comment */
@@ -109,26 +110,10 @@
109 fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
110 free(zDate);
111 }
112 db_finalize(&q);
113 }
114 if( zUuid ){
115 fossil_print("%-13s ", "leaf:");
116 if(is_a_leaf(rid)){
117 if(db_int(0, "SELECT 1 FROM tagxref AS tx"
118 " WHERE tx.rid=%d"
119 " AND tx.tagid=%d"
120 " AND tx.tagtype>0",
121 rid, TAG_CLOSED)){
122 fossil_print("%s\n", "closed");
123 }else{
124 fossil_print("%s\n", "open");
125 }
126 }else{
127 fossil_print("no\n");
128 }
129 }
130 zTags = info_tags_of_checkin(rid, 0);
131 if( zTags && zTags[0] ){
132 fossil_print("tags: %s\n", zTags);
133 }
134 free(zTags);
@@ -498,15 +483,16 @@
498 }
499
500 /*
501 ** WEBPAGE: vinfo
502 ** WEBPAGE: ci
503 ** URL: /ci?name=RID|ARTIFACTID
 
504 **
505 ** Display information about a particular check-in.
506 **
507 ** We also jump here from /info if the name is a version.
508 **
509 ** If the /ci page is used (instead of /vinfo or /info) then the
510 ** default behavior is to show unified diffs of all file changes.
511 ** With /vinfo and /info, only a list of the changed files are
512 ** shown, without diffs. This behavior is inverted if the
@@ -761,11 +747,11 @@
761
762 /*
763 ** WEBPAGE: winfo
764 ** URL: /winfo?name=UUID
765 **
766 ** Return information about a wiki page.
767 */
768 void winfo_page(void){
769 int rid;
770 Manifest *pWiki;
771 char *zUuid;
@@ -964,20 +950,25 @@
964 }
965
966
967 /*
968 ** WEBPAGE: vdiff
969 ** URL: /vdiff
 
 
 
970 **
971 ** Query parameters:
972 **
973 ** from=TAG Left side of the comparison
974 ** to=TAG Right side of the comparison
975 ** branch=TAG Show all changes on a particular branch
976 ** v=BOOLEAN Default true. If false, only list files that have changed
977 ** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
978 ** glob=STRING only diff files matching this glob
 
 
979 **
980 **
981 ** Show all differences between two check-ins.
982 */
983 void vdiff_page(void){
@@ -1410,10 +1401,12 @@
1410 ** is 0. Generate plaintext if "patch" is present.
1411 **
1412 ** Additional parameters:
1413 **
1414 ** verbose Show more detail when describing artifacts
 
 
1415 */
1416 void diff_page(void){
1417 int v1, v2;
1418 int isPatch;
1419 int sideBySide;
@@ -2037,14 +2030,14 @@
2037
2038 /*
2039 ** WEBPAGE: info
2040 ** URL: info/ARTIFACTID
2041 **
2042 ** The argument is a artifact ID which might be a baseline or a file or
2043 ** a ticket changes or a wiki edit or something else.
2044 **
2045 ** Figure out what the artifact ID is and jump to it.
2046 */
2047 void info_page(void){
2048 const char *zName;
2049 Blob uuid;
2050 int rid;
@@ -2272,17 +2265,19 @@
2272 return zA[0]==0 && zB[0]==0;
2273 }
2274
2275 /*
2276 ** WEBPAGE: ci_edit
2277 ** URL: ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER
2278 **
2279 ** Present a dialog for updating properties of a baseline:
2280 **
2281 ** * The check-in user
2282 ** * The check-in comment
 
2283 ** * The background color.
 
2284 */
2285 void ci_edit_page(void){
2286 int rid;
2287 const char *zComment; /* Current comment on the check-in */
2288 const char *zNewComment; /* Revised check-in comment */
2289
--- src/info.c
+++ src/info.c
@@ -48,10 +48,11 @@
48 **
49 ** * The UUID
50 ** * The record ID
51 ** * mtime and ctime
52 ** * who signed it
53 **
54 */
55 void show_common_info(
56 int rid, /* The rid for the check-in to display info for */
57 const char *zUuidName, /* Name of the UUID */
58 int showComment, /* True to show the check-in comment */
@@ -109,26 +110,10 @@
110 fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
111 free(zDate);
112 }
113 db_finalize(&q);
114 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115 zTags = info_tags_of_checkin(rid, 0);
116 if( zTags && zTags[0] ){
117 fossil_print("tags: %s\n", zTags);
118 }
119 free(zTags);
@@ -498,15 +483,16 @@
483 }
484
485 /*
486 ** WEBPAGE: vinfo
487 ** WEBPAGE: ci
488 ** URL: /ci?name=ARTIFACTID
489 ** URL: /vinfo?name=ARTIFACTID
490 **
491 ** Display information about a particular check-in.
492 **
493 ** We also jump here from /info if the name is a check-in
494 **
495 ** If the /ci page is used (instead of /vinfo or /info) then the
496 ** default behavior is to show unified diffs of all file changes.
497 ** With /vinfo and /info, only a list of the changed files are
498 ** shown, without diffs. This behavior is inverted if the
@@ -761,11 +747,11 @@
747
748 /*
749 ** WEBPAGE: winfo
750 ** URL: /winfo?name=UUID
751 **
752 ** Display information about a wiki page.
753 */
754 void winfo_page(void){
755 int rid;
756 Manifest *pWiki;
757 char *zUuid;
@@ -964,20 +950,25 @@
950 }
951
952
953 /*
954 ** WEBPAGE: vdiff
955 ** URL: /vdiff?from=TAG&to=TAG
956 **
957 ** Show the difference between two check-ins identified by the from= and
958 ** to= query parameters.
959 **
960 ** Query parameters:
961 **
962 ** from=TAG Left side of the comparison
963 ** to=TAG Right side of the comparison
964 ** branch=TAG Show all changes on a particular branch
965 ** v=BOOLEAN Default true. If false, only list files that have changed
966 ** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
967 ** glob=STRING only diff files matching this glob
968 ** dc=N show N lines of context around each diff
969 ** w ignore whitespace when computing diffs
970 **
971 **
972 ** Show all differences between two check-ins.
973 */
974 void vdiff_page(void){
@@ -1410,10 +1401,12 @@
1401 ** is 0. Generate plaintext if "patch" is present.
1402 **
1403 ** Additional parameters:
1404 **
1405 ** verbose Show more detail when describing artifacts
1406 ** dc=N Show N lines of context around each diff
1407 ** w Ignore whitespace
1408 */
1409 void diff_page(void){
1410 int v1, v2;
1411 int isPatch;
1412 int sideBySide;
@@ -2037,14 +2030,14 @@
2030
2031 /*
2032 ** WEBPAGE: info
2033 ** URL: info/ARTIFACTID
2034 **
2035 ** The argument is a artifact ID which might be a check-in or a file or
2036 ** a ticket changes or a wiki edit or something else.
2037 **
2038 ** Figure out what the artifact ID is and display it appropriately.
2039 */
2040 void info_page(void){
2041 const char *zName;
2042 Blob uuid;
2043 int rid;
@@ -2272,17 +2265,19 @@
2265 return zA[0]==0 && zB[0]==0;
2266 }
2267
2268 /*
2269 ** WEBPAGE: ci_edit
2270 ** URL: /ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER
2271 **
2272 ** Present a dialog for updating properties of a check-in.
2273 **
2274 ** * The check-in user
2275 ** * The check-in comment
2276 ** * The check-in time and date
2277 ** * The background color.
2278 ** * Add and remove tags
2279 */
2280 void ci_edit_page(void){
2281 int rid;
2282 const char *zComment; /* Current comment on the check-in */
2283 const char *zNewComment; /* Revised check-in comment */
2284
+87
--- src/leaf.c
+++ src/leaf.c
@@ -180,5 +180,92 @@
180180
for(rid=bag_first(&needToCheck); rid; rid=bag_next(&needToCheck,rid)){
181181
leaf_check(rid);
182182
}
183183
bag_clear(&needToCheck);
184184
}
185
+
186
+/*
187
+** If check-in rid is an open-leaf and there exists another
188
+** open leaf on the same branch, then return 1.
189
+**
190
+** If check-in rid is not an open leaf, or if it is the only open leaf
191
+** on its branch, then return 0.
192
+*/
193
+int leaf_ambiguity(int rid){
194
+ int rc; /* Result */
195
+ char zVal[30];
196
+ if( !is_a_leaf(rid) ) return 0;
197
+ sqlite3_snprintf(sizeof(zVal), zVal, "%d", rid);
198
+ rc = db_exists(
199
+ "SELECT 1 FROM leaf"
200
+ " WHERE NOT %z"
201
+ " AND rid<>%d"
202
+ " AND (SELECT value FROM tagxref WHERE tagid=%d AND rid=leaf.rid)="
203
+ " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)"
204
+ " AND NOT %z",
205
+ leaf_is_closed_sql(zVal), rid, TAG_BRANCH, TAG_BRANCH, rid,
206
+ leaf_is_closed_sql("leaf.rid"));
207
+ return rc;
208
+}
209
+
210
+/*
211
+** If check-in rid is an open-leaf and there exists another open leaf
212
+** on the same branch, then print a detailed warning showing all open
213
+** leaves on that branch.
214
+*/
215
+int leaf_ambiguity_warning(int rid, int currentCkout){
216
+ char *zBr;
217
+ Stmt q;
218
+ int n = 0;
219
+ Blob msg;
220
+ if( leaf_ambiguity(rid)==0 ) return 0;
221
+ zBr = db_text(0, "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
222
+ TAG_BRANCH, rid);
223
+ if( zBr==0 ) zBr = fossil_strdup("trunk");
224
+ blob_init(&msg, 0, 0);
225
+ blob_appendf(&msg, "WARNING: multiple open leaf check-ins on %s:", zBr);
226
+ db_prepare(&q,
227
+ "SELECT"
228
+ " (SELECT uuid FROM blob WHERE rid=leaf.rid),"
229
+ " (SELECT datetime(mtime%s) FROM event WHERE objid=leaf.rid),"
230
+ " leaf.rid"
231
+ " FROM leaf"
232
+ " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=leaf.rid)=%Q"
233
+ " AND NOT %z"
234
+ " ORDER BY 2 DESC",
235
+ timeline_utc(), TAG_BRANCH, zBr, leaf_is_closed_sql("leaf.rid")
236
+ );
237
+ while( db_step(&q)==SQLITE_ROW ){
238
+ blob_appendf(&msg, "\n (%d) %s [%S]%s",
239
+ ++n, db_column_text(&q,1), db_column_text(&q,0),
240
+ db_column_int(&q,2)==currentCkout ? " (current)" : "");
241
+ }
242
+ db_finalize(&q);
243
+ fossil_warning("%s",blob_str(&msg));
244
+ blob_reset(&msg);
245
+ return 1;
246
+}
247
+
248
+/*
249
+** COMMAND: test-leaf-ambiguity
250
+**
251
+** Usage: %fossil NAME ...
252
+**
253
+** Resolve each name on the command line and call leaf_ambiguity_warning()
254
+** for each resulting RID.
255
+*/
256
+void leaf_ambiguity_warning_test(void){
257
+ int i;
258
+ int rid;
259
+ int rc;
260
+ db_find_and_open_repository(0,0);
261
+ verify_all_options();
262
+ for(i=2; i<g.argc; i++){
263
+ char *zUuid;
264
+ rid = name_to_typed_rid(g.argv[i], "ci");
265
+ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
266
+ fossil_print("%s (rid=%d) %S ", g.argv[i], rid, zUuid ? zUuid : "(none)");
267
+ fossil_free(zUuid);
268
+ rc = leaf_ambiguity_warning(rid, rid);
269
+ if( rc==0 ) fossil_print(" ok\n");
270
+ }
271
+}
185272
--- src/leaf.c
+++ src/leaf.c
@@ -180,5 +180,92 @@
180 for(rid=bag_first(&needToCheck); rid; rid=bag_next(&needToCheck,rid)){
181 leaf_check(rid);
182 }
183 bag_clear(&needToCheck);
184 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
--- src/leaf.c
+++ src/leaf.c
@@ -180,5 +180,92 @@
180 for(rid=bag_first(&needToCheck); rid; rid=bag_next(&needToCheck,rid)){
181 leaf_check(rid);
182 }
183 bag_clear(&needToCheck);
184 }
185
186 /*
187 ** If check-in rid is an open-leaf and there exists another
188 ** open leaf on the same branch, then return 1.
189 **
190 ** If check-in rid is not an open leaf, or if it is the only open leaf
191 ** on its branch, then return 0.
192 */
193 int leaf_ambiguity(int rid){
194 int rc; /* Result */
195 char zVal[30];
196 if( !is_a_leaf(rid) ) return 0;
197 sqlite3_snprintf(sizeof(zVal), zVal, "%d", rid);
198 rc = db_exists(
199 "SELECT 1 FROM leaf"
200 " WHERE NOT %z"
201 " AND rid<>%d"
202 " AND (SELECT value FROM tagxref WHERE tagid=%d AND rid=leaf.rid)="
203 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)"
204 " AND NOT %z",
205 leaf_is_closed_sql(zVal), rid, TAG_BRANCH, TAG_BRANCH, rid,
206 leaf_is_closed_sql("leaf.rid"));
207 return rc;
208 }
209
210 /*
211 ** If check-in rid is an open-leaf and there exists another open leaf
212 ** on the same branch, then print a detailed warning showing all open
213 ** leaves on that branch.
214 */
215 int leaf_ambiguity_warning(int rid, int currentCkout){
216 char *zBr;
217 Stmt q;
218 int n = 0;
219 Blob msg;
220 if( leaf_ambiguity(rid)==0 ) return 0;
221 zBr = db_text(0, "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
222 TAG_BRANCH, rid);
223 if( zBr==0 ) zBr = fossil_strdup("trunk");
224 blob_init(&msg, 0, 0);
225 blob_appendf(&msg, "WARNING: multiple open leaf check-ins on %s:", zBr);
226 db_prepare(&q,
227 "SELECT"
228 " (SELECT uuid FROM blob WHERE rid=leaf.rid),"
229 " (SELECT datetime(mtime%s) FROM event WHERE objid=leaf.rid),"
230 " leaf.rid"
231 " FROM leaf"
232 " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=leaf.rid)=%Q"
233 " AND NOT %z"
234 " ORDER BY 2 DESC",
235 timeline_utc(), TAG_BRANCH, zBr, leaf_is_closed_sql("leaf.rid")
236 );
237 while( db_step(&q)==SQLITE_ROW ){
238 blob_appendf(&msg, "\n (%d) %s [%S]%s",
239 ++n, db_column_text(&q,1), db_column_text(&q,0),
240 db_column_int(&q,2)==currentCkout ? " (current)" : "");
241 }
242 db_finalize(&q);
243 fossil_warning("%s",blob_str(&msg));
244 blob_reset(&msg);
245 return 1;
246 }
247
248 /*
249 ** COMMAND: test-leaf-ambiguity
250 **
251 ** Usage: %fossil NAME ...
252 **
253 ** Resolve each name on the command line and call leaf_ambiguity_warning()
254 ** for each resulting RID.
255 */
256 void leaf_ambiguity_warning_test(void){
257 int i;
258 int rid;
259 int rc;
260 db_find_and_open_repository(0,0);
261 verify_all_options();
262 for(i=2; i<g.argc; i++){
263 char *zUuid;
264 rid = name_to_typed_rid(g.argv[i], "ci");
265 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
266 fossil_print("%s (rid=%d) %S ", g.argv[i], rid, zUuid ? zUuid : "(none)");
267 fossil_free(zUuid);
268 rc = leaf_ambiguity_warning(rid, rid);
269 if( rc==0 ) fossil_print(" ok\n");
270 }
271 }
272
+2 -2
--- src/login.c
+++ src/login.c
@@ -1302,12 +1302,12 @@
13021302
}
13031303
13041304
/*
13051305
** WEBPAGE: register
13061306
**
1307
-** Generate the register page.
1308
-**
1307
+** Page to allow users to self-register. The "self-register" setting
1308
+** must be enabled for this page to operate.
13091309
*/
13101310
void register_page(void){
13111311
const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;
13121312
unsigned int uSeed;
13131313
const char *zDecoded;
13141314
--- src/login.c
+++ src/login.c
@@ -1302,12 +1302,12 @@
1302 }
1303
1304 /*
1305 ** WEBPAGE: register
1306 **
1307 ** Generate the register page.
1308 **
1309 */
1310 void register_page(void){
1311 const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;
1312 unsigned int uSeed;
1313 const char *zDecoded;
1314
--- src/login.c
+++ src/login.c
@@ -1302,12 +1302,12 @@
1302 }
1303
1304 /*
1305 ** WEBPAGE: register
1306 **
1307 ** Page to allow users to self-register. The "self-register" setting
1308 ** must be enabled for this page to operate.
1309 */
1310 void register_page(void){
1311 const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;
1312 unsigned int uSeed;
1313 const char *zDecoded;
1314
+5 -2
--- src/main.c
+++ src/main.c
@@ -657,10 +657,11 @@
657657
"in conjunction with any other flags.\n");
658658
fossil_exit(1);
659659
}else{
660660
const char *zChdir = find_option("chdir",0,1);
661661
g.isHTTP = 0;
662
+ g.rcvid = 0;
662663
g.fQuiet = find_option("quiet", 0, 0)!=0;
663664
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
664665
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
665666
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
666667
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -1132,11 +1133,14 @@
11321133
putchar('\n');
11331134
}
11341135
11351136
/*
11361137
** WEBPAGE: help
1137
-** URL: /help/CMD
1138
+** URL: /help?name=CMD
1139
+**
1140
+** Show the built-in help text for CMD. CMD can be a command-line interface
1141
+** command or a page name from the web interface.
11381142
*/
11391143
void help_page(void){
11401144
const char *zCmd = P("cmd");
11411145
11421146
if( zCmd==0 ) zCmd = P("name");
@@ -1200,11 +1204,10 @@
12001204
@ </ul></td>
12011205
}
12021206
@ </tr></table>
12031207
12041208
@ <h1>Available web UI pages:</h1>
1205
- @ (Only pages with help text are linked.)
12061209
@ <table border="0"><tr>
12071210
for(i=j=0; i<count(aCommand); i++){
12081211
const char *z = aCommand[i].zName;
12091212
if( '/'!=*z ) continue;
12101213
j++;
12111214
--- src/main.c
+++ src/main.c
@@ -657,10 +657,11 @@
657 "in conjunction with any other flags.\n");
658 fossil_exit(1);
659 }else{
660 const char *zChdir = find_option("chdir",0,1);
661 g.isHTTP = 0;
 
662 g.fQuiet = find_option("quiet", 0, 0)!=0;
663 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
664 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
665 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
666 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -1132,11 +1133,14 @@
1132 putchar('\n');
1133 }
1134
1135 /*
1136 ** WEBPAGE: help
1137 ** URL: /help/CMD
 
 
 
1138 */
1139 void help_page(void){
1140 const char *zCmd = P("cmd");
1141
1142 if( zCmd==0 ) zCmd = P("name");
@@ -1200,11 +1204,10 @@
1200 @ </ul></td>
1201 }
1202 @ </tr></table>
1203
1204 @ <h1>Available web UI pages:</h1>
1205 @ (Only pages with help text are linked.)
1206 @ <table border="0"><tr>
1207 for(i=j=0; i<count(aCommand); i++){
1208 const char *z = aCommand[i].zName;
1209 if( '/'!=*z ) continue;
1210 j++;
1211
--- src/main.c
+++ src/main.c
@@ -657,10 +657,11 @@
657 "in conjunction with any other flags.\n");
658 fossil_exit(1);
659 }else{
660 const char *zChdir = find_option("chdir",0,1);
661 g.isHTTP = 0;
662 g.rcvid = 0;
663 g.fQuiet = find_option("quiet", 0, 0)!=0;
664 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
665 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
666 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
667 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -1132,11 +1133,14 @@
1133 putchar('\n');
1134 }
1135
1136 /*
1137 ** WEBPAGE: help
1138 ** URL: /help?name=CMD
1139 **
1140 ** Show the built-in help text for CMD. CMD can be a command-line interface
1141 ** command or a page name from the web interface.
1142 */
1143 void help_page(void){
1144 const char *zCmd = P("cmd");
1145
1146 if( zCmd==0 ) zCmd = P("name");
@@ -1200,11 +1204,10 @@
1204 @ </ul></td>
1205 }
1206 @ </tr></table>
1207
1208 @ <h1>Available web UI pages:</h1>
 
1209 @ <table border="0"><tr>
1210 for(i=j=0; i<count(aCommand); i++){
1211 const char *z = aCommand[i].zName;
1212 if( '/'!=*z ) continue;
1213 j++;
1214
+5 -2
--- src/main.c
+++ src/main.c
@@ -657,10 +657,11 @@
657657
"in conjunction with any other flags.\n");
658658
fossil_exit(1);
659659
}else{
660660
const char *zChdir = find_option("chdir",0,1);
661661
g.isHTTP = 0;
662
+ g.rcvid = 0;
662663
g.fQuiet = find_option("quiet", 0, 0)!=0;
663664
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
664665
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
665666
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
666667
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -1132,11 +1133,14 @@
11321133
putchar('\n');
11331134
}
11341135
11351136
/*
11361137
** WEBPAGE: help
1137
-** URL: /help/CMD
1138
+** URL: /help?name=CMD
1139
+**
1140
+** Show the built-in help text for CMD. CMD can be a command-line interface
1141
+** command or a page name from the web interface.
11381142
*/
11391143
void help_page(void){
11401144
const char *zCmd = P("cmd");
11411145
11421146
if( zCmd==0 ) zCmd = P("name");
@@ -1200,11 +1204,10 @@
12001204
@ </ul></td>
12011205
}
12021206
@ </tr></table>
12031207
12041208
@ <h1>Available web UI pages:</h1>
1205
- @ (Only pages with help text are linked.)
12061209
@ <table border="0"><tr>
12071210
for(i=j=0; i<count(aCommand); i++){
12081211
const char *z = aCommand[i].zName;
12091212
if( '/'!=*z ) continue;
12101213
j++;
12111214
--- src/main.c
+++ src/main.c
@@ -657,10 +657,11 @@
657 "in conjunction with any other flags.\n");
658 fossil_exit(1);
659 }else{
660 const char *zChdir = find_option("chdir",0,1);
661 g.isHTTP = 0;
 
662 g.fQuiet = find_option("quiet", 0, 0)!=0;
663 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
664 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
665 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
666 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -1132,11 +1133,14 @@
1132 putchar('\n');
1133 }
1134
1135 /*
1136 ** WEBPAGE: help
1137 ** URL: /help/CMD
 
 
 
1138 */
1139 void help_page(void){
1140 const char *zCmd = P("cmd");
1141
1142 if( zCmd==0 ) zCmd = P("name");
@@ -1200,11 +1204,10 @@
1200 @ </ul></td>
1201 }
1202 @ </tr></table>
1203
1204 @ <h1>Available web UI pages:</h1>
1205 @ (Only pages with help text are linked.)
1206 @ <table border="0"><tr>
1207 for(i=j=0; i<count(aCommand); i++){
1208 const char *z = aCommand[i].zName;
1209 if( '/'!=*z ) continue;
1210 j++;
1211
--- src/main.c
+++ src/main.c
@@ -657,10 +657,11 @@
657 "in conjunction with any other flags.\n");
658 fossil_exit(1);
659 }else{
660 const char *zChdir = find_option("chdir",0,1);
661 g.isHTTP = 0;
662 g.rcvid = 0;
663 g.fQuiet = find_option("quiet", 0, 0)!=0;
664 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
665 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
666 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
667 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
@@ -1132,11 +1133,14 @@
1133 putchar('\n');
1134 }
1135
1136 /*
1137 ** WEBPAGE: help
1138 ** URL: /help?name=CMD
1139 **
1140 ** Show the built-in help text for CMD. CMD can be a command-line interface
1141 ** command or a page name from the web interface.
1142 */
1143 void help_page(void){
1144 const char *zCmd = P("cmd");
1145
1146 if( zCmd==0 ) zCmd = P("name");
@@ -1200,11 +1204,10 @@
1204 @ </ul></td>
1205 }
1206 @ </tr></table>
1207
1208 @ <h1>Available web UI pages:</h1>
 
1209 @ <table border="0"><tr>
1210 for(i=j=0; i<count(aCommand); i++){
1211 const char *z = aCommand[i].zName;
1212 if( '/'!=*z ) continue;
1213 j++;
1214
+76 -17
--- src/merge.c
+++ src/merge.c
@@ -53,10 +53,85 @@
5353
fossil_free(zCom);
5454
}
5555
db_finalize(&q);
5656
}
5757
58
+
59
+/* Pick the most recent leaf that is (1) not equal to vid and (2)
60
+** has not already been merged into vid and (3) the leaf is not
61
+** closed and (4) the leaf is in the same branch as vid.
62
+**
63
+** Set vmergeFlag to control whether the vmerge table is checked.
64
+*/
65
+int fossil_find_nearest_fork(int vid, int vmergeFlag){
66
+ Blob sql;
67
+ Stmt q;
68
+ int rid = 0;
69
+
70
+ blob_zero(&sql);
71
+ blob_append_sql(&sql,
72
+ "SELECT leaf.rid"
73
+ " FROM leaf, event"
74
+ " WHERE leaf.rid=event.objid"
75
+ " AND leaf.rid!=%d", /* Constraint (1) */
76
+ vid
77
+ );
78
+ if( vmergeFlag ){
79
+ blob_append_sql(&sql,
80
+ " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
81
+ );
82
+ }
83
+ blob_append_sql(&sql,
84
+ " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
85
+ " WHERE rid=leaf.rid"
86
+ " AND tagid=%d"
87
+ " AND tagtype>0)"
88
+ " AND (SELECT value FROM tagxref" /* Constraint (4) */
89
+ " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
90
+ " (SELECT value FROM tagxref"
91
+ " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
92
+ " ORDER BY event.mtime DESC LIMIT 1",
93
+ TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
94
+ );
95
+ db_prepare(&q, "%s", blob_sql_text(&sql));
96
+ blob_reset(&sql);
97
+ if( db_step(&q)==SQLITE_ROW ){
98
+ rid = db_column_int(&q, 0);
99
+ }
100
+ db_finalize(&q);
101
+ return rid;
102
+}
103
+
104
+/*
105
+** Check content that was received with rcvid and return true if any
106
+** fork was created.
107
+*/
108
+int fossil_any_has_fork(int rcvid){
109
+ static Stmt q;
110
+ int fForkSeen = 0;
111
+
112
+ if( rcvid==0 ) return 0;
113
+ db_static_prepare(&q,
114
+ " SELECT pid FROM plink WHERE pid>0 AND isprim"
115
+ " AND cid IN (SELECT blob.rid FROM blob"
116
+ " WHERE rcvid=:rcvid)");
117
+ db_bind_int(&q, ":rcvid", rcvid);
118
+ while( !fForkSeen && db_step(&q)==SQLITE_ROW ){
119
+ int pid = db_column_int(&q, 0);
120
+ if( count_nonbranch_children(pid)>1 ){
121
+ compute_leaves(pid,1);
122
+ if( db_int(0, "SELECT count(*) FROM leaves")>1 ){
123
+ int rid = db_int(0, "SELECT rid FROM leaves, event"
124
+ " WHERE event.objid=leaves.rid"
125
+ " ORDER BY event.mtime DESC LIMIT 1");
126
+ fForkSeen = fossil_find_nearest_fork(rid, db_open_local(0))!=0;
127
+ }
128
+ }
129
+ }
130
+ db_finalize(&q);
131
+ return fForkSeen;
132
+}
58133
59134
/*
60135
** COMMAND: merge
61136
**
62137
** Usage: %fossil merge ?OPTIONS? ?VERSION?
@@ -172,27 +247,11 @@
172247
*/
173248
Stmt q;
174249
if( pickFlag || backoutFlag || integrateFlag){
175250
fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
176251
}
177
- mid = db_int(0,
178
- "SELECT leaf.rid"
179
- " FROM leaf, event"
180
- " WHERE leaf.rid=event.objid"
181
- " AND leaf.rid!=%d" /* Constraint (1) */
182
- " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
183
- " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
184
- " WHERE rid=leaf.rid"
185
- " AND tagid=%d"
186
- " AND tagtype>0)"
187
- " AND (SELECT value FROM tagxref" /* Constraint (4) */
188
- " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
189
- " (SELECT value FROM tagxref"
190
- " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
191
- " ORDER BY event.mtime DESC LIMIT 1",
192
- vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
193
- );
252
+ mid = fossil_find_nearest_fork(vid, db_open_local(0));
194253
if( mid==0 ){
195254
fossil_fatal("no unmerged forks of branch \"%s\"",
196255
db_text(0, "SELECT value FROM tagxref"
197256
" WHERE tagid=%d AND rid=%d AND tagtype>0",
198257
TAG_BRANCH, vid)
199258
--- src/merge.c
+++ src/merge.c
@@ -53,10 +53,85 @@
53 fossil_free(zCom);
54 }
55 db_finalize(&q);
56 }
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
@@ -172,27 +247,11 @@
172 */
173 Stmt q;
174 if( pickFlag || backoutFlag || integrateFlag){
175 fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
176 }
177 mid = db_int(0,
178 "SELECT leaf.rid"
179 " FROM leaf, event"
180 " WHERE leaf.rid=event.objid"
181 " AND leaf.rid!=%d" /* Constraint (1) */
182 " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
183 " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
184 " WHERE rid=leaf.rid"
185 " AND tagid=%d"
186 " AND tagtype>0)"
187 " AND (SELECT value FROM tagxref" /* Constraint (4) */
188 " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
189 " (SELECT value FROM tagxref"
190 " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
191 " ORDER BY event.mtime DESC LIMIT 1",
192 vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
193 );
194 if( mid==0 ){
195 fossil_fatal("no unmerged forks of branch \"%s\"",
196 db_text(0, "SELECT value FROM tagxref"
197 " WHERE tagid=%d AND rid=%d AND tagtype>0",
198 TAG_BRANCH, vid)
199
--- src/merge.c
+++ src/merge.c
@@ -53,10 +53,85 @@
53 fossil_free(zCom);
54 }
55 db_finalize(&q);
56 }
57
58
59 /* Pick the most recent leaf that is (1) not equal to vid and (2)
60 ** has not already been merged into vid and (3) the leaf is not
61 ** closed and (4) the leaf is in the same branch as vid.
62 **
63 ** Set vmergeFlag to control whether the vmerge table is checked.
64 */
65 int fossil_find_nearest_fork(int vid, int vmergeFlag){
66 Blob sql;
67 Stmt q;
68 int rid = 0;
69
70 blob_zero(&sql);
71 blob_append_sql(&sql,
72 "SELECT leaf.rid"
73 " FROM leaf, event"
74 " WHERE leaf.rid=event.objid"
75 " AND leaf.rid!=%d", /* Constraint (1) */
76 vid
77 );
78 if( vmergeFlag ){
79 blob_append_sql(&sql,
80 " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
81 );
82 }
83 blob_append_sql(&sql,
84 " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
85 " WHERE rid=leaf.rid"
86 " AND tagid=%d"
87 " AND tagtype>0)"
88 " AND (SELECT value FROM tagxref" /* Constraint (4) */
89 " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
90 " (SELECT value FROM tagxref"
91 " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
92 " ORDER BY event.mtime DESC LIMIT 1",
93 TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
94 );
95 db_prepare(&q, "%s", blob_sql_text(&sql));
96 blob_reset(&sql);
97 if( db_step(&q)==SQLITE_ROW ){
98 rid = db_column_int(&q, 0);
99 }
100 db_finalize(&q);
101 return rid;
102 }
103
104 /*
105 ** Check content that was received with rcvid and return true if any
106 ** fork was created.
107 */
108 int fossil_any_has_fork(int rcvid){
109 static Stmt q;
110 int fForkSeen = 0;
111
112 if( rcvid==0 ) return 0;
113 db_static_prepare(&q,
114 " SELECT pid FROM plink WHERE pid>0 AND isprim"
115 " AND cid IN (SELECT blob.rid FROM blob"
116 " WHERE rcvid=:rcvid)");
117 db_bind_int(&q, ":rcvid", rcvid);
118 while( !fForkSeen && db_step(&q)==SQLITE_ROW ){
119 int pid = db_column_int(&q, 0);
120 if( count_nonbranch_children(pid)>1 ){
121 compute_leaves(pid,1);
122 if( db_int(0, "SELECT count(*) FROM leaves")>1 ){
123 int rid = db_int(0, "SELECT rid FROM leaves, event"
124 " WHERE event.objid=leaves.rid"
125 " ORDER BY event.mtime DESC LIMIT 1");
126 fForkSeen = fossil_find_nearest_fork(rid, db_open_local(0))!=0;
127 }
128 }
129 }
130 db_finalize(&q);
131 return fForkSeen;
132 }
133
134 /*
135 ** COMMAND: merge
136 **
137 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
@@ -172,27 +247,11 @@
247 */
248 Stmt q;
249 if( pickFlag || backoutFlag || integrateFlag){
250 fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
251 }
252 mid = fossil_find_nearest_fork(vid, db_open_local(0));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253 if( mid==0 ){
254 fossil_fatal("no unmerged forks of branch \"%s\"",
255 db_text(0, "SELECT value FROM tagxref"
256 " WHERE tagid=%d AND rid=%d AND tagtype>0",
257 TAG_BRANCH, vid)
258
+1 -1
--- src/merge3.c
+++ src/merge3.c
@@ -260,11 +260,11 @@
260260
i2 += 3;
261261
}else
262262
{
263263
/* We have found a region where different edits to V1 and V2 overlap.
264264
** This is a merge conflict. Find the size of the conflict, then
265
- ** output both possible edits separate by distinctive marks.
265
+ ** output both possible edits separated by distinctive marks.
266266
*/
267267
int sz = 1; /* Size of the conflict in lines */
268268
nConflict++;
269269
while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
270270
sz++;
271271
--- src/merge3.c
+++ src/merge3.c
@@ -260,11 +260,11 @@
260 i2 += 3;
261 }else
262 {
263 /* We have found a region where different edits to V1 and V2 overlap.
264 ** This is a merge conflict. Find the size of the conflict, then
265 ** output both possible edits separate by distinctive marks.
266 */
267 int sz = 1; /* Size of the conflict in lines */
268 nConflict++;
269 while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
270 sz++;
271
--- src/merge3.c
+++ src/merge3.c
@@ -260,11 +260,11 @@
260 i2 += 3;
261 }else
262 {
263 /* We have found a region where different edits to V1 and V2 overlap.
264 ** This is a merge conflict. Find the size of the conflict, then
265 ** output both possible edits separated by distinctive marks.
266 */
267 int sz = 1; /* Size of the conflict in lines */
268 nConflict++;
269 while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
270 sz++;
271
+3 -3
--- src/pivot.c
+++ src/pivot.c
@@ -48,11 +48,11 @@
4848
"DELETE FROM aqueue;"
4949
"CREATE INDEX IF NOT EXISTS aqueue_idx1 ON aqueue(pending, mtime);"
5050
);
5151
5252
/* Insert the primary record */
53
- db_multi_exec(
53
+ db_multi_exec(
5454
"INSERT INTO aqueue(rid, mtime, pending, src)"
5555
" SELECT %d, mtime, 1, 1 FROM event WHERE objid=%d AND type='ci' LIMIT 1",
5656
rid, rid
5757
);
5858
}
@@ -62,11 +62,11 @@
6262
** must be at least one secondary but there can be more than one if
6363
** desired.
6464
*/
6565
void pivot_set_secondary(int rid){
6666
/* Insert the primary record */
67
- db_multi_exec(
67
+ db_multi_exec(
6868
"INSERT OR IGNORE INTO aqueue(rid, mtime, pending, src)"
6969
" SELECT %d, mtime, 1, 0 FROM event WHERE objid=%d AND type='ci'",
7070
rid, rid
7171
);
7272
}
@@ -77,11 +77,11 @@
7777
** can be found.
7878
*/
7979
int pivot_find(void){
8080
Stmt q1, q2, u1, i1;
8181
int rid = 0;
82
-
82
+
8383
/* aqueue must contain at least one primary and one other. Otherwise
8484
** we abort early
8585
*/
8686
if( db_int(0, "SELECT count(distinct src) FROM aqueue")<2 ){
8787
fossil_fatal("lack both primary and secondary files");
8888
--- src/pivot.c
+++ src/pivot.c
@@ -48,11 +48,11 @@
48 "DELETE FROM aqueue;"
49 "CREATE INDEX IF NOT EXISTS aqueue_idx1 ON aqueue(pending, mtime);"
50 );
51
52 /* Insert the primary record */
53 db_multi_exec(
54 "INSERT INTO aqueue(rid, mtime, pending, src)"
55 " SELECT %d, mtime, 1, 1 FROM event WHERE objid=%d AND type='ci' LIMIT 1",
56 rid, rid
57 );
58 }
@@ -62,11 +62,11 @@
62 ** must be at least one secondary but there can be more than one if
63 ** desired.
64 */
65 void pivot_set_secondary(int rid){
66 /* Insert the primary record */
67 db_multi_exec(
68 "INSERT OR IGNORE INTO aqueue(rid, mtime, pending, src)"
69 " SELECT %d, mtime, 1, 0 FROM event WHERE objid=%d AND type='ci'",
70 rid, rid
71 );
72 }
@@ -77,11 +77,11 @@
77 ** can be found.
78 */
79 int pivot_find(void){
80 Stmt q1, q2, u1, i1;
81 int rid = 0;
82
83 /* aqueue must contain at least one primary and one other. Otherwise
84 ** we abort early
85 */
86 if( db_int(0, "SELECT count(distinct src) FROM aqueue")<2 ){
87 fossil_fatal("lack both primary and secondary files");
88
--- src/pivot.c
+++ src/pivot.c
@@ -48,11 +48,11 @@
48 "DELETE FROM aqueue;"
49 "CREATE INDEX IF NOT EXISTS aqueue_idx1 ON aqueue(pending, mtime);"
50 );
51
52 /* Insert the primary record */
53 db_multi_exec(
54 "INSERT INTO aqueue(rid, mtime, pending, src)"
55 " SELECT %d, mtime, 1, 1 FROM event WHERE objid=%d AND type='ci' LIMIT 1",
56 rid, rid
57 );
58 }
@@ -62,11 +62,11 @@
62 ** must be at least one secondary but there can be more than one if
63 ** desired.
64 */
65 void pivot_set_secondary(int rid){
66 /* Insert the primary record */
67 db_multi_exec(
68 "INSERT OR IGNORE INTO aqueue(rid, mtime, pending, src)"
69 " SELECT %d, mtime, 1, 0 FROM event WHERE objid=%d AND type='ci'",
70 rid, rid
71 );
72 }
@@ -77,11 +77,11 @@
77 ** can be found.
78 */
79 int pivot_find(void){
80 Stmt q1, q2, u1, i1;
81 int rid = 0;
82
83 /* aqueue must contain at least one primary and one other. Otherwise
84 ** we abort early
85 */
86 if( db_int(0, "SELECT count(distinct src) FROM aqueue")<2 ){
87 fossil_fatal("lack both primary and secondary files");
88
+6 -6
--- src/popen.c
+++ src/popen.c
@@ -38,11 +38,11 @@
3838
** The following macros are used to cast pointers to integers and
3939
** integers to pointers. The way you do this varies from one compiler
4040
** to the next, so we have developed the following set of #if statements
4141
** to generate appropriate macros for a wide range of compilers.
4242
**
43
-** The correct "ANSI" way to do this is to use the intptr_t type.
43
+** The correct "ANSI" way to do this is to use the intptr_t type.
4444
** Unfortunately, that typedef is not available on all compilers, or
4545
** if it is available, it requires an #include of specific headers
4646
** that vary from one machine to the next.
4747
**
4848
** This code is copied out of SQLite.
@@ -112,11 +112,11 @@
112112
}
113113
#endif
114114
115115
/*
116116
** Create a child process running shell command "zCmd". *ppOut is
117
-** a FILE that becomes the standard input of the child process.
117
+** a FILE that becomes the standard input of the child process.
118118
** (The caller writes to *ppOut in order to send text to the child.)
119119
** *ppIn is stdout from the child process. (The caller
120120
** reads from *ppIn in order to receive input from the child.)
121121
** Note that *ppIn is an unbuffered file descriptor, not a FILE.
122122
** The process ID of the child is written into *pChildPid.
@@ -124,17 +124,17 @@
124124
** Return the number of errors.
125125
*/
126126
int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
127127
#ifdef _WIN32
128128
HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
129
- SECURITY_ATTRIBUTES saAttr;
129
+ SECURITY_ATTRIBUTES saAttr;
130130
DWORD childPid = 0;
131131
int fd;
132132
133133
saAttr.nLength = sizeof(saAttr);
134134
saAttr.bInheritHandle = TRUE;
135
- saAttr.lpSecurityDescriptor = NULL;
135
+ saAttr.lpSecurityDescriptor = NULL;
136136
hStderr = GetStdHandle(STD_ERROR_HANDLE);
137137
if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
138138
win32_fatal_error("cannot create pipe for stdout");
139139
}
140140
SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
@@ -141,18 +141,18 @@
141141
142142
if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
143143
win32_fatal_error("cannot create pipe for stdin");
144144
}
145145
SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
146
-
146
+
147147
win32_create_child_process(fossil_utf8_to_unicode(zCmd),
148148
hStdinRd, hStdoutWr, hStderr,&childPid);
149149
*pChildPid = childPid;
150150
*pfdIn = _open_osfhandle(PTR_TO_INT(hStdoutRd), 0);
151151
fd = _open_osfhandle(PTR_TO_INT(hStdinWr), 0);
152152
*ppOut = _fdopen(fd, "w");
153
- CloseHandle(hStdinRd);
153
+ CloseHandle(hStdinRd);
154154
CloseHandle(hStdoutWr);
155155
return 0;
156156
#else
157157
int pin[2], pout[2];
158158
*pfdIn = 0;
159159
--- src/popen.c
+++ src/popen.c
@@ -38,11 +38,11 @@
38 ** The following macros are used to cast pointers to integers and
39 ** integers to pointers. The way you do this varies from one compiler
40 ** to the next, so we have developed the following set of #if statements
41 ** to generate appropriate macros for a wide range of compilers.
42 **
43 ** The correct "ANSI" way to do this is to use the intptr_t type.
44 ** Unfortunately, that typedef is not available on all compilers, or
45 ** if it is available, it requires an #include of specific headers
46 ** that vary from one machine to the next.
47 **
48 ** This code is copied out of SQLite.
@@ -112,11 +112,11 @@
112 }
113 #endif
114
115 /*
116 ** Create a child process running shell command "zCmd". *ppOut is
117 ** a FILE that becomes the standard input of the child process.
118 ** (The caller writes to *ppOut in order to send text to the child.)
119 ** *ppIn is stdout from the child process. (The caller
120 ** reads from *ppIn in order to receive input from the child.)
121 ** Note that *ppIn is an unbuffered file descriptor, not a FILE.
122 ** The process ID of the child is written into *pChildPid.
@@ -124,17 +124,17 @@
124 ** Return the number of errors.
125 */
126 int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
127 #ifdef _WIN32
128 HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
129 SECURITY_ATTRIBUTES saAttr;
130 DWORD childPid = 0;
131 int fd;
132
133 saAttr.nLength = sizeof(saAttr);
134 saAttr.bInheritHandle = TRUE;
135 saAttr.lpSecurityDescriptor = NULL;
136 hStderr = GetStdHandle(STD_ERROR_HANDLE);
137 if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
138 win32_fatal_error("cannot create pipe for stdout");
139 }
140 SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
@@ -141,18 +141,18 @@
141
142 if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
143 win32_fatal_error("cannot create pipe for stdin");
144 }
145 SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
146
147 win32_create_child_process(fossil_utf8_to_unicode(zCmd),
148 hStdinRd, hStdoutWr, hStderr,&childPid);
149 *pChildPid = childPid;
150 *pfdIn = _open_osfhandle(PTR_TO_INT(hStdoutRd), 0);
151 fd = _open_osfhandle(PTR_TO_INT(hStdinWr), 0);
152 *ppOut = _fdopen(fd, "w");
153 CloseHandle(hStdinRd);
154 CloseHandle(hStdoutWr);
155 return 0;
156 #else
157 int pin[2], pout[2];
158 *pfdIn = 0;
159
--- src/popen.c
+++ src/popen.c
@@ -38,11 +38,11 @@
38 ** The following macros are used to cast pointers to integers and
39 ** integers to pointers. The way you do this varies from one compiler
40 ** to the next, so we have developed the following set of #if statements
41 ** to generate appropriate macros for a wide range of compilers.
42 **
43 ** The correct "ANSI" way to do this is to use the intptr_t type.
44 ** Unfortunately, that typedef is not available on all compilers, or
45 ** if it is available, it requires an #include of specific headers
46 ** that vary from one machine to the next.
47 **
48 ** This code is copied out of SQLite.
@@ -112,11 +112,11 @@
112 }
113 #endif
114
115 /*
116 ** Create a child process running shell command "zCmd". *ppOut is
117 ** a FILE that becomes the standard input of the child process.
118 ** (The caller writes to *ppOut in order to send text to the child.)
119 ** *ppIn is stdout from the child process. (The caller
120 ** reads from *ppIn in order to receive input from the child.)
121 ** Note that *ppIn is an unbuffered file descriptor, not a FILE.
122 ** The process ID of the child is written into *pChildPid.
@@ -124,17 +124,17 @@
124 ** Return the number of errors.
125 */
126 int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
127 #ifdef _WIN32
128 HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
129 SECURITY_ATTRIBUTES saAttr;
130 DWORD childPid = 0;
131 int fd;
132
133 saAttr.nLength = sizeof(saAttr);
134 saAttr.bInheritHandle = TRUE;
135 saAttr.lpSecurityDescriptor = NULL;
136 hStderr = GetStdHandle(STD_ERROR_HANDLE);
137 if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
138 win32_fatal_error("cannot create pipe for stdout");
139 }
140 SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
@@ -141,18 +141,18 @@
141
142 if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
143 win32_fatal_error("cannot create pipe for stdin");
144 }
145 SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
146
147 win32_create_child_process(fossil_utf8_to_unicode(zCmd),
148 hStdinRd, hStdoutWr, hStderr,&childPid);
149 *pChildPid = childPid;
150 *pfdIn = _open_osfhandle(PTR_TO_INT(hStdoutRd), 0);
151 fd = _open_osfhandle(PTR_TO_INT(hStdinWr), 0);
152 *ppOut = _fdopen(fd, "w");
153 CloseHandle(hStdinRd);
154 CloseHandle(hStdoutWr);
155 return 0;
156 #else
157 int pin[2], pout[2];
158 *pfdIn = 0;
159
+18 -5
--- src/report.c
+++ src/report.c
@@ -28,11 +28,11 @@
2828
#ifndef SQLITE_RECURSIVE
2929
# define SQLITE_RECURSIVE 33
3030
#endif
3131
3232
/*
33
-** WEBPAGE: /reportlist
33
+** WEBPAGE: reportlist
3434
**
3535
** Main menu for Tickets.
3636
*/
3737
void view_list(void){
3838
const char *zScript;
@@ -284,11 +284,15 @@
284284
report_unrestrict_sql();
285285
return zErr;
286286
}
287287
288288
/*
289
-** WEBPAGE: /rptsql
289
+** WEBPAGE: rptsql
290
+** URL: /rptsql?rn=N
291
+**
292
+** Display the SQL query used to generate a ticket report. The rn=N
293
+** query parameter identifies the specific report number to be displayed.
290294
*/
291295
void view_see_sql(void){
292296
int rn;
293297
const char *zTitle;
294298
const char *zSQL;
@@ -332,12 +336,21 @@
332336
style_footer();
333337
db_finalize(&q);
334338
}
335339
336340
/*
337
-** WEBPAGE: /rptnew
338
-** WEBPAGE: /rptedit
341
+** WEBPAGE: rptnew
342
+** WEBPAGE: rptedit
343
+**
344
+** Create (/rptnew) or edit (/rptedit) a ticket report format.
345
+** Query parameters:
346
+**
347
+** rn=N Ticket report number. (required)
348
+** t=TITLE Title of the report format
349
+** w=USER Owner of the report format
350
+** s=SQL SQL text used to implement the report
351
+** k=KEY Color key
339352
*/
340353
void view_edit(void){
341354
int rn;
342355
const char *zTitle;
343356
const char *z;
@@ -1061,11 +1074,11 @@
10611074
@ </script>
10621075
}
10631076
10641077
10651078
/*
1066
-** WEBPAGE: /rptview
1079
+** WEBPAGE: rptview
10671080
**
10681081
** Generate a report. The rn query parameter is the report number
10691082
** corresponding to REPORTFMT.RN. If the tablist query parameter exists,
10701083
** then the output consists of lines of tab-separated fields instead of
10711084
** an HTML table.
10721085
--- src/report.c
+++ src/report.c
@@ -28,11 +28,11 @@
28 #ifndef SQLITE_RECURSIVE
29 # define SQLITE_RECURSIVE 33
30 #endif
31
32 /*
33 ** WEBPAGE: /reportlist
34 **
35 ** Main menu for Tickets.
36 */
37 void view_list(void){
38 const char *zScript;
@@ -284,11 +284,15 @@
284 report_unrestrict_sql();
285 return zErr;
286 }
287
288 /*
289 ** WEBPAGE: /rptsql
 
 
 
 
290 */
291 void view_see_sql(void){
292 int rn;
293 const char *zTitle;
294 const char *zSQL;
@@ -332,12 +336,21 @@
332 style_footer();
333 db_finalize(&q);
334 }
335
336 /*
337 ** WEBPAGE: /rptnew
338 ** WEBPAGE: /rptedit
 
 
 
 
 
 
 
 
 
339 */
340 void view_edit(void){
341 int rn;
342 const char *zTitle;
343 const char *z;
@@ -1061,11 +1074,11 @@
1061 @ </script>
1062 }
1063
1064
1065 /*
1066 ** WEBPAGE: /rptview
1067 **
1068 ** Generate a report. The rn query parameter is the report number
1069 ** corresponding to REPORTFMT.RN. If the tablist query parameter exists,
1070 ** then the output consists of lines of tab-separated fields instead of
1071 ** an HTML table.
1072
--- src/report.c
+++ src/report.c
@@ -28,11 +28,11 @@
28 #ifndef SQLITE_RECURSIVE
29 # define SQLITE_RECURSIVE 33
30 #endif
31
32 /*
33 ** WEBPAGE: reportlist
34 **
35 ** Main menu for Tickets.
36 */
37 void view_list(void){
38 const char *zScript;
@@ -284,11 +284,15 @@
284 report_unrestrict_sql();
285 return zErr;
286 }
287
288 /*
289 ** WEBPAGE: rptsql
290 ** URL: /rptsql?rn=N
291 **
292 ** Display the SQL query used to generate a ticket report. The rn=N
293 ** query parameter identifies the specific report number to be displayed.
294 */
295 void view_see_sql(void){
296 int rn;
297 const char *zTitle;
298 const char *zSQL;
@@ -332,12 +336,21 @@
336 style_footer();
337 db_finalize(&q);
338 }
339
340 /*
341 ** WEBPAGE: rptnew
342 ** WEBPAGE: rptedit
343 **
344 ** Create (/rptnew) or edit (/rptedit) a ticket report format.
345 ** Query parameters:
346 **
347 ** rn=N Ticket report number. (required)
348 ** t=TITLE Title of the report format
349 ** w=USER Owner of the report format
350 ** s=SQL SQL text used to implement the report
351 ** k=KEY Color key
352 */
353 void view_edit(void){
354 int rn;
355 const char *zTitle;
356 const char *z;
@@ -1061,11 +1074,11 @@
1074 @ </script>
1075 }
1076
1077
1078 /*
1079 ** WEBPAGE: rptview
1080 **
1081 ** Generate a report. The rn query parameter is the report number
1082 ** corresponding to REPORTFMT.RN. If the tablist query parameter exists,
1083 ** then the output consists of lines of tab-separated fields instead of
1084 ** an HTML table.
1085
+2 -3
--- src/schema.c
+++ src/schema.c
@@ -367,10 +367,11 @@
367367
@ INSERT INTO tag VALUES(6, 'private'); -- TAG_PRIVATE
368368
@ INSERT INTO tag VALUES(7, 'cluster'); -- TAG_CLUSTER
369369
@ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH
370370
@ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED
371371
@ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT
372
+@ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE
372373
@
373374
@ -- Assignments of tags to baselines. Note that we allow tags to
374375
@ -- have values assigned to them. So we are not really dealing with
375376
@ -- tags here. These are really properties. But we are going to
376377
@ -- keep calling them tags because in many cases the value is ignored.
@@ -466,13 +467,11 @@
466467
# define TAG_PRIVATE 6 /* Do not sync */
467468
# define TAG_CLUSTER 7 /* A cluster */
468469
# define TAG_BRANCH 8 /* Value is name of the current branch */
469470
# define TAG_CLOSED 9 /* Do not display this check-in as a leaf */
470471
# define TAG_PARENT 10 /* Change to parentage on a check-in */
471
-#endif
472
-#if EXPORT_INTERFACE
473
-# define MAX_INT_TAG 16 /* The largest pre-assigned tag id */
472
+# define TAG_NOTE 11 /* Extra text appended to a check-in comment */
474473
#endif
475474
476475
/*
477476
** The schema for the local FOSSIL database file found at the root
478477
** of every check-out. This database contains the complete state of
479478
--- src/schema.c
+++ src/schema.c
@@ -367,10 +367,11 @@
367 @ INSERT INTO tag VALUES(6, 'private'); -- TAG_PRIVATE
368 @ INSERT INTO tag VALUES(7, 'cluster'); -- TAG_CLUSTER
369 @ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH
370 @ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED
371 @ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT
 
372 @
373 @ -- Assignments of tags to baselines. Note that we allow tags to
374 @ -- have values assigned to them. So we are not really dealing with
375 @ -- tags here. These are really properties. But we are going to
376 @ -- keep calling them tags because in many cases the value is ignored.
@@ -466,13 +467,11 @@
466 # define TAG_PRIVATE 6 /* Do not sync */
467 # define TAG_CLUSTER 7 /* A cluster */
468 # define TAG_BRANCH 8 /* Value is name of the current branch */
469 # define TAG_CLOSED 9 /* Do not display this check-in as a leaf */
470 # define TAG_PARENT 10 /* Change to parentage on a check-in */
471 #endif
472 #if EXPORT_INTERFACE
473 # define MAX_INT_TAG 16 /* The largest pre-assigned tag id */
474 #endif
475
476 /*
477 ** The schema for the local FOSSIL database file found at the root
478 ** of every check-out. This database contains the complete state of
479
--- src/schema.c
+++ src/schema.c
@@ -367,10 +367,11 @@
367 @ INSERT INTO tag VALUES(6, 'private'); -- TAG_PRIVATE
368 @ INSERT INTO tag VALUES(7, 'cluster'); -- TAG_CLUSTER
369 @ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH
370 @ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED
371 @ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT
372 @ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE
373 @
374 @ -- Assignments of tags to baselines. Note that we allow tags to
375 @ -- have values assigned to them. So we are not really dealing with
376 @ -- tags here. These are really properties. But we are going to
377 @ -- keep calling them tags because in many cases the value is ignored.
@@ -466,13 +467,11 @@
467 # define TAG_PRIVATE 6 /* Do not sync */
468 # define TAG_CLUSTER 7 /* A cluster */
469 # define TAG_BRANCH 8 /* Value is name of the current branch */
470 # define TAG_CLOSED 9 /* Do not display this check-in as a leaf */
471 # define TAG_PARENT 10 /* Change to parentage on a check-in */
472 # define TAG_NOTE 11 /* Extra text appended to a check-in comment */
 
 
473 #endif
474
475 /*
476 ** The schema for the local FOSSIL database file found at the root
477 ** of every check-out. This database contains the complete state of
478
+9 -1
--- src/search.c
+++ src/search.c
@@ -1047,14 +1047,22 @@
10471047
@ </div>
10481048
}
10491049
}
10501050
10511051
/*
1052
-** WEBPAGE: /search
1052
+** WEBPAGE: search
10531053
**
10541054
** Search for check-in comments, documents, tickets, or wiki that
10551055
** match a user-supplied pattern.
1056
+**
1057
+** s=PATTERN Specify the full-text pattern to search for
1058
+** y=TYPE What to search.
1059
+** c -> check-ins
1060
+** d -> documentation
1061
+** t -> tickets
1062
+** w -> wiki
1063
+** all -> everything
10561064
*/
10571065
void search_page(void){
10581066
login_check_credentials();
10591067
style_header("Search");
10601068
search_screen(SRCH_ALL, 1);
10611069
--- src/search.c
+++ src/search.c
@@ -1047,14 +1047,22 @@
1047 @ </div>
1048 }
1049 }
1050
1051 /*
1052 ** WEBPAGE: /search
1053 **
1054 ** Search for check-in comments, documents, tickets, or wiki that
1055 ** match a user-supplied pattern.
 
 
 
 
 
 
 
 
1056 */
1057 void search_page(void){
1058 login_check_credentials();
1059 style_header("Search");
1060 search_screen(SRCH_ALL, 1);
1061
--- src/search.c
+++ src/search.c
@@ -1047,14 +1047,22 @@
1047 @ </div>
1048 }
1049 }
1050
1051 /*
1052 ** WEBPAGE: search
1053 **
1054 ** Search for check-in comments, documents, tickets, or wiki that
1055 ** match a user-supplied pattern.
1056 **
1057 ** s=PATTERN Specify the full-text pattern to search for
1058 ** y=TYPE What to search.
1059 ** c -> check-ins
1060 ** d -> documentation
1061 ** t -> tickets
1062 ** w -> wiki
1063 ** all -> everything
1064 */
1065 void search_page(void){
1066 login_check_credentials();
1067 style_header("Search");
1068 search_screen(SRCH_ALL, 1);
1069
+33 -7
--- src/setup.c
+++ src/setup.c
@@ -54,11 +54,13 @@
5454
}
5555
5656
5757
5858
/*
59
-** WEBPAGE: /setup
59
+** WEBPAGE: setup
60
+**
61
+** Main menu for the administrative pages. Requires Admin privileges.
6062
*/
6163
void setup_page(void){
6264
login_check_credentials();
6365
if( !g.perm.Setup ){
6466
login_needed(0);
@@ -123,12 +125,12 @@
123125
"A record of received artifacts and their sources");
124126
setup_menu_entry("User Log", "access_log",
125127
"A record of login attempts");
126128
setup_menu_entry("Administrative Log", "admin_log",
127129
"View the admin_log entries");
128
- setup_menu_entry("Stats", "stat",
129
- "Display repository statistics");
130
+ setup_menu_entry("Sitemap", "sitemap",
131
+ "Links to miscellaneous pages");
130132
setup_menu_entry("SQL", "admin_sql",
131133
"Enter raw SQL commands");
132134
setup_menu_entry("TH1", "admin_th1",
133135
"Enter raw TH1 commands");
134136
@ </table>
@@ -138,11 +140,11 @@
138140
139141
/*
140142
** WEBPAGE: setup_ulist
141143
**
142144
** Show a list of users. Clicking on any user jumps to the edit
143
-** screen for that user.
145
+** screen for that user. Requires Admin privileges.
144146
*/
145147
void setup_ulist(void){
146148
Stmt s;
147149
int prevLevel = 0;
148150
@@ -313,11 +315,14 @@
313315
while( zPw[0]=='*' ){ zPw++; }
314316
return zPw[0]!=0;
315317
}
316318
317319
/*
318
-** WEBPAGE: /setup_uedit
320
+** WEBPAGE: setup_uedit
321
+**
322
+** Edit information about a user or create a new user.
323
+** Requires Admin privileges.
319324
*/
320325
void user_edit(void){
321326
const char *zId, *zLogin, *zInfo, *zCap, *zPw;
322327
const char *zGroup;
323328
const char *zOldLogin;
@@ -989,10 +994,12 @@
989994
}
990995
991996
992997
/*
993998
** WEBPAGE: setup_access
999
+**
1000
+** The access-control settings page. Requires Admin privileges.
9941001
*/
9951002
void setup_access(void){
9961003
login_check_credentials();
9971004
if( !g.perm.Setup ){
9981005
login_needed(0);
@@ -1186,10 +1193,13 @@
11861193
style_footer();
11871194
}
11881195
11891196
/*
11901197
** WEBPAGE: setup_login_group
1198
+**
1199
+** Change how the current repository participates in a login
1200
+** group.
11911201
*/
11921202
void setup_login_group(void){
11931203
const char *zGroup;
11941204
char *zErrMsg = 0;
11951205
Blob fullName;
@@ -1299,10 +1309,13 @@
12991309
style_footer();
13001310
}
13011311
13021312
/*
13031313
** WEBPAGE: setup_timeline
1314
+**
1315
+** Edit administrative settings controlling the display of
1316
+** timelines.
13041317
*/
13051318
void setup_timeline(void){
13061319
double tmDiff;
13071320
char zTmDiff[20];
13081321
static const char *const azTimeFormats[] = {
@@ -1385,10 +1398,13 @@
13851398
style_footer();
13861399
}
13871400
13881401
/*
13891402
** WEBPAGE: setup_settings
1403
+**
1404
+** Change or view miscellanous settings. Part of the
1405
+** Admin pages requiring Admin privileges.
13901406
*/
13911407
void setup_settings(void){
13921408
Setting const *pSet;
13931409
13941410
login_check_credentials();
@@ -1468,10 +1484,12 @@
14681484
style_footer();
14691485
}
14701486
14711487
/*
14721488
** WEBPAGE: setup_config
1489
+**
1490
+** The "Admin/Configuration" page. Requires Admin privilege.
14731491
*/
14741492
void setup_config(void){
14751493
login_check_credentials();
14761494
if( !g.perm.Setup ){
14771495
login_needed(0);
@@ -1547,10 +1565,12 @@
15471565
style_footer();
15481566
}
15491567
15501568
/*
15511569
** WEBPAGE: setup_modreq
1570
+**
1571
+** Admin page for setting up moderation of tickets and wiki.
15521572
*/
15531573
void setup_modreq(void){
15541574
login_check_credentials();
15551575
if( !g.perm.Setup ){
15561576
login_needed(0);
@@ -1592,10 +1612,13 @@
15921612
15931613
}
15941614
15951615
/*
15961616
** WEBPAGE: setup_adunit
1617
+**
1618
+** Administrative page for configuring and controlling ad units
1619
+** and how they are displayed.
15971620
*/
15981621
void setup_adunit(void){
15991622
login_check_credentials();
16001623
if( !g.perm.Setup ){
16011624
login_needed(0);
@@ -1660,10 +1683,12 @@
16601683
db_end_transaction(0);
16611684
}
16621685
16631686
/*
16641687
** WEBPAGE: setup_logo
1688
+**
1689
+** Administrative page for changing the logo image.
16651690
*/
16661691
void setup_logo(void){
16671692
const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
16681693
const char *zLogoMime = db_get("logo-mimetype","image/gif");
16691694
const char *aLogoImg = P("logoim");
@@ -1812,10 +1837,11 @@
18121837
18131838
/*
18141839
** WEBPAGE: admin_sql
18151840
**
18161841
** Run raw SQL commands against the database file using the web interface.
1842
+** Requires Admin privileges.
18171843
*/
18181844
void sql_page(void){
18191845
const char *zQ = P("q");
18201846
int go = P("go")!=0;
18211847
login_check_credentials();
@@ -1933,11 +1959,11 @@
19331959
/*
19341960
** WEBPAGE: admin_th1
19351961
**
19361962
** Run raw TH1 commands using the web interface. If Tcl integration was
19371963
** enabled at compile-time and the "tcl" setting is enabled, Tcl commands
1938
-** may be run as well.
1964
+** may be run as well. Requires Admin privilege.
19391965
*/
19401966
void th1_page(void){
19411967
const char *zQ = P("q");
19421968
int go = P("go")!=0;
19431969
login_check_credentials();
@@ -2054,11 +2080,11 @@
20542080
}
20552081
20562082
/*
20572083
** WEBPAGE: srchsetup
20582084
**
2059
-** Configure the search engine.
2085
+** Configure the search engine. Requires Admin privilege.
20602086
*/
20612087
void page_srchsetup(){
20622088
login_check_credentials();
20632089
if( !g.perm.Setup && !g.perm.Admin ){
20642090
login_needed(0);
20652091
--- src/setup.c
+++ src/setup.c
@@ -54,11 +54,13 @@
54 }
55
56
57
58 /*
59 ** WEBPAGE: /setup
 
 
60 */
61 void setup_page(void){
62 login_check_credentials();
63 if( !g.perm.Setup ){
64 login_needed(0);
@@ -123,12 +125,12 @@
123 "A record of received artifacts and their sources");
124 setup_menu_entry("User Log", "access_log",
125 "A record of login attempts");
126 setup_menu_entry("Administrative Log", "admin_log",
127 "View the admin_log entries");
128 setup_menu_entry("Stats", "stat",
129 "Display repository statistics");
130 setup_menu_entry("SQL", "admin_sql",
131 "Enter raw SQL commands");
132 setup_menu_entry("TH1", "admin_th1",
133 "Enter raw TH1 commands");
134 @ </table>
@@ -138,11 +140,11 @@
138
139 /*
140 ** WEBPAGE: setup_ulist
141 **
142 ** Show a list of users. Clicking on any user jumps to the edit
143 ** screen for that user.
144 */
145 void setup_ulist(void){
146 Stmt s;
147 int prevLevel = 0;
148
@@ -313,11 +315,14 @@
313 while( zPw[0]=='*' ){ zPw++; }
314 return zPw[0]!=0;
315 }
316
317 /*
318 ** WEBPAGE: /setup_uedit
 
 
 
319 */
320 void user_edit(void){
321 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
322 const char *zGroup;
323 const char *zOldLogin;
@@ -989,10 +994,12 @@
989 }
990
991
992 /*
993 ** WEBPAGE: setup_access
 
 
994 */
995 void setup_access(void){
996 login_check_credentials();
997 if( !g.perm.Setup ){
998 login_needed(0);
@@ -1186,10 +1193,13 @@
1186 style_footer();
1187 }
1188
1189 /*
1190 ** WEBPAGE: setup_login_group
 
 
 
1191 */
1192 void setup_login_group(void){
1193 const char *zGroup;
1194 char *zErrMsg = 0;
1195 Blob fullName;
@@ -1299,10 +1309,13 @@
1299 style_footer();
1300 }
1301
1302 /*
1303 ** WEBPAGE: setup_timeline
 
 
 
1304 */
1305 void setup_timeline(void){
1306 double tmDiff;
1307 char zTmDiff[20];
1308 static const char *const azTimeFormats[] = {
@@ -1385,10 +1398,13 @@
1385 style_footer();
1386 }
1387
1388 /*
1389 ** WEBPAGE: setup_settings
 
 
 
1390 */
1391 void setup_settings(void){
1392 Setting const *pSet;
1393
1394 login_check_credentials();
@@ -1468,10 +1484,12 @@
1468 style_footer();
1469 }
1470
1471 /*
1472 ** WEBPAGE: setup_config
 
 
1473 */
1474 void setup_config(void){
1475 login_check_credentials();
1476 if( !g.perm.Setup ){
1477 login_needed(0);
@@ -1547,10 +1565,12 @@
1547 style_footer();
1548 }
1549
1550 /*
1551 ** WEBPAGE: setup_modreq
 
 
1552 */
1553 void setup_modreq(void){
1554 login_check_credentials();
1555 if( !g.perm.Setup ){
1556 login_needed(0);
@@ -1592,10 +1612,13 @@
1592
1593 }
1594
1595 /*
1596 ** WEBPAGE: setup_adunit
 
 
 
1597 */
1598 void setup_adunit(void){
1599 login_check_credentials();
1600 if( !g.perm.Setup ){
1601 login_needed(0);
@@ -1660,10 +1683,12 @@
1660 db_end_transaction(0);
1661 }
1662
1663 /*
1664 ** WEBPAGE: setup_logo
 
 
1665 */
1666 void setup_logo(void){
1667 const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
1668 const char *zLogoMime = db_get("logo-mimetype","image/gif");
1669 const char *aLogoImg = P("logoim");
@@ -1812,10 +1837,11 @@
1812
1813 /*
1814 ** WEBPAGE: admin_sql
1815 **
1816 ** Run raw SQL commands against the database file using the web interface.
 
1817 */
1818 void sql_page(void){
1819 const char *zQ = P("q");
1820 int go = P("go")!=0;
1821 login_check_credentials();
@@ -1933,11 +1959,11 @@
1933 /*
1934 ** WEBPAGE: admin_th1
1935 **
1936 ** Run raw TH1 commands using the web interface. If Tcl integration was
1937 ** enabled at compile-time and the "tcl" setting is enabled, Tcl commands
1938 ** may be run as well.
1939 */
1940 void th1_page(void){
1941 const char *zQ = P("q");
1942 int go = P("go")!=0;
1943 login_check_credentials();
@@ -2054,11 +2080,11 @@
2054 }
2055
2056 /*
2057 ** WEBPAGE: srchsetup
2058 **
2059 ** Configure the search engine.
2060 */
2061 void page_srchsetup(){
2062 login_check_credentials();
2063 if( !g.perm.Setup && !g.perm.Admin ){
2064 login_needed(0);
2065
--- src/setup.c
+++ src/setup.c
@@ -54,11 +54,13 @@
54 }
55
56
57
58 /*
59 ** WEBPAGE: setup
60 **
61 ** Main menu for the administrative pages. Requires Admin privileges.
62 */
63 void setup_page(void){
64 login_check_credentials();
65 if( !g.perm.Setup ){
66 login_needed(0);
@@ -123,12 +125,12 @@
125 "A record of received artifacts and their sources");
126 setup_menu_entry("User Log", "access_log",
127 "A record of login attempts");
128 setup_menu_entry("Administrative Log", "admin_log",
129 "View the admin_log entries");
130 setup_menu_entry("Sitemap", "sitemap",
131 "Links to miscellaneous pages");
132 setup_menu_entry("SQL", "admin_sql",
133 "Enter raw SQL commands");
134 setup_menu_entry("TH1", "admin_th1",
135 "Enter raw TH1 commands");
136 @ </table>
@@ -138,11 +140,11 @@
140
141 /*
142 ** WEBPAGE: setup_ulist
143 **
144 ** Show a list of users. Clicking on any user jumps to the edit
145 ** screen for that user. Requires Admin privileges.
146 */
147 void setup_ulist(void){
148 Stmt s;
149 int prevLevel = 0;
150
@@ -313,11 +315,14 @@
315 while( zPw[0]=='*' ){ zPw++; }
316 return zPw[0]!=0;
317 }
318
319 /*
320 ** WEBPAGE: setup_uedit
321 **
322 ** Edit information about a user or create a new user.
323 ** Requires Admin privileges.
324 */
325 void user_edit(void){
326 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
327 const char *zGroup;
328 const char *zOldLogin;
@@ -989,10 +994,12 @@
994 }
995
996
997 /*
998 ** WEBPAGE: setup_access
999 **
1000 ** The access-control settings page. Requires Admin privileges.
1001 */
1002 void setup_access(void){
1003 login_check_credentials();
1004 if( !g.perm.Setup ){
1005 login_needed(0);
@@ -1186,10 +1193,13 @@
1193 style_footer();
1194 }
1195
1196 /*
1197 ** WEBPAGE: setup_login_group
1198 **
1199 ** Change how the current repository participates in a login
1200 ** group.
1201 */
1202 void setup_login_group(void){
1203 const char *zGroup;
1204 char *zErrMsg = 0;
1205 Blob fullName;
@@ -1299,10 +1309,13 @@
1309 style_footer();
1310 }
1311
1312 /*
1313 ** WEBPAGE: setup_timeline
1314 **
1315 ** Edit administrative settings controlling the display of
1316 ** timelines.
1317 */
1318 void setup_timeline(void){
1319 double tmDiff;
1320 char zTmDiff[20];
1321 static const char *const azTimeFormats[] = {
@@ -1385,10 +1398,13 @@
1398 style_footer();
1399 }
1400
1401 /*
1402 ** WEBPAGE: setup_settings
1403 **
1404 ** Change or view miscellanous settings. Part of the
1405 ** Admin pages requiring Admin privileges.
1406 */
1407 void setup_settings(void){
1408 Setting const *pSet;
1409
1410 login_check_credentials();
@@ -1468,10 +1484,12 @@
1484 style_footer();
1485 }
1486
1487 /*
1488 ** WEBPAGE: setup_config
1489 **
1490 ** The "Admin/Configuration" page. Requires Admin privilege.
1491 */
1492 void setup_config(void){
1493 login_check_credentials();
1494 if( !g.perm.Setup ){
1495 login_needed(0);
@@ -1547,10 +1565,12 @@
1565 style_footer();
1566 }
1567
1568 /*
1569 ** WEBPAGE: setup_modreq
1570 **
1571 ** Admin page for setting up moderation of tickets and wiki.
1572 */
1573 void setup_modreq(void){
1574 login_check_credentials();
1575 if( !g.perm.Setup ){
1576 login_needed(0);
@@ -1592,10 +1612,13 @@
1612
1613 }
1614
1615 /*
1616 ** WEBPAGE: setup_adunit
1617 **
1618 ** Administrative page for configuring and controlling ad units
1619 ** and how they are displayed.
1620 */
1621 void setup_adunit(void){
1622 login_check_credentials();
1623 if( !g.perm.Setup ){
1624 login_needed(0);
@@ -1660,10 +1683,12 @@
1683 db_end_transaction(0);
1684 }
1685
1686 /*
1687 ** WEBPAGE: setup_logo
1688 **
1689 ** Administrative page for changing the logo image.
1690 */
1691 void setup_logo(void){
1692 const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
1693 const char *zLogoMime = db_get("logo-mimetype","image/gif");
1694 const char *aLogoImg = P("logoim");
@@ -1812,10 +1837,11 @@
1837
1838 /*
1839 ** WEBPAGE: admin_sql
1840 **
1841 ** Run raw SQL commands against the database file using the web interface.
1842 ** Requires Admin privileges.
1843 */
1844 void sql_page(void){
1845 const char *zQ = P("q");
1846 int go = P("go")!=0;
1847 login_check_credentials();
@@ -1933,11 +1959,11 @@
1959 /*
1960 ** WEBPAGE: admin_th1
1961 **
1962 ** Run raw TH1 commands using the web interface. If Tcl integration was
1963 ** enabled at compile-time and the "tcl" setting is enabled, Tcl commands
1964 ** may be run as well. Requires Admin privilege.
1965 */
1966 void th1_page(void){
1967 const char *zQ = P("q");
1968 int go = P("go")!=0;
1969 login_check_credentials();
@@ -2054,11 +2080,11 @@
2080 }
2081
2082 /*
2083 ** WEBPAGE: srchsetup
2084 **
2085 ** Configure the search engine. Requires Admin privilege.
2086 */
2087 void page_srchsetup(){
2088 login_check_credentials();
2089 if( !g.perm.Setup && !g.perm.Admin ){
2090 login_needed(0);
2091
+62 -53
--- src/shell.c
+++ src/shell.c
@@ -334,11 +334,11 @@
334334
/*
335335
** The following is the open SQLite database. We make a pointer
336336
** to this database a static variable so that it can be accessed
337337
** by the SIGINT handler to interrupt database processing.
338338
*/
339
-static sqlite3 *db = 0;
339
+static sqlite3 *globalDb = 0;
340340
341341
/*
342342
** True if an interrupt (Control-C) has been received.
343343
*/
344344
static volatile int seenInterrupt = 0;
@@ -525,10 +525,11 @@
525525
sqlite3 *db; /* The database */
526526
int echoOn; /* True to echo input commands */
527527
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
528528
int statsOn; /* True to display memory stats before each finalize */
529529
int scanstatsOn; /* True to display scan stats before each finalize */
530
+ int backslashOn; /* Resolve C-style \x escapes in SQL input text */
530531
int outCount; /* Revert to stdout when reaching zero */
531532
int cnt; /* Number of records displayed so far */
532533
FILE *out; /* Write results here */
533534
FILE *traceOut; /* Output for sqlite3_trace() */
534535
int nErr; /* Number of errors seen */
@@ -802,11 +803,11 @@
802803
*/
803804
static void interrupt_handler(int NotUsed){
804805
UNUSED_PARAMETER(NotUsed);
805806
seenInterrupt++;
806807
if( seenInterrupt>2 ) exit(1);
807
- if( db ) sqlite3_interrupt(db);
808
+ if( globalDb ) sqlite3_interrupt(globalDb);
808809
}
809810
#endif
810811
811812
/*
812813
** This is the callback routine that the shell
@@ -1906,27 +1907,27 @@
19061907
*/
19071908
static void open_db(ShellState *p, int keepAlive){
19081909
if( p->db==0 ){
19091910
sqlite3_initialize();
19101911
sqlite3_open(p->zDbFilename, &p->db);
1911
- db = p->db;
1912
- if( db && sqlite3_errcode(db)==SQLITE_OK ){
1913
- sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
1912
+ globalDb = p->db;
1913
+ if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
1914
+ sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
19141915
shellstaticFunc, 0, 0);
19151916
}
1916
- if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
1917
+ if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
19171918
fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
1918
- p->zDbFilename, sqlite3_errmsg(db));
1919
+ p->zDbFilename, sqlite3_errmsg(p->db));
19191920
if( keepAlive ) return;
19201921
exit(1);
19211922
}
19221923
#ifndef SQLITE_OMIT_LOAD_EXTENSION
19231924
sqlite3_enable_load_extension(p->db, 1);
19241925
#endif
1925
- sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
1926
+ sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
19261927
readfileFunc, 0, 0);
1927
- sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
1928
+ sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
19281929
writefileFunc, 0, 0);
19291930
}
19301931
}
19311932
19321933
/*
@@ -1942,11 +1943,11 @@
19421943
static void resolve_backslashes(char *z){
19431944
int i, j;
19441945
char c;
19451946
while( *z && *z!='\\' ) z++;
19461947
for(i=j=0; (c = z[i])!=0; i++, j++){
1947
- if( c=='\\' ){
1948
+ if( c=='\\' && z[i+1]!=0 ){
19481949
c = z[++i];
19491950
if( c=='n' ){
19501951
c = '\n';
19511952
}else if( c=='t' ){
19521953
c = '\t';
@@ -2583,36 +2584,36 @@
25832584
** process that line.
25842585
**
25852586
** Return 1 on error, 2 to exit, and 0 otherwise.
25862587
*/
25872588
static int do_meta_command(char *zLine, ShellState *p){
2588
- int i = 1;
2589
+ int h = 1;
25892590
int nArg = 0;
25902591
int n, c;
25912592
int rc = 0;
25922593
char *azArg[50];
25932594
25942595
/* Parse the input line into tokens.
25952596
*/
2596
- while( zLine[i] && nArg<ArraySize(azArg) ){
2597
- while( IsSpace(zLine[i]) ){ i++; }
2598
- if( zLine[i]==0 ) break;
2599
- if( zLine[i]=='\'' || zLine[i]=='"' ){
2600
- int delim = zLine[i++];
2601
- azArg[nArg++] = &zLine[i];
2602
- while( zLine[i] && zLine[i]!=delim ){
2603
- if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++;
2604
- i++;
2605
- }
2606
- if( zLine[i]==delim ){
2607
- zLine[i++] = 0;
2597
+ while( zLine[h] && nArg<ArraySize(azArg) ){
2598
+ while( IsSpace(zLine[h]) ){ h++; }
2599
+ if( zLine[h]==0 ) break;
2600
+ if( zLine[h]=='\'' || zLine[h]=='"' ){
2601
+ int delim = zLine[h++];
2602
+ azArg[nArg++] = &zLine[h];
2603
+ while( zLine[h] && zLine[h]!=delim ){
2604
+ if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
2605
+ h++;
2606
+ }
2607
+ if( zLine[h]==delim ){
2608
+ zLine[h++] = 0;
26082609
}
26092610
if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
26102611
}else{
2611
- azArg[nArg++] = &zLine[i];
2612
- while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
2613
- if( zLine[i] ) zLine[i++] = 0;
2612
+ azArg[nArg++] = &zLine[h];
2613
+ while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
2614
+ if( zLine[h] ) zLine[h++] = 0;
26142615
resolve_backslashes(azArg[nArg-1]);
26152616
}
26162617
}
26172618
26182619
/* Process the input line.
@@ -2984,11 +2985,11 @@
29842985
return 1;
29852986
}
29862987
nByte = strlen30(zSql);
29872988
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
29882989
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
2989
- if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
2990
+ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
29902991
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
29912992
char cSep = '(';
29922993
while( xRead(&sCtx) ){
29932994
zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z);
29942995
cSep = ',';
@@ -3004,21 +3005,21 @@
30043005
zCreate = sqlite3_mprintf("%z\n)", zCreate);
30053006
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
30063007
sqlite3_free(zCreate);
30073008
if( rc ){
30083009
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
3009
- sqlite3_errmsg(db));
3010
+ sqlite3_errmsg(p->db));
30103011
sqlite3_free(sCtx.z);
30113012
xCloser(sCtx.in);
30123013
return 1;
30133014
}
30143015
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
30153016
}
30163017
sqlite3_free(zSql);
30173018
if( rc ){
30183019
if (pStmt) sqlite3_finalize(pStmt);
3019
- fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
3020
+ fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
30203021
xCloser(sCtx.in);
30213022
return 1;
30223023
}
30233024
nCol = sqlite3_column_count(pStmt);
30243025
sqlite3_finalize(pStmt);
@@ -3039,17 +3040,17 @@
30393040
zSql[j++] = ')';
30403041
zSql[j] = 0;
30413042
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
30423043
sqlite3_free(zSql);
30433044
if( rc ){
3044
- fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
3045
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
30453046
if (pStmt) sqlite3_finalize(pStmt);
30463047
xCloser(sCtx.in);
30473048
return 1;
30483049
}
3049
- needCommit = sqlite3_get_autocommit(db);
3050
- if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
3050
+ needCommit = sqlite3_get_autocommit(p->db);
3051
+ if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
30513052
do{
30523053
int startLine = sCtx.nLine;
30533054
for(i=0; i<nCol; i++){
30543055
char *z = xRead(&sCtx);
30553056
/*
@@ -3084,19 +3085,19 @@
30843085
if( i>=nCol ){
30853086
sqlite3_step(pStmt);
30863087
rc = sqlite3_reset(pStmt);
30873088
if( rc!=SQLITE_OK ){
30883089
fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
3089
- sqlite3_errmsg(db));
3090
+ sqlite3_errmsg(p->db));
30903091
}
30913092
}
30923093
}while( sCtx.cTerm!=EOF );
30933094
30943095
xCloser(sCtx.in);
30953096
sqlite3_free(sCtx.z);
30963097
sqlite3_finalize(pStmt);
3097
- if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
3098
+ if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
30983099
}else
30993100
31003101
if( c=='i' && (strncmp(azArg[0], "indices", n)==0
31013102
|| strncmp(azArg[0], "indexes", n)==0) ){
31023103
ShellState data;
@@ -3646,17 +3647,17 @@
36463647
sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
36473648
}
36483649
while( sqlite3_step(pStmt)==SQLITE_ROW ){
36493650
if( nRow>=nAlloc ){
36503651
char **azNew;
3651
- int n = nAlloc*2 + 10;
3652
- azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n);
3652
+ int n2 = nAlloc*2 + 10;
3653
+ azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n2);
36533654
if( azNew==0 ){
36543655
fprintf(stderr, "Error: out of memory\n");
36553656
break;
36563657
}
3657
- nAlloc = n;
3658
+ nAlloc = n2;
36583659
azResult = azNew;
36593660
}
36603661
azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
36613662
if( azResult[nRow] ) nRow++;
36623663
}
@@ -3705,19 +3706,19 @@
37053706
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
37063707
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
37073708
{ "imposter", SQLITE_TESTCTRL_IMPOSTER },
37083709
};
37093710
int testctrl = -1;
3710
- int rc = 0;
3711
- int i, n;
3711
+ int rc2 = 0;
3712
+ int i, n2;
37123713
open_db(p, 0);
37133714
37143715
/* convert testctrl text option to value. allow any unique prefix
37153716
** of the option name, or a numerical value. */
3716
- n = strlen30(azArg[1]);
3717
+ n2 = strlen30(azArg[1]);
37173718
for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
3718
- if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
3719
+ if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
37193720
if( testctrl<0 ){
37203721
testctrl = aCtrl[i].ctrlCode;
37213722
}else{
37223723
fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
37233724
testctrl = -1;
@@ -3734,12 +3735,12 @@
37343735
/* sqlite3_test_control(int, db, int) */
37353736
case SQLITE_TESTCTRL_OPTIMIZATIONS:
37363737
case SQLITE_TESTCTRL_RESERVE:
37373738
if( nArg==3 ){
37383739
int opt = (int)strtol(azArg[2], 0, 0);
3739
- rc = sqlite3_test_control(testctrl, p->db, opt);
3740
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3740
+ rc2 = sqlite3_test_control(testctrl, p->db, opt);
3741
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
37413742
} else {
37423743
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
37433744
azArg[1]);
37443745
}
37453746
break;
@@ -3748,23 +3749,23 @@
37483749
case SQLITE_TESTCTRL_PRNG_SAVE:
37493750
case SQLITE_TESTCTRL_PRNG_RESTORE:
37503751
case SQLITE_TESTCTRL_PRNG_RESET:
37513752
case SQLITE_TESTCTRL_BYTEORDER:
37523753
if( nArg==2 ){
3753
- rc = sqlite3_test_control(testctrl);
3754
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3754
+ rc2 = sqlite3_test_control(testctrl);
3755
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
37553756
} else {
37563757
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
37573758
}
37583759
break;
37593760
37603761
/* sqlite3_test_control(int, uint) */
37613762
case SQLITE_TESTCTRL_PENDING_BYTE:
37623763
if( nArg==3 ){
37633764
unsigned int opt = (unsigned int)integerValue(azArg[2]);
3764
- rc = sqlite3_test_control(testctrl, opt);
3765
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3765
+ rc2 = sqlite3_test_control(testctrl, opt);
3766
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
37663767
} else {
37673768
fprintf(stderr,"Error: testctrl %s takes a single unsigned"
37683769
" int option\n", azArg[1]);
37693770
}
37703771
break;
@@ -3773,12 +3774,12 @@
37733774
case SQLITE_TESTCTRL_ASSERT:
37743775
case SQLITE_TESTCTRL_ALWAYS:
37753776
case SQLITE_TESTCTRL_NEVER_CORRUPT:
37763777
if( nArg==3 ){
37773778
int opt = booleanValue(azArg[2]);
3778
- rc = sqlite3_test_control(testctrl, opt);
3779
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3779
+ rc2 = sqlite3_test_control(testctrl, opt);
3780
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
37803781
} else {
37813782
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
37823783
azArg[1]);
37833784
}
37843785
break;
@@ -3786,26 +3787,26 @@
37863787
/* sqlite3_test_control(int, char *) */
37873788
#ifdef SQLITE_N_KEYWORD
37883789
case SQLITE_TESTCTRL_ISKEYWORD:
37893790
if( nArg==3 ){
37903791
const char *opt = azArg[2];
3791
- rc = sqlite3_test_control(testctrl, opt);
3792
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3792
+ rc2 = sqlite3_test_control(testctrl, opt);
3793
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
37933794
} else {
37943795
fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
37953796
azArg[1]);
37963797
}
37973798
break;
37983799
#endif
37993800
38003801
case SQLITE_TESTCTRL_IMPOSTER:
38013802
if( nArg==5 ){
3802
- rc = sqlite3_test_control(testctrl, p->db,
3803
+ rc2 = sqlite3_test_control(testctrl, p->db,
38033804
azArg[2],
38043805
integerValue(azArg[3]),
38053806
integerValue(azArg[4]));
3806
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3807
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
38073808
}else{
38083809
fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
38093810
}
38103811
break;
38113812
@@ -4109,10 +4110,11 @@
41094110
}
41104111
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
41114112
&& sqlite3_complete(zSql) ){
41124113
p->cnt = 0;
41134114
open_db(p, 0);
4115
+ if( p->backslashOn ) resolve_backslashes(zSql);
41144116
BEGIN_TIMER;
41154117
rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
41164118
END_TIMER;
41174119
if( rc || zErrMsg ){
41184120
char zPrefix[100];
@@ -4575,10 +4577,17 @@
45754577
data.autoEQP = 1;
45764578
}else if( strcmp(z,"-stats")==0 ){
45774579
data.statsOn = 1;
45784580
}else if( strcmp(z,"-scanstats")==0 ){
45794581
data.scanstatsOn = 1;
4582
+ }else if( strcmp(z,"-backslash")==0 ){
4583
+ /* Undocumented command-line option: -backslash
4584
+ ** Causes C-style backslash escapes to be evaluated in SQL statements
4585
+ ** prior to sending the SQL into SQLite. Useful for injecting
4586
+ ** crazy bytes in the middle of SQL statements for testing and debugging.
4587
+ */
4588
+ data.backslashOn = 1;
45804589
}else if( strcmp(z,"-bail")==0 ){
45814590
bail_on_error = 1;
45824591
}else if( strcmp(z,"-version")==0 ){
45834592
printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
45844593
return 0;
45854594
--- src/shell.c
+++ src/shell.c
@@ -334,11 +334,11 @@
334 /*
335 ** The following is the open SQLite database. We make a pointer
336 ** to this database a static variable so that it can be accessed
337 ** by the SIGINT handler to interrupt database processing.
338 */
339 static sqlite3 *db = 0;
340
341 /*
342 ** True if an interrupt (Control-C) has been received.
343 */
344 static volatile int seenInterrupt = 0;
@@ -525,10 +525,11 @@
525 sqlite3 *db; /* The database */
526 int echoOn; /* True to echo input commands */
527 int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
528 int statsOn; /* True to display memory stats before each finalize */
529 int scanstatsOn; /* True to display scan stats before each finalize */
 
530 int outCount; /* Revert to stdout when reaching zero */
531 int cnt; /* Number of records displayed so far */
532 FILE *out; /* Write results here */
533 FILE *traceOut; /* Output for sqlite3_trace() */
534 int nErr; /* Number of errors seen */
@@ -802,11 +803,11 @@
802 */
803 static void interrupt_handler(int NotUsed){
804 UNUSED_PARAMETER(NotUsed);
805 seenInterrupt++;
806 if( seenInterrupt>2 ) exit(1);
807 if( db ) sqlite3_interrupt(db);
808 }
809 #endif
810
811 /*
812 ** This is the callback routine that the shell
@@ -1906,27 +1907,27 @@
1906 */
1907 static void open_db(ShellState *p, int keepAlive){
1908 if( p->db==0 ){
1909 sqlite3_initialize();
1910 sqlite3_open(p->zDbFilename, &p->db);
1911 db = p->db;
1912 if( db && sqlite3_errcode(db)==SQLITE_OK ){
1913 sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
1914 shellstaticFunc, 0, 0);
1915 }
1916 if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
1917 fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
1918 p->zDbFilename, sqlite3_errmsg(db));
1919 if( keepAlive ) return;
1920 exit(1);
1921 }
1922 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1923 sqlite3_enable_load_extension(p->db, 1);
1924 #endif
1925 sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
1926 readfileFunc, 0, 0);
1927 sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
1928 writefileFunc, 0, 0);
1929 }
1930 }
1931
1932 /*
@@ -1942,11 +1943,11 @@
1942 static void resolve_backslashes(char *z){
1943 int i, j;
1944 char c;
1945 while( *z && *z!='\\' ) z++;
1946 for(i=j=0; (c = z[i])!=0; i++, j++){
1947 if( c=='\\' ){
1948 c = z[++i];
1949 if( c=='n' ){
1950 c = '\n';
1951 }else if( c=='t' ){
1952 c = '\t';
@@ -2583,36 +2584,36 @@
2583 ** process that line.
2584 **
2585 ** Return 1 on error, 2 to exit, and 0 otherwise.
2586 */
2587 static int do_meta_command(char *zLine, ShellState *p){
2588 int i = 1;
2589 int nArg = 0;
2590 int n, c;
2591 int rc = 0;
2592 char *azArg[50];
2593
2594 /* Parse the input line into tokens.
2595 */
2596 while( zLine[i] && nArg<ArraySize(azArg) ){
2597 while( IsSpace(zLine[i]) ){ i++; }
2598 if( zLine[i]==0 ) break;
2599 if( zLine[i]=='\'' || zLine[i]=='"' ){
2600 int delim = zLine[i++];
2601 azArg[nArg++] = &zLine[i];
2602 while( zLine[i] && zLine[i]!=delim ){
2603 if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++;
2604 i++;
2605 }
2606 if( zLine[i]==delim ){
2607 zLine[i++] = 0;
2608 }
2609 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
2610 }else{
2611 azArg[nArg++] = &zLine[i];
2612 while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
2613 if( zLine[i] ) zLine[i++] = 0;
2614 resolve_backslashes(azArg[nArg-1]);
2615 }
2616 }
2617
2618 /* Process the input line.
@@ -2984,11 +2985,11 @@
2984 return 1;
2985 }
2986 nByte = strlen30(zSql);
2987 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2988 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
2989 if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
2990 char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
2991 char cSep = '(';
2992 while( xRead(&sCtx) ){
2993 zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z);
2994 cSep = ',';
@@ -3004,21 +3005,21 @@
3004 zCreate = sqlite3_mprintf("%z\n)", zCreate);
3005 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
3006 sqlite3_free(zCreate);
3007 if( rc ){
3008 fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
3009 sqlite3_errmsg(db));
3010 sqlite3_free(sCtx.z);
3011 xCloser(sCtx.in);
3012 return 1;
3013 }
3014 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3015 }
3016 sqlite3_free(zSql);
3017 if( rc ){
3018 if (pStmt) sqlite3_finalize(pStmt);
3019 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
3020 xCloser(sCtx.in);
3021 return 1;
3022 }
3023 nCol = sqlite3_column_count(pStmt);
3024 sqlite3_finalize(pStmt);
@@ -3039,17 +3040,17 @@
3039 zSql[j++] = ')';
3040 zSql[j] = 0;
3041 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3042 sqlite3_free(zSql);
3043 if( rc ){
3044 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
3045 if (pStmt) sqlite3_finalize(pStmt);
3046 xCloser(sCtx.in);
3047 return 1;
3048 }
3049 needCommit = sqlite3_get_autocommit(db);
3050 if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
3051 do{
3052 int startLine = sCtx.nLine;
3053 for(i=0; i<nCol; i++){
3054 char *z = xRead(&sCtx);
3055 /*
@@ -3084,19 +3085,19 @@
3084 if( i>=nCol ){
3085 sqlite3_step(pStmt);
3086 rc = sqlite3_reset(pStmt);
3087 if( rc!=SQLITE_OK ){
3088 fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
3089 sqlite3_errmsg(db));
3090 }
3091 }
3092 }while( sCtx.cTerm!=EOF );
3093
3094 xCloser(sCtx.in);
3095 sqlite3_free(sCtx.z);
3096 sqlite3_finalize(pStmt);
3097 if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
3098 }else
3099
3100 if( c=='i' && (strncmp(azArg[0], "indices", n)==0
3101 || strncmp(azArg[0], "indexes", n)==0) ){
3102 ShellState data;
@@ -3646,17 +3647,17 @@
3646 sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
3647 }
3648 while( sqlite3_step(pStmt)==SQLITE_ROW ){
3649 if( nRow>=nAlloc ){
3650 char **azNew;
3651 int n = nAlloc*2 + 10;
3652 azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n);
3653 if( azNew==0 ){
3654 fprintf(stderr, "Error: out of memory\n");
3655 break;
3656 }
3657 nAlloc = n;
3658 azResult = azNew;
3659 }
3660 azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
3661 if( azResult[nRow] ) nRow++;
3662 }
@@ -3705,19 +3706,19 @@
3705 { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
3706 { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
3707 { "imposter", SQLITE_TESTCTRL_IMPOSTER },
3708 };
3709 int testctrl = -1;
3710 int rc = 0;
3711 int i, n;
3712 open_db(p, 0);
3713
3714 /* convert testctrl text option to value. allow any unique prefix
3715 ** of the option name, or a numerical value. */
3716 n = strlen30(azArg[1]);
3717 for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
3718 if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
3719 if( testctrl<0 ){
3720 testctrl = aCtrl[i].ctrlCode;
3721 }else{
3722 fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
3723 testctrl = -1;
@@ -3734,12 +3735,12 @@
3734 /* sqlite3_test_control(int, db, int) */
3735 case SQLITE_TESTCTRL_OPTIMIZATIONS:
3736 case SQLITE_TESTCTRL_RESERVE:
3737 if( nArg==3 ){
3738 int opt = (int)strtol(azArg[2], 0, 0);
3739 rc = sqlite3_test_control(testctrl, p->db, opt);
3740 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3741 } else {
3742 fprintf(stderr,"Error: testctrl %s takes a single int option\n",
3743 azArg[1]);
3744 }
3745 break;
@@ -3748,23 +3749,23 @@
3748 case SQLITE_TESTCTRL_PRNG_SAVE:
3749 case SQLITE_TESTCTRL_PRNG_RESTORE:
3750 case SQLITE_TESTCTRL_PRNG_RESET:
3751 case SQLITE_TESTCTRL_BYTEORDER:
3752 if( nArg==2 ){
3753 rc = sqlite3_test_control(testctrl);
3754 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3755 } else {
3756 fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
3757 }
3758 break;
3759
3760 /* sqlite3_test_control(int, uint) */
3761 case SQLITE_TESTCTRL_PENDING_BYTE:
3762 if( nArg==3 ){
3763 unsigned int opt = (unsigned int)integerValue(azArg[2]);
3764 rc = sqlite3_test_control(testctrl, opt);
3765 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3766 } else {
3767 fprintf(stderr,"Error: testctrl %s takes a single unsigned"
3768 " int option\n", azArg[1]);
3769 }
3770 break;
@@ -3773,12 +3774,12 @@
3773 case SQLITE_TESTCTRL_ASSERT:
3774 case SQLITE_TESTCTRL_ALWAYS:
3775 case SQLITE_TESTCTRL_NEVER_CORRUPT:
3776 if( nArg==3 ){
3777 int opt = booleanValue(azArg[2]);
3778 rc = sqlite3_test_control(testctrl, opt);
3779 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3780 } else {
3781 fprintf(stderr,"Error: testctrl %s takes a single int option\n",
3782 azArg[1]);
3783 }
3784 break;
@@ -3786,26 +3787,26 @@
3786 /* sqlite3_test_control(int, char *) */
3787 #ifdef SQLITE_N_KEYWORD
3788 case SQLITE_TESTCTRL_ISKEYWORD:
3789 if( nArg==3 ){
3790 const char *opt = azArg[2];
3791 rc = sqlite3_test_control(testctrl, opt);
3792 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3793 } else {
3794 fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
3795 azArg[1]);
3796 }
3797 break;
3798 #endif
3799
3800 case SQLITE_TESTCTRL_IMPOSTER:
3801 if( nArg==5 ){
3802 rc = sqlite3_test_control(testctrl, p->db,
3803 azArg[2],
3804 integerValue(azArg[3]),
3805 integerValue(azArg[4]));
3806 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3807 }else{
3808 fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
3809 }
3810 break;
3811
@@ -4109,10 +4110,11 @@
4109 }
4110 if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
4111 && sqlite3_complete(zSql) ){
4112 p->cnt = 0;
4113 open_db(p, 0);
 
4114 BEGIN_TIMER;
4115 rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
4116 END_TIMER;
4117 if( rc || zErrMsg ){
4118 char zPrefix[100];
@@ -4575,10 +4577,17 @@
4575 data.autoEQP = 1;
4576 }else if( strcmp(z,"-stats")==0 ){
4577 data.statsOn = 1;
4578 }else if( strcmp(z,"-scanstats")==0 ){
4579 data.scanstatsOn = 1;
 
 
 
 
 
 
 
4580 }else if( strcmp(z,"-bail")==0 ){
4581 bail_on_error = 1;
4582 }else if( strcmp(z,"-version")==0 ){
4583 printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
4584 return 0;
4585
--- src/shell.c
+++ src/shell.c
@@ -334,11 +334,11 @@
334 /*
335 ** The following is the open SQLite database. We make a pointer
336 ** to this database a static variable so that it can be accessed
337 ** by the SIGINT handler to interrupt database processing.
338 */
339 static sqlite3 *globalDb = 0;
340
341 /*
342 ** True if an interrupt (Control-C) has been received.
343 */
344 static volatile int seenInterrupt = 0;
@@ -525,10 +525,11 @@
525 sqlite3 *db; /* The database */
526 int echoOn; /* True to echo input commands */
527 int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
528 int statsOn; /* True to display memory stats before each finalize */
529 int scanstatsOn; /* True to display scan stats before each finalize */
530 int backslashOn; /* Resolve C-style \x escapes in SQL input text */
531 int outCount; /* Revert to stdout when reaching zero */
532 int cnt; /* Number of records displayed so far */
533 FILE *out; /* Write results here */
534 FILE *traceOut; /* Output for sqlite3_trace() */
535 int nErr; /* Number of errors seen */
@@ -802,11 +803,11 @@
803 */
804 static void interrupt_handler(int NotUsed){
805 UNUSED_PARAMETER(NotUsed);
806 seenInterrupt++;
807 if( seenInterrupt>2 ) exit(1);
808 if( globalDb ) sqlite3_interrupt(globalDb);
809 }
810 #endif
811
812 /*
813 ** This is the callback routine that the shell
@@ -1906,27 +1907,27 @@
1907 */
1908 static void open_db(ShellState *p, int keepAlive){
1909 if( p->db==0 ){
1910 sqlite3_initialize();
1911 sqlite3_open(p->zDbFilename, &p->db);
1912 globalDb = p->db;
1913 if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
1914 sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
1915 shellstaticFunc, 0, 0);
1916 }
1917 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
1918 fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
1919 p->zDbFilename, sqlite3_errmsg(p->db));
1920 if( keepAlive ) return;
1921 exit(1);
1922 }
1923 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1924 sqlite3_enable_load_extension(p->db, 1);
1925 #endif
1926 sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
1927 readfileFunc, 0, 0);
1928 sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
1929 writefileFunc, 0, 0);
1930 }
1931 }
1932
1933 /*
@@ -1942,11 +1943,11 @@
1943 static void resolve_backslashes(char *z){
1944 int i, j;
1945 char c;
1946 while( *z && *z!='\\' ) z++;
1947 for(i=j=0; (c = z[i])!=0; i++, j++){
1948 if( c=='\\' && z[i+1]!=0 ){
1949 c = z[++i];
1950 if( c=='n' ){
1951 c = '\n';
1952 }else if( c=='t' ){
1953 c = '\t';
@@ -2583,36 +2584,36 @@
2584 ** process that line.
2585 **
2586 ** Return 1 on error, 2 to exit, and 0 otherwise.
2587 */
2588 static int do_meta_command(char *zLine, ShellState *p){
2589 int h = 1;
2590 int nArg = 0;
2591 int n, c;
2592 int rc = 0;
2593 char *azArg[50];
2594
2595 /* Parse the input line into tokens.
2596 */
2597 while( zLine[h] && nArg<ArraySize(azArg) ){
2598 while( IsSpace(zLine[h]) ){ h++; }
2599 if( zLine[h]==0 ) break;
2600 if( zLine[h]=='\'' || zLine[h]=='"' ){
2601 int delim = zLine[h++];
2602 azArg[nArg++] = &zLine[h];
2603 while( zLine[h] && zLine[h]!=delim ){
2604 if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
2605 h++;
2606 }
2607 if( zLine[h]==delim ){
2608 zLine[h++] = 0;
2609 }
2610 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
2611 }else{
2612 azArg[nArg++] = &zLine[h];
2613 while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
2614 if( zLine[h] ) zLine[h++] = 0;
2615 resolve_backslashes(azArg[nArg-1]);
2616 }
2617 }
2618
2619 /* Process the input line.
@@ -2984,11 +2985,11 @@
2985 return 1;
2986 }
2987 nByte = strlen30(zSql);
2988 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2989 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
2990 if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
2991 char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
2992 char cSep = '(';
2993 while( xRead(&sCtx) ){
2994 zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z);
2995 cSep = ',';
@@ -3004,21 +3005,21 @@
3005 zCreate = sqlite3_mprintf("%z\n)", zCreate);
3006 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
3007 sqlite3_free(zCreate);
3008 if( rc ){
3009 fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
3010 sqlite3_errmsg(p->db));
3011 sqlite3_free(sCtx.z);
3012 xCloser(sCtx.in);
3013 return 1;
3014 }
3015 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3016 }
3017 sqlite3_free(zSql);
3018 if( rc ){
3019 if (pStmt) sqlite3_finalize(pStmt);
3020 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
3021 xCloser(sCtx.in);
3022 return 1;
3023 }
3024 nCol = sqlite3_column_count(pStmt);
3025 sqlite3_finalize(pStmt);
@@ -3039,17 +3040,17 @@
3040 zSql[j++] = ')';
3041 zSql[j] = 0;
3042 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3043 sqlite3_free(zSql);
3044 if( rc ){
3045 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
3046 if (pStmt) sqlite3_finalize(pStmt);
3047 xCloser(sCtx.in);
3048 return 1;
3049 }
3050 needCommit = sqlite3_get_autocommit(p->db);
3051 if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
3052 do{
3053 int startLine = sCtx.nLine;
3054 for(i=0; i<nCol; i++){
3055 char *z = xRead(&sCtx);
3056 /*
@@ -3084,19 +3085,19 @@
3085 if( i>=nCol ){
3086 sqlite3_step(pStmt);
3087 rc = sqlite3_reset(pStmt);
3088 if( rc!=SQLITE_OK ){
3089 fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
3090 sqlite3_errmsg(p->db));
3091 }
3092 }
3093 }while( sCtx.cTerm!=EOF );
3094
3095 xCloser(sCtx.in);
3096 sqlite3_free(sCtx.z);
3097 sqlite3_finalize(pStmt);
3098 if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
3099 }else
3100
3101 if( c=='i' && (strncmp(azArg[0], "indices", n)==0
3102 || strncmp(azArg[0], "indexes", n)==0) ){
3103 ShellState data;
@@ -3646,17 +3647,17 @@
3647 sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
3648 }
3649 while( sqlite3_step(pStmt)==SQLITE_ROW ){
3650 if( nRow>=nAlloc ){
3651 char **azNew;
3652 int n2 = nAlloc*2 + 10;
3653 azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n2);
3654 if( azNew==0 ){
3655 fprintf(stderr, "Error: out of memory\n");
3656 break;
3657 }
3658 nAlloc = n2;
3659 azResult = azNew;
3660 }
3661 azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
3662 if( azResult[nRow] ) nRow++;
3663 }
@@ -3705,19 +3706,19 @@
3706 { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
3707 { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
3708 { "imposter", SQLITE_TESTCTRL_IMPOSTER },
3709 };
3710 int testctrl = -1;
3711 int rc2 = 0;
3712 int i, n2;
3713 open_db(p, 0);
3714
3715 /* convert testctrl text option to value. allow any unique prefix
3716 ** of the option name, or a numerical value. */
3717 n2 = strlen30(azArg[1]);
3718 for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
3719 if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
3720 if( testctrl<0 ){
3721 testctrl = aCtrl[i].ctrlCode;
3722 }else{
3723 fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
3724 testctrl = -1;
@@ -3734,12 +3735,12 @@
3735 /* sqlite3_test_control(int, db, int) */
3736 case SQLITE_TESTCTRL_OPTIMIZATIONS:
3737 case SQLITE_TESTCTRL_RESERVE:
3738 if( nArg==3 ){
3739 int opt = (int)strtol(azArg[2], 0, 0);
3740 rc2 = sqlite3_test_control(testctrl, p->db, opt);
3741 fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
3742 } else {
3743 fprintf(stderr,"Error: testctrl %s takes a single int option\n",
3744 azArg[1]);
3745 }
3746 break;
@@ -3748,23 +3749,23 @@
3749 case SQLITE_TESTCTRL_PRNG_SAVE:
3750 case SQLITE_TESTCTRL_PRNG_RESTORE:
3751 case SQLITE_TESTCTRL_PRNG_RESET:
3752 case SQLITE_TESTCTRL_BYTEORDER:
3753 if( nArg==2 ){
3754 rc2 = sqlite3_test_control(testctrl);
3755 fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
3756 } else {
3757 fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
3758 }
3759 break;
3760
3761 /* sqlite3_test_control(int, uint) */
3762 case SQLITE_TESTCTRL_PENDING_BYTE:
3763 if( nArg==3 ){
3764 unsigned int opt = (unsigned int)integerValue(azArg[2]);
3765 rc2 = sqlite3_test_control(testctrl, opt);
3766 fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
3767 } else {
3768 fprintf(stderr,"Error: testctrl %s takes a single unsigned"
3769 " int option\n", azArg[1]);
3770 }
3771 break;
@@ -3773,12 +3774,12 @@
3774 case SQLITE_TESTCTRL_ASSERT:
3775 case SQLITE_TESTCTRL_ALWAYS:
3776 case SQLITE_TESTCTRL_NEVER_CORRUPT:
3777 if( nArg==3 ){
3778 int opt = booleanValue(azArg[2]);
3779 rc2 = sqlite3_test_control(testctrl, opt);
3780 fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
3781 } else {
3782 fprintf(stderr,"Error: testctrl %s takes a single int option\n",
3783 azArg[1]);
3784 }
3785 break;
@@ -3786,26 +3787,26 @@
3787 /* sqlite3_test_control(int, char *) */
3788 #ifdef SQLITE_N_KEYWORD
3789 case SQLITE_TESTCTRL_ISKEYWORD:
3790 if( nArg==3 ){
3791 const char *opt = azArg[2];
3792 rc2 = sqlite3_test_control(testctrl, opt);
3793 fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
3794 } else {
3795 fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
3796 azArg[1]);
3797 }
3798 break;
3799 #endif
3800
3801 case SQLITE_TESTCTRL_IMPOSTER:
3802 if( nArg==5 ){
3803 rc2 = sqlite3_test_control(testctrl, p->db,
3804 azArg[2],
3805 integerValue(azArg[3]),
3806 integerValue(azArg[4]));
3807 fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
3808 }else{
3809 fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
3810 }
3811 break;
3812
@@ -4109,10 +4110,11 @@
4110 }
4111 if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
4112 && sqlite3_complete(zSql) ){
4113 p->cnt = 0;
4114 open_db(p, 0);
4115 if( p->backslashOn ) resolve_backslashes(zSql);
4116 BEGIN_TIMER;
4117 rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
4118 END_TIMER;
4119 if( rc || zErrMsg ){
4120 char zPrefix[100];
@@ -4575,10 +4577,17 @@
4577 data.autoEQP = 1;
4578 }else if( strcmp(z,"-stats")==0 ){
4579 data.statsOn = 1;
4580 }else if( strcmp(z,"-scanstats")==0 ){
4581 data.scanstatsOn = 1;
4582 }else if( strcmp(z,"-backslash")==0 ){
4583 /* Undocumented command-line option: -backslash
4584 ** Causes C-style backslash escapes to be evaluated in SQL statements
4585 ** prior to sending the SQL into SQLite. Useful for injecting
4586 ** crazy bytes in the middle of SQL statements for testing and debugging.
4587 */
4588 data.backslashOn = 1;
4589 }else if( strcmp(z,"-bail")==0 ){
4590 bail_on_error = 1;
4591 }else if( strcmp(z,"-version")==0 ){
4592 printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
4593 return 0;
4594
+10 -1
--- src/shun.c
+++ src/shun.c
@@ -35,10 +35,13 @@
3535
return rc==SQLITE_ROW;
3636
}
3737
3838
/*
3939
** WEBPAGE: shun
40
+**
41
+** View the SHA1 hashes of all shunned artifacts. Add new hashes
42
+** to the shun set. Requires Admin privilege.
4043
*/
4144
void shun_page(void){
4245
Stmt q;
4346
int cnt = 0;
4447
const char *zUuid = P("uuid");
@@ -293,10 +296,15 @@
293296
294297
/*
295298
** WEBPAGE: rcvfromlist
296299
**
297300
** Show a listing of RCVFROM table entries.
301
+**
302
+** The RCVFROM table records where this repository received each
303
+** artifact, including the time of receipt, user, and IP address.
304
+**
305
+** Access requires Admin privilege.
298306
*/
299307
void rcvfromlist_page(void){
300308
int ofst = atoi(PD("ofst","0"));
301309
int showAll = P("all")!=0;
302310
int cnt;
@@ -375,11 +383,12 @@
375383
}
376384
377385
/*
378386
** WEBPAGE: rcvfrom
379387
**
380
-** Show a single RCVFROM table entry.
388
+** Show a single RCVFROM table entry identified by the rcvid= query
389
+** parameters. Requires Admin privilege.
381390
*/
382391
void rcvfrom_page(void){
383392
int rcvid = atoi(PD("rcvid","0"));
384393
Stmt q;
385394
386395
--- src/shun.c
+++ src/shun.c
@@ -35,10 +35,13 @@
35 return rc==SQLITE_ROW;
36 }
37
38 /*
39 ** WEBPAGE: shun
 
 
 
40 */
41 void shun_page(void){
42 Stmt q;
43 int cnt = 0;
44 const char *zUuid = P("uuid");
@@ -293,10 +296,15 @@
293
294 /*
295 ** WEBPAGE: rcvfromlist
296 **
297 ** Show a listing of RCVFROM table entries.
 
 
 
 
 
298 */
299 void rcvfromlist_page(void){
300 int ofst = atoi(PD("ofst","0"));
301 int showAll = P("all")!=0;
302 int cnt;
@@ -375,11 +383,12 @@
375 }
376
377 /*
378 ** WEBPAGE: rcvfrom
379 **
380 ** Show a single RCVFROM table entry.
 
381 */
382 void rcvfrom_page(void){
383 int rcvid = atoi(PD("rcvid","0"));
384 Stmt q;
385
386
--- src/shun.c
+++ src/shun.c
@@ -35,10 +35,13 @@
35 return rc==SQLITE_ROW;
36 }
37
38 /*
39 ** WEBPAGE: shun
40 **
41 ** View the SHA1 hashes of all shunned artifacts. Add new hashes
42 ** to the shun set. Requires Admin privilege.
43 */
44 void shun_page(void){
45 Stmt q;
46 int cnt = 0;
47 const char *zUuid = P("uuid");
@@ -293,10 +296,15 @@
296
297 /*
298 ** WEBPAGE: rcvfromlist
299 **
300 ** Show a listing of RCVFROM table entries.
301 **
302 ** The RCVFROM table records where this repository received each
303 ** artifact, including the time of receipt, user, and IP address.
304 **
305 ** Access requires Admin privilege.
306 */
307 void rcvfromlist_page(void){
308 int ofst = atoi(PD("ofst","0"));
309 int showAll = P("all")!=0;
310 int cnt;
@@ -375,11 +383,12 @@
383 }
384
385 /*
386 ** WEBPAGE: rcvfrom
387 **
388 ** Show a single RCVFROM table entry identified by the rcvid= query
389 ** parameters. Requires Admin privilege.
390 */
391 void rcvfrom_page(void){
392 int rcvid = atoi(PD("rcvid","0"));
393 Stmt q;
394
395
+102 -62
--- src/sitemap.c
+++ src/sitemap.c
@@ -22,93 +22,133 @@
2222
#include <assert.h>
2323
2424
/*
2525
** WEBPAGE: sitemap
2626
**
27
-** Show an incomplete list of web pages offered by the Fossil web engine.
27
+** List some of the web pages offered by the Fossil web engine. This
28
+** page is intended as a suppliment to the menu bar on the main screen.
29
+** That is, this page is designed to hold links that are omitted from
30
+** the main menu due to lack of space.
2831
*/
2932
void sitemap_page(void){
33
+ int srchFlags;
3034
login_check_credentials();
35
+ srchFlags = search_restrict(SRCH_ALL);
3136
style_header("Site Map");
3237
style_adunit_config(ADUNIT_RIGHT_OK);
38
+#if 0
3339
@ <p>
3440
@ The following links are just a few of the many web-pages available for
3541
@ this Fossil repository:
3642
@ </p>
3743
@
44
+#endif
3845
@ <ul>
3946
@ <li>%z(href("%R/home"))Home Page</a>
40
- @ <ul>
41
- @ <li>%z(href("%R/docsrc"))Search Project Documentation</a></li>
42
- @ </ul></li>
43
- @ <li>%z(href("%R/tree"))File Browser</a></li>
44
- @ <ul>
45
- @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
46
- @ Trunk Check-in</a></li>
47
- @ <li>%z(href("%R/tree?type=flat"))Flat-view</a></li>
48
- @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li>
49
- @ </ul>
50
- @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li>
51
- @ <ul>
52
- @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
53
- @ check-ins</a></li>
54
- @ <li>%z(href("%R/timeline?n=all&namechng"))All check-ins with file name
55
- @ changes</a></li>
56
- @ <li>%z(href("%R/reports"))Activity Reports</a></li>
57
- @ </ul>
58
- @ <li>%z(href("%R/brlist"))Branches</a></li>
59
- @ <ul>
60
- @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li>
61
- @ <li>%z(href("%R/taglist"))List of Tags</a></li>
62
- @ </ul>
63
- @ </li>
64
- @ <li>%z(href("%R/wikihelp"))Wiki</a>
65
- @ <ul>
66
- @ <li>%z(href("%R/wikisrch"))Wiki Search</a></li>
67
- @ <li>%z(href("%R/wcontent"))List of Wiki Pages</a></li>
68
- @ <li>%z(href("%R/timeline?y=w"))Recent activity</a></li>
69
- @ <li>%z(href("%R/wiki_rules"))Wiki Formatting Rules</a></li>
70
- @ <li>%z(href("%R/md_rules"))Markdown Formatting Rules</a></li>
71
- @ <li>%z(href("%R/wiki?name=Sandbox"))Sandbox</a></li>
72
- @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
73
- @ </ul>
74
- @ </li>
75
- @ <li>%z(href("%R/reportlist"))Tickets</a>
76
- @ <ul>
77
- @ <li>%z(href("%R/tktsrch"))Ticket Search</a></li>
78
- @ <li>%z(href("%R/timeline?y=t"))Recent activity</a></li>
79
- @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
80
- @ </ul>
81
- @ </li>
82
- @ <li>%z(href("%R/search"))Full-Text Search</a></li>
83
- @ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
84
- @ <li>%z(href("%R/stat"))Repository Status</a>
85
- @ <ul>
86
- @ <li>%z(href("%R/hash-collisions"))Collisions on SHA1 hash
87
- @ prefixes</a></li>
88
- @ <li>%z(href("%R/urllist"))List of URLs used to access
89
- @ this repository</a></li>
90
- @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
91
- @ </ul></li>
47
+ if( srchFlags & SRCH_DOC ){
48
+ @ <ul>
49
+ @ <li>%z(href("%R/docsrch"))Search Project Documentation</a></li>
50
+ @ </ul>
51
+ }
52
+ @ </li>
53
+ if( g.perm.Read ){
54
+ @ <li>%z(href("%R/tree"))File Browser</a></li>
55
+ @ <ul>
56
+ @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
57
+ @ Trunk Check-in</a></li>
58
+ @ <li>%z(href("%R/tree?type=flat"))Flat-view</a></li>
59
+ @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li>
60
+ @ </ul>
61
+ }
62
+ if( g.perm.Read ){
63
+ @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li>
64
+ @ <ul>
65
+ @ <li>%z(href("%R/reports"))Activity Reports</a></li>
66
+ @ <li>%z(href("%R/timeline?n=all&namechng"))File name changes</a></li>
67
+ @ <li>%z(href("%R/timeline?n=all&forks"))Forks</a></li>
68
+ @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
69
+ @ check-ins</a></li>
70
+ @ </ul>
71
+ }
72
+ if( g.perm.Read ){
73
+ @ <li>%z(href("%R/brlist"))Branches</a></li>
74
+ @ <ul>
75
+ @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li>
76
+ @ <li>%z(href("%R/taglist"))List of Tags</a></li>
77
+ @ </ul>
78
+ @ </li>
79
+ }
80
+ if( g.perm.RdWiki ){
81
+ @ <li>%z(href("%R/wikihelp"))Wiki</a>
82
+ @ <ul>
83
+ if( srchFlags & SRCH_WIKI ){
84
+ @ <li>%z(href("%R/wikisrch"))Wiki Search</a></li>
85
+ }
86
+ @ <li>%z(href("%R/wcontent"))List of Wiki Pages</a></li>
87
+ @ <li>%z(href("%R/timeline?y=w"))Recent activity</a></li>
88
+ @ <li>%z(href("%R/wiki_rules"))Wiki Formatting Rules</a></li>
89
+ @ <li>%z(href("%R/md_rules"))Markdown Formatting Rules</a></li>
90
+ @ <li>%z(href("%R/wiki?name=Sandbox"))Sandbox</a></li>
91
+ @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
92
+ @ </ul>
93
+ @ </li>
94
+ }
95
+ if( g.perm.RdTkt ){
96
+ @ <li>%z(href("%R/reportlist"))Tickets</a>
97
+ @ <ul>
98
+ if( srchFlags & SRCH_TKT ){
99
+ @ <li>%z(href("%R/tktsrch"))Ticket Search</a></li>
100
+ }
101
+ @ <li>%z(href("%R/timeline?y=t"))Recent activity</a></li>
102
+ @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
103
+ @ </ul>
104
+ @ </li>
105
+ }
106
+ if( srchFlags ){
107
+ @ <li>%z(href("%R/search"))Full-Text Search</a></li>
108
+ }
109
+ @ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
110
+ if( g.perm.Read ){
111
+ @ <li>%z(href("%R/stat"))Repository Status</a>
112
+ @ <ul>
113
+ @ <li>%z(href("%R/hash-collisions"))Collisions on SHA1 hash
114
+ @ prefixes</a></li>
115
+ if( g.perm.Admin ){
116
+ @ <li>%z(href("%R/urllist"))List of URLs used to access
117
+ @ this repository</a></li>
118
+ }
119
+ @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
120
+ @ </ul>
121
+ @ </li>
122
+ }
92123
@ <li>On-line Documentation
93124
@ <ul>
94125
@ <li>%z(href("%R/help"))List of All Commands and Web Pages</a></li>
95126
@ <li>%z(href("%R/test-all-help"))All "help" text on a single page</a></li>
96127
@ <li>%z(href("%R/mimetype_list"))Filename suffix to mimetype map</a></li>
97128
@ </ul></li>
98
- @ <li>%z(href("%R/setup"))Administration Pages</a>
99
- @ <ul>
100
- @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
101
- @ <li>%z(href("%R/admin_log"))Admin log</a></li>
102
- @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
103
- @ </ul></li>
129
+ if( g.perm.Admin ){
130
+ @ <li>%z(href("%R/setup"))Administration Pages</a>
131
+ @ <ul>
132
+ @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
133
+ @ <li>%z(href("%R/admin_log"))Admin log</a></li>
134
+ @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
135
+ @ </ul></li>
136
+ }
104137
@ <li>Test Pages
105138
@ <ul>
106
- @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
107
- @ <li>%z(href("%R/test_timewarps"))List of "Timewarp" Check-ins</a></li>
108
- @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
139
+ if( g.perm.Admin || db_get_boolean("test_env_enable",0) ){
140
+ @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
141
+ }
142
+ if( g.perm.Read && g.perm.Hyperlink ){
143
+ @ <li>%z(href("%R/test_timewarps"))List of "Timewarp" Check-ins</a></li>
144
+ }
145
+ if( g.perm.Read ){
146
+ @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
147
+ }
109148
@ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
110149
@ colors assigned to branch names</a>
150
+ @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</li>
111151
@ </ul></li>
112152
@ </ul></li>
113153
style_footer();
114154
}
115155
--- src/sitemap.c
+++ src/sitemap.c
@@ -22,93 +22,133 @@
22 #include <assert.h>
23
24 /*
25 ** WEBPAGE: sitemap
26 **
27 ** Show an incomplete list of web pages offered by the Fossil web engine.
 
 
 
28 */
29 void sitemap_page(void){
 
30 login_check_credentials();
 
31 style_header("Site Map");
32 style_adunit_config(ADUNIT_RIGHT_OK);
 
33 @ <p>
34 @ The following links are just a few of the many web-pages available for
35 @ this Fossil repository:
36 @ </p>
37 @
 
38 @ <ul>
39 @ <li>%z(href("%R/home"))Home Page</a>
40 @ <ul>
41 @ <li>%z(href("%R/docsrc"))Search Project Documentation</a></li>
42 @ </ul></li>
43 @ <li>%z(href("%R/tree"))File Browser</a></li>
44 @ <ul>
45 @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
46 @ Trunk Check-in</a></li>
47 @ <li>%z(href("%R/tree?type=flat"))Flat-view</a></li>
48 @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li>
49 @ </ul>
50 @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li>
51 @ <ul>
52 @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
53 @ check-ins</a></li>
54 @ <li>%z(href("%R/timeline?n=all&namechng"))All check-ins with file name
55 @ changes</a></li>
56 @ <li>%z(href("%R/reports"))Activity Reports</a></li>
57 @ </ul>
58 @ <li>%z(href("%R/brlist"))Branches</a></li>
59 @ <ul>
60 @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li>
61 @ <li>%z(href("%R/taglist"))List of Tags</a></li>
62 @ </ul>
63 @ </li>
64 @ <li>%z(href("%R/wikihelp"))Wiki</a>
65 @ <ul>
66 @ <li>%z(href("%R/wikisrch"))Wiki Search</a></li>
67 @ <li>%z(href("%R/wcontent"))List of Wiki Pages</a></li>
68 @ <li>%z(href("%R/timeline?y=w"))Recent activity</a></li>
69 @ <li>%z(href("%R/wiki_rules"))Wiki Formatting Rules</a></li>
70 @ <li>%z(href("%R/md_rules"))Markdown Formatting Rules</a></li>
71 @ <li>%z(href("%R/wiki?name=Sandbox"))Sandbox</a></li>
72 @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
73 @ </ul>
74 @ </li>
75 @ <li>%z(href("%R/reportlist"))Tickets</a>
76 @ <ul>
77 @ <li>%z(href("%R/tktsrch"))Ticket Search</a></li>
78 @ <li>%z(href("%R/timeline?y=t"))Recent activity</a></li>
79 @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
80 @ </ul>
81 @ </li>
82 @ <li>%z(href("%R/search"))Full-Text Search</a></li>
83 @ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
84 @ <li>%z(href("%R/stat"))Repository Status</a>
85 @ <ul>
86 @ <li>%z(href("%R/hash-collisions"))Collisions on SHA1 hash
87 @ prefixes</a></li>
88 @ <li>%z(href("%R/urllist"))List of URLs used to access
89 @ this repository</a></li>
90 @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
91 @ </ul></li>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92 @ <li>On-line Documentation
93 @ <ul>
94 @ <li>%z(href("%R/help"))List of All Commands and Web Pages</a></li>
95 @ <li>%z(href("%R/test-all-help"))All "help" text on a single page</a></li>
96 @ <li>%z(href("%R/mimetype_list"))Filename suffix to mimetype map</a></li>
97 @ </ul></li>
98 @ <li>%z(href("%R/setup"))Administration Pages</a>
99 @ <ul>
100 @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
101 @ <li>%z(href("%R/admin_log"))Admin log</a></li>
102 @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
103 @ </ul></li>
 
 
104 @ <li>Test Pages
105 @ <ul>
106 @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
107 @ <li>%z(href("%R/test_timewarps"))List of "Timewarp" Check-ins</a></li>
108 @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
 
 
 
 
 
 
109 @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
110 @ colors assigned to branch names</a>
 
111 @ </ul></li>
112 @ </ul></li>
113 style_footer();
114 }
115
--- src/sitemap.c
+++ src/sitemap.c
@@ -22,93 +22,133 @@
22 #include <assert.h>
23
24 /*
25 ** WEBPAGE: sitemap
26 **
27 ** List some of the web pages offered by the Fossil web engine. This
28 ** page is intended as a suppliment to the menu bar on the main screen.
29 ** That is, this page is designed to hold links that are omitted from
30 ** the main menu due to lack of space.
31 */
32 void sitemap_page(void){
33 int srchFlags;
34 login_check_credentials();
35 srchFlags = search_restrict(SRCH_ALL);
36 style_header("Site Map");
37 style_adunit_config(ADUNIT_RIGHT_OK);
38 #if 0
39 @ <p>
40 @ The following links are just a few of the many web-pages available for
41 @ this Fossil repository:
42 @ </p>
43 @
44 #endif
45 @ <ul>
46 @ <li>%z(href("%R/home"))Home Page</a>
47 if( srchFlags & SRCH_DOC ){
48 @ <ul>
49 @ <li>%z(href("%R/docsrch"))Search Project Documentation</a></li>
50 @ </ul>
51 }
52 @ </li>
53 if( g.perm.Read ){
54 @ <li>%z(href("%R/tree"))File Browser</a></li>
55 @ <ul>
56 @ <li>%z(href("%R/tree?type=tree&ci=trunk"))Tree-view,
57 @ Trunk Check-in</a></li>
58 @ <li>%z(href("%R/tree?type=flat"))Flat-view</a></li>
59 @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li>
60 @ </ul>
61 }
62 if( g.perm.Read ){
63 @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li>
64 @ <ul>
65 @ <li>%z(href("%R/reports"))Activity Reports</a></li>
66 @ <li>%z(href("%R/timeline?n=all&namechng"))File name changes</a></li>
67 @ <li>%z(href("%R/timeline?n=all&forks"))Forks</a></li>
68 @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10
69 @ check-ins</a></li>
70 @ </ul>
71 }
72 if( g.perm.Read ){
73 @ <li>%z(href("%R/brlist"))Branches</a></li>
74 @ <ul>
75 @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li>
76 @ <li>%z(href("%R/taglist"))List of Tags</a></li>
77 @ </ul>
78 @ </li>
79 }
80 if( g.perm.RdWiki ){
81 @ <li>%z(href("%R/wikihelp"))Wiki</a>
82 @ <ul>
83 if( srchFlags & SRCH_WIKI ){
84 @ <li>%z(href("%R/wikisrch"))Wiki Search</a></li>
85 }
86 @ <li>%z(href("%R/wcontent"))List of Wiki Pages</a></li>
87 @ <li>%z(href("%R/timeline?y=w"))Recent activity</a></li>
88 @ <li>%z(href("%R/wiki_rules"))Wiki Formatting Rules</a></li>
89 @ <li>%z(href("%R/md_rules"))Markdown Formatting Rules</a></li>
90 @ <li>%z(href("%R/wiki?name=Sandbox"))Sandbox</a></li>
91 @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
92 @ </ul>
93 @ </li>
94 }
95 if( g.perm.RdTkt ){
96 @ <li>%z(href("%R/reportlist"))Tickets</a>
97 @ <ul>
98 if( srchFlags & SRCH_TKT ){
99 @ <li>%z(href("%R/tktsrch"))Ticket Search</a></li>
100 }
101 @ <li>%z(href("%R/timeline?y=t"))Recent activity</a></li>
102 @ <li>%z(href("%R/attachlist"))List of Attachments</a></li>
103 @ </ul>
104 @ </li>
105 }
106 if( srchFlags ){
107 @ <li>%z(href("%R/search"))Full-Text Search</a></li>
108 }
109 @ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
110 if( g.perm.Read ){
111 @ <li>%z(href("%R/stat"))Repository Status</a>
112 @ <ul>
113 @ <li>%z(href("%R/hash-collisions"))Collisions on SHA1 hash
114 @ prefixes</a></li>
115 if( g.perm.Admin ){
116 @ <li>%z(href("%R/urllist"))List of URLs used to access
117 @ this repository</a></li>
118 }
119 @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
120 @ </ul>
121 @ </li>
122 }
123 @ <li>On-line Documentation
124 @ <ul>
125 @ <li>%z(href("%R/help"))List of All Commands and Web Pages</a></li>
126 @ <li>%z(href("%R/test-all-help"))All "help" text on a single page</a></li>
127 @ <li>%z(href("%R/mimetype_list"))Filename suffix to mimetype map</a></li>
128 @ </ul></li>
129 if( g.perm.Admin ){
130 @ <li>%z(href("%R/setup"))Administration Pages</a>
131 @ <ul>
132 @ <li>%z(href("%R/modreq"))Pending Moderation Requests</a></li>
133 @ <li>%z(href("%R/admin_log"))Admin log</a></li>
134 @ <li>%z(href("%R/cachestat"))Status of the web-page cache</a></li>
135 @ </ul></li>
136 }
137 @ <li>Test Pages
138 @ <ul>
139 if( g.perm.Admin || db_get_boolean("test_env_enable",0) ){
140 @ <li>%z(href("%R/test_env"))CGI Environment Test</a></li>
141 }
142 if( g.perm.Read && g.perm.Hyperlink ){
143 @ <li>%z(href("%R/test_timewarps"))List of "Timewarp" Check-ins</a></li>
144 }
145 if( g.perm.Read ){
146 @ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
147 }
148 @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
149 @ colors assigned to branch names</a>
150 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</li>
151 @ </ul></li>
152 @ </ul></li>
153 style_footer();
154 }
155
+7 -1
--- src/skins.c
+++ src/skins.c
@@ -407,10 +407,13 @@
407407
return 0;
408408
}
409409
410410
/*
411411
** WEBPAGE: setup_skin
412
+**
413
+** Show a list of available skins with buttons for selecting which
414
+** skin to use. Requires Admin privilege.
412415
*/
413416
void setup_skin(void){
414417
const char *z;
415418
char *zName;
416419
char *zErr = 0;
@@ -565,10 +568,13 @@
565568
}
566569
567570
568571
/*
569572
** WEBPAGE: setup_skinedit
573
+**
574
+** Edit aspects of a skin determined by the w= query parameter.
575
+** Requires Admin privileges.
570576
**
571577
** w=N -- 0=CSS, 1=footer, 2=header, 3=details
572578
*/
573579
void setup_skinedit(void){
574580
static const struct sSkinAddr {
@@ -602,11 +608,11 @@
602608
cgi_replace_parameter(aSkinAttr[ii].zFile, builtin_text(zDflt));
603609
}
604610
style_header("%s", aSkinAttr[ii].zTitle);
605611
for(j=0; j<ArraySize(aSkinAttr); j++){
606612
if( j==ii ) continue;
607
- style_submenu_element(aSkinAttr[j].zSubmenu, 0,
613
+ style_submenu_element(aSkinAttr[j].zSubmenu, 0,
608614
"%R/setup_skinedit?w=%d&basis=%h",j,zBasis);
609615
}
610616
style_submenu_element("Skins", 0, "%R/setup_skin");
611617
@ <form action="%s(g.zTop)/setup_skinedit" method="post"><div>
612618
login_insert_csrf_secret();
613619
--- src/skins.c
+++ src/skins.c
@@ -407,10 +407,13 @@
407 return 0;
408 }
409
410 /*
411 ** WEBPAGE: setup_skin
 
 
 
412 */
413 void setup_skin(void){
414 const char *z;
415 char *zName;
416 char *zErr = 0;
@@ -565,10 +568,13 @@
565 }
566
567
568 /*
569 ** WEBPAGE: setup_skinedit
 
 
 
570 **
571 ** w=N -- 0=CSS, 1=footer, 2=header, 3=details
572 */
573 void setup_skinedit(void){
574 static const struct sSkinAddr {
@@ -602,11 +608,11 @@
602 cgi_replace_parameter(aSkinAttr[ii].zFile, builtin_text(zDflt));
603 }
604 style_header("%s", aSkinAttr[ii].zTitle);
605 for(j=0; j<ArraySize(aSkinAttr); j++){
606 if( j==ii ) continue;
607 style_submenu_element(aSkinAttr[j].zSubmenu, 0,
608 "%R/setup_skinedit?w=%d&basis=%h",j,zBasis);
609 }
610 style_submenu_element("Skins", 0, "%R/setup_skin");
611 @ <form action="%s(g.zTop)/setup_skinedit" method="post"><div>
612 login_insert_csrf_secret();
613
--- src/skins.c
+++ src/skins.c
@@ -407,10 +407,13 @@
407 return 0;
408 }
409
410 /*
411 ** WEBPAGE: setup_skin
412 **
413 ** Show a list of available skins with buttons for selecting which
414 ** skin to use. Requires Admin privilege.
415 */
416 void setup_skin(void){
417 const char *z;
418 char *zName;
419 char *zErr = 0;
@@ -565,10 +568,13 @@
568 }
569
570
571 /*
572 ** WEBPAGE: setup_skinedit
573 **
574 ** Edit aspects of a skin determined by the w= query parameter.
575 ** Requires Admin privileges.
576 **
577 ** w=N -- 0=CSS, 1=footer, 2=header, 3=details
578 */
579 void setup_skinedit(void){
580 static const struct sSkinAddr {
@@ -602,11 +608,11 @@
608 cgi_replace_parameter(aSkinAttr[ii].zFile, builtin_text(zDflt));
609 }
610 style_header("%s", aSkinAttr[ii].zTitle);
611 for(j=0; j<ArraySize(aSkinAttr); j++){
612 if( j==ii ) continue;
613 style_submenu_element(aSkinAttr[j].zSubmenu, 0,
614 "%R/setup_skinedit?w=%d&basis=%h",j,zBasis);
615 }
616 style_submenu_element("Skins", 0, "%R/setup_skin");
617 @ <form action="%s(g.zTop)/setup_skinedit" method="post"><div>
618 login_insert_csrf_secret();
619
+9 -2
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -66,21 +66,27 @@
6666
){
6767
const unsigned char *pIn;
6868
unsigned char *pOut;
6969
unsigned int nIn;
7070
unsigned long int nOut;
71
+ int rc;
7172
7273
pIn = sqlite3_value_blob(argv[0]);
7374
nIn = sqlite3_value_bytes(argv[0]);
7475
nOut = 13 + nIn + (nIn+999)/1000;
7576
pOut = sqlite3_malloc( nOut+4 );
7677
pOut[0] = nIn>>24 & 0xff;
7778
pOut[1] = nIn>>16 & 0xff;
7879
pOut[2] = nIn>>8 & 0xff;
7980
pOut[3] = nIn & 0xff;
80
- compress(&pOut[4], &nOut, pIn, nIn);
81
- sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
81
+ rc = compress(&pOut[4], &nOut, pIn, nIn);
82
+ if( rc==Z_OK ){
83
+ sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
84
+ }else{
85
+ sqlite3_free(pOut);
86
+ sqlite3_result_error(context, "input cannot be zlib compressed", -1);
87
+ }
8288
}
8389
8490
/*
8591
** Implementation of the "decompress(X)" SQL function. The argument X
8692
** is a blob which was obtained from compress(Y). The output will be
@@ -103,10 +109,11 @@
103109
pOut = sqlite3_malloc( nOut+1 );
104110
rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
105111
if( rc==Z_OK ){
106112
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
107113
}else{
114
+ sqlite3_free(pOut);
108115
sqlite3_result_error(context, "input is not zlib compressed", -1);
109116
}
110117
}
111118
112119
/*
113120
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -66,21 +66,27 @@
66 ){
67 const unsigned char *pIn;
68 unsigned char *pOut;
69 unsigned int nIn;
70 unsigned long int nOut;
 
71
72 pIn = sqlite3_value_blob(argv[0]);
73 nIn = sqlite3_value_bytes(argv[0]);
74 nOut = 13 + nIn + (nIn+999)/1000;
75 pOut = sqlite3_malloc( nOut+4 );
76 pOut[0] = nIn>>24 & 0xff;
77 pOut[1] = nIn>>16 & 0xff;
78 pOut[2] = nIn>>8 & 0xff;
79 pOut[3] = nIn & 0xff;
80 compress(&pOut[4], &nOut, pIn, nIn);
81 sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
 
 
 
 
 
82 }
83
84 /*
85 ** Implementation of the "decompress(X)" SQL function. The argument X
86 ** is a blob which was obtained from compress(Y). The output will be
@@ -103,10 +109,11 @@
103 pOut = sqlite3_malloc( nOut+1 );
104 rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
105 if( rc==Z_OK ){
106 sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
107 }else{
 
108 sqlite3_result_error(context, "input is not zlib compressed", -1);
109 }
110 }
111
112 /*
113
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -66,21 +66,27 @@
66 ){
67 const unsigned char *pIn;
68 unsigned char *pOut;
69 unsigned int nIn;
70 unsigned long int nOut;
71 int rc;
72
73 pIn = sqlite3_value_blob(argv[0]);
74 nIn = sqlite3_value_bytes(argv[0]);
75 nOut = 13 + nIn + (nIn+999)/1000;
76 pOut = sqlite3_malloc( nOut+4 );
77 pOut[0] = nIn>>24 & 0xff;
78 pOut[1] = nIn>>16 & 0xff;
79 pOut[2] = nIn>>8 & 0xff;
80 pOut[3] = nIn & 0xff;
81 rc = compress(&pOut[4], &nOut, pIn, nIn);
82 if( rc==Z_OK ){
83 sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
84 }else{
85 sqlite3_free(pOut);
86 sqlite3_result_error(context, "input cannot be zlib compressed", -1);
87 }
88 }
89
90 /*
91 ** Implementation of the "decompress(X)" SQL function. The argument X
92 ** is a blob which was obtained from compress(Y). The output will be
@@ -103,10 +109,11 @@
109 pOut = sqlite3_malloc( nOut+1 );
110 rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
111 if( rc==Z_OK ){
112 sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
113 }else{
114 sqlite3_free(pOut);
115 sqlite3_result_error(context, "input is not zlib compressed", -1);
116 }
117 }
118
119 /*
120
+6 -2
--- src/style.c
+++ src/style.c
@@ -1360,10 +1360,12 @@
13601360
}
13611361
13621362
13631363
/*
13641364
** WEBPAGE: style.css
1365
+**
1366
+** Return the style sheet.
13651367
*/
13661368
void page_style_css(void){
13671369
Blob css;
13681370
int i;
13691371
@@ -1395,10 +1397,13 @@
13951397
g.isConst = 1;
13961398
}
13971399
13981400
/*
13991401
** WEBPAGE: test_env
1402
+**
1403
+** Display CGI-variables and other aspects of the run-time
1404
+** environment, for debugging and trouble-shooting purposes.
14001405
*/
14011406
void page_test_env(void){
14021407
char c;
14031408
int i;
14041409
int showAll;
@@ -1466,13 +1471,12 @@
14661471
style_footer();
14671472
if( g.perm.Admin && P("err") ) fossil_fatal("%s", P("err"));
14681473
}
14691474
14701475
/*
1471
-** This page is a honeypot for spiders and bots.
1472
-**
14731476
** WEBPAGE: honeypot
1477
+** This page is a honeypot for spiders and bots.
14741478
*/
14751479
void honeypot_page(void){
14761480
cgi_set_status(403, "Forbidden");
14771481
@ <p>Please enable javascript or log in to see this content</p>
14781482
}
14791483
--- src/style.c
+++ src/style.c
@@ -1360,10 +1360,12 @@
1360 }
1361
1362
1363 /*
1364 ** WEBPAGE: style.css
 
 
1365 */
1366 void page_style_css(void){
1367 Blob css;
1368 int i;
1369
@@ -1395,10 +1397,13 @@
1395 g.isConst = 1;
1396 }
1397
1398 /*
1399 ** WEBPAGE: test_env
 
 
 
1400 */
1401 void page_test_env(void){
1402 char c;
1403 int i;
1404 int showAll;
@@ -1466,13 +1471,12 @@
1466 style_footer();
1467 if( g.perm.Admin && P("err") ) fossil_fatal("%s", P("err"));
1468 }
1469
1470 /*
1471 ** This page is a honeypot for spiders and bots.
1472 **
1473 ** WEBPAGE: honeypot
 
1474 */
1475 void honeypot_page(void){
1476 cgi_set_status(403, "Forbidden");
1477 @ <p>Please enable javascript or log in to see this content</p>
1478 }
1479
--- src/style.c
+++ src/style.c
@@ -1360,10 +1360,12 @@
1360 }
1361
1362
1363 /*
1364 ** WEBPAGE: style.css
1365 **
1366 ** Return the style sheet.
1367 */
1368 void page_style_css(void){
1369 Blob css;
1370 int i;
1371
@@ -1395,10 +1397,13 @@
1397 g.isConst = 1;
1398 }
1399
1400 /*
1401 ** WEBPAGE: test_env
1402 **
1403 ** Display CGI-variables and other aspects of the run-time
1404 ** environment, for debugging and trouble-shooting purposes.
1405 */
1406 void page_test_env(void){
1407 char c;
1408 int i;
1409 int showAll;
@@ -1466,13 +1471,12 @@
1471 style_footer();
1472 if( g.perm.Admin && P("err") ) fossil_fatal("%s", P("err"));
1473 }
1474
1475 /*
 
 
1476 ** WEBPAGE: honeypot
1477 ** This page is a honeypot for spiders and bots.
1478 */
1479 void honeypot_page(void){
1480 cgi_set_status(403, "Forbidden");
1481 @ <p>Please enable javascript or log in to see this content</p>
1482 }
1483
+5
--- src/tag.c
+++ src/tag.c
@@ -536,10 +536,12 @@
536536
usage("add|cancel|find|list ...");
537537
}
538538
539539
/*
540540
** WEBPAGE: taglist
541
+**
542
+** List all non-propagating symbolic tags.
541543
*/
542544
void taglist_page(void){
543545
Stmt q;
544546
545547
login_check_credentials();
@@ -575,10 +577,13 @@
575577
style_footer();
576578
}
577579
578580
/*
579581
** WEBPAGE: /tagtimeline
582
+**
583
+** Render a timeline with all check-ins that contain non-propagating
584
+** symbolic tags.
580585
*/
581586
void tagtimeline_page(void){
582587
Stmt q;
583588
584589
login_check_credentials();
585590
--- src/tag.c
+++ src/tag.c
@@ -536,10 +536,12 @@
536 usage("add|cancel|find|list ...");
537 }
538
539 /*
540 ** WEBPAGE: taglist
 
 
541 */
542 void taglist_page(void){
543 Stmt q;
544
545 login_check_credentials();
@@ -575,10 +577,13 @@
575 style_footer();
576 }
577
578 /*
579 ** WEBPAGE: /tagtimeline
 
 
 
580 */
581 void tagtimeline_page(void){
582 Stmt q;
583
584 login_check_credentials();
585
--- src/tag.c
+++ src/tag.c
@@ -536,10 +536,12 @@
536 usage("add|cancel|find|list ...");
537 }
538
539 /*
540 ** WEBPAGE: taglist
541 **
542 ** List all non-propagating symbolic tags.
543 */
544 void taglist_page(void){
545 Stmt q;
546
547 login_check_credentials();
@@ -575,10 +577,13 @@
577 style_footer();
578 }
579
580 /*
581 ** WEBPAGE: /tagtimeline
582 **
583 ** Render a timeline with all check-ins that contain non-propagating
584 ** symbolic tags.
585 */
586 void tagtimeline_page(void){
587 Stmt q;
588
589 login_check_credentials();
590
+37 -2
--- src/timeline.c
+++ src/timeline.c
@@ -163,11 +163,10 @@
163163
void test_hash_color_page(void){
164164
const char *zBr;
165165
char zNm[10];
166166
int i, cnt;
167167
login_check_credentials();
168
- if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
169168
170169
style_header("Hash Color Test");
171170
for(i=cnt=0; i<10; i++){
172171
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
173172
zBr = P(zNm);
@@ -270,10 +269,11 @@
270269
int tagid = db_column_int(pQuery, 9);
271270
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
272271
const char *zBr = 0; /* Branch */
273272
int commentColumn = 3; /* Column containing comment text */
274273
int modPending; /* Pending moderation */
274
+ char *zDateLink; /* URL for the link on the timestamp */
275275
char zTime[20];
276276
277277
if( zDate==0 ){
278278
zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */
279279
}
@@ -351,11 +351,12 @@
351351
}else if( rid==vid ){
352352
@ <tr class="timelineCurrent">
353353
}else {
354354
@ <tr>
355355
}
356
- @ <td class="timelineTime">%s(zTime)</td>
356
+ zDateLink = href("%R/timeline?c=%!S&unhide", zUuid);
357
+ @ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td>
357358
@ <td class="timelineGraph">
358359
if( tmFlags & TIMELINE_UCOLOR ) zBgClr = zUser ? hash_color(zUser) : 0;
359360
if( zType[0]=='c'
360361
&& (pGraph || zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0)
361362
){
@@ -1215,10 +1216,11 @@
12151216
** shortest ... show only the shortest path
12161217
** uf=FUUID Show only check-ins that use given file version
12171218
** brbg Background color from branch name
12181219
** ubg Background color from user
12191220
** namechng Show only check-ins that filename changes
1221
+** forks Show only forks and their children
12201222
** ym=YYYY-MM Shown only events for the given year/month.
12211223
** datefmt=N Override the date format
12221224
**
12231225
** p= and d= can appear individually or together. If either p= or d=
12241226
** appear, then u=, y=, a=, and b= are ignored.
@@ -1248,10 +1250,11 @@
12481250
const char *zUses = P("uf"); /* Only show check-ins hold this file */
12491251
const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */
12501252
const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */
12511253
int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
12521254
int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */
1255
+ int forkOnly = PB("forks"); /* Show only forks and their children */
12531256
int tagid; /* Tag ID */
12541257
int tmFlags = 0; /* Timeline flags */
12551258
const char *zThisTag = 0; /* Suppress links to this tag */
12561259
const char *zThisUser = 0; /* Suppress links to this user */
12571260
HQuery url; /* URL for various branch links */
@@ -1354,10 +1357,30 @@
13541357
"CREATE TEMP TABLE rnfile(rid INTEGER PRIMARY KEY);"
13551358
"INSERT OR IGNORE INTO rnfile"
13561359
" SELECT mid FROM mlink WHERE pfnid>0 AND pfnid!=fnid;"
13571360
);
13581361
disableY = 1;
1362
+ }
1363
+ if( forkOnly ){
1364
+ db_multi_exec(
1365
+ "CREATE TEMP TABLE rnfork(rid INTEGER PRIMARY KEY);\n"
1366
+ "INSERT OR IGNORE INTO rnfork(rid)\n"
1367
+ " SELECT pid FROM plink\n"
1368
+ " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=cid)=="
1369
+ " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n"
1370
+ " GROUP BY pid"
1371
+ " HAVING count(*)>1;\n"
1372
+ "INSERT OR IGNORE INTO rnfork(rid)"
1373
+ " SELECT cid FROM plink\n"
1374
+ " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=cid)=="
1375
+ " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n"
1376
+ " AND pid IN rnfork;",
1377
+ TAG_BRANCH, TAG_BRANCH, TAG_BRANCH, TAG_BRANCH
1378
+ );
1379
+ tmFlags |= TIMELINE_UNHIDE;
1380
+ zType = "ci";
1381
+ disableY = 1;
13591382
}
13601383
13611384
style_header("Timeline");
13621385
login_anonymous_available();
13631386
timeline_temp_table();
@@ -1484,10 +1507,13 @@
14841507
blob_append_sql(&sql, " AND event.objid IN usesfile ");
14851508
}
14861509
if( renameOnly ){
14871510
blob_append_sql(&sql, " AND event.objid IN rnfile ");
14881511
}
1512
+ if( forkOnly ){
1513
+ blob_append_sql(&sql, " AND event.objid IN rnfork ");
1514
+ }
14891515
if( zYearMonth ){
14901516
blob_append_sql(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
14911517
zYearMonth);
14921518
}
14931519
else if( zYearWeek ){
@@ -1656,10 +1682,14 @@
16561682
}
16571683
if( renameOnly ){
16581684
blob_appendf(&desc, " that contain filename changes");
16591685
tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
16601686
}
1687
+ if( forkOnly ){
1688
+ blob_appendf(&desc, " associated with forks");
1689
+ tmFlags |= TIMELINE_DISJOINT;
1690
+ }
16611691
if( zUser ){
16621692
blob_appendf(&desc, " by user %h", zUser);
16631693
tmFlags |= TIMELINE_DISJOINT;
16641694
}
16651695
if( zTagName ){
@@ -2204,10 +2234,15 @@
22042234
db_finalize(&q);
22052235
}
22062236
22072237
/*
22082238
** WEBPAGE: test_timewarps
2239
+**
2240
+** Show all check-ins that are "timewarps". A timewarp is a
2241
+** check-in that occurs before its parent, according to the
2242
+** timestamp information on the check-in. This can only actually
2243
+** happen, of course, if a users system clock is set incorrectly.
22092244
*/
22102245
void test_timewarp_page(void){
22112246
Stmt q;
22122247
22132248
login_check_credentials();
22142249
--- src/timeline.c
+++ src/timeline.c
@@ -163,11 +163,10 @@
163 void test_hash_color_page(void){
164 const char *zBr;
165 char zNm[10];
166 int i, cnt;
167 login_check_credentials();
168 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
169
170 style_header("Hash Color Test");
171 for(i=cnt=0; i<10; i++){
172 sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
173 zBr = P(zNm);
@@ -270,10 +269,11 @@
270 int tagid = db_column_int(pQuery, 9);
271 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
272 const char *zBr = 0; /* Branch */
273 int commentColumn = 3; /* Column containing comment text */
274 int modPending; /* Pending moderation */
 
275 char zTime[20];
276
277 if( zDate==0 ){
278 zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */
279 }
@@ -351,11 +351,12 @@
351 }else if( rid==vid ){
352 @ <tr class="timelineCurrent">
353 }else {
354 @ <tr>
355 }
356 @ <td class="timelineTime">%s(zTime)</td>
 
357 @ <td class="timelineGraph">
358 if( tmFlags & TIMELINE_UCOLOR ) zBgClr = zUser ? hash_color(zUser) : 0;
359 if( zType[0]=='c'
360 && (pGraph || zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0)
361 ){
@@ -1215,10 +1216,11 @@
1215 ** shortest ... show only the shortest path
1216 ** uf=FUUID Show only check-ins that use given file version
1217 ** brbg Background color from branch name
1218 ** ubg Background color from user
1219 ** namechng Show only check-ins that filename changes
 
1220 ** ym=YYYY-MM Shown only events for the given year/month.
1221 ** datefmt=N Override the date format
1222 **
1223 ** p= and d= can appear individually or together. If either p= or d=
1224 ** appear, then u=, y=, a=, and b= are ignored.
@@ -1248,10 +1250,11 @@
1248 const char *zUses = P("uf"); /* Only show check-ins hold this file */
1249 const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */
1250 const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */
1251 int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
1252 int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */
 
1253 int tagid; /* Tag ID */
1254 int tmFlags = 0; /* Timeline flags */
1255 const char *zThisTag = 0; /* Suppress links to this tag */
1256 const char *zThisUser = 0; /* Suppress links to this user */
1257 HQuery url; /* URL for various branch links */
@@ -1354,10 +1357,30 @@
1354 "CREATE TEMP TABLE rnfile(rid INTEGER PRIMARY KEY);"
1355 "INSERT OR IGNORE INTO rnfile"
1356 " SELECT mid FROM mlink WHERE pfnid>0 AND pfnid!=fnid;"
1357 );
1358 disableY = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1359 }
1360
1361 style_header("Timeline");
1362 login_anonymous_available();
1363 timeline_temp_table();
@@ -1484,10 +1507,13 @@
1484 blob_append_sql(&sql, " AND event.objid IN usesfile ");
1485 }
1486 if( renameOnly ){
1487 blob_append_sql(&sql, " AND event.objid IN rnfile ");
1488 }
 
 
 
1489 if( zYearMonth ){
1490 blob_append_sql(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
1491 zYearMonth);
1492 }
1493 else if( zYearWeek ){
@@ -1656,10 +1682,14 @@
1656 }
1657 if( renameOnly ){
1658 blob_appendf(&desc, " that contain filename changes");
1659 tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
1660 }
 
 
 
 
1661 if( zUser ){
1662 blob_appendf(&desc, " by user %h", zUser);
1663 tmFlags |= TIMELINE_DISJOINT;
1664 }
1665 if( zTagName ){
@@ -2204,10 +2234,15 @@
2204 db_finalize(&q);
2205 }
2206
2207 /*
2208 ** WEBPAGE: test_timewarps
 
 
 
 
 
2209 */
2210 void test_timewarp_page(void){
2211 Stmt q;
2212
2213 login_check_credentials();
2214
--- src/timeline.c
+++ src/timeline.c
@@ -163,11 +163,10 @@
163 void test_hash_color_page(void){
164 const char *zBr;
165 char zNm[10];
166 int i, cnt;
167 login_check_credentials();
 
168
169 style_header("Hash Color Test");
170 for(i=cnt=0; i<10; i++){
171 sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
172 zBr = P(zNm);
@@ -270,10 +269,11 @@
269 int tagid = db_column_int(pQuery, 9);
270 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
271 const char *zBr = 0; /* Branch */
272 int commentColumn = 3; /* Column containing comment text */
273 int modPending; /* Pending moderation */
274 char *zDateLink; /* URL for the link on the timestamp */
275 char zTime[20];
276
277 if( zDate==0 ){
278 zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */
279 }
@@ -351,11 +351,12 @@
351 }else if( rid==vid ){
352 @ <tr class="timelineCurrent">
353 }else {
354 @ <tr>
355 }
356 zDateLink = href("%R/timeline?c=%!S&unhide", zUuid);
357 @ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td>
358 @ <td class="timelineGraph">
359 if( tmFlags & TIMELINE_UCOLOR ) zBgClr = zUser ? hash_color(zUser) : 0;
360 if( zType[0]=='c'
361 && (pGraph || zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0)
362 ){
@@ -1215,10 +1216,11 @@
1216 ** shortest ... show only the shortest path
1217 ** uf=FUUID Show only check-ins that use given file version
1218 ** brbg Background color from branch name
1219 ** ubg Background color from user
1220 ** namechng Show only check-ins that filename changes
1221 ** forks Show only forks and their children
1222 ** ym=YYYY-MM Shown only events for the given year/month.
1223 ** datefmt=N Override the date format
1224 **
1225 ** p= and d= can appear individually or together. If either p= or d=
1226 ** appear, then u=, y=, a=, and b= are ignored.
@@ -1248,10 +1250,11 @@
1250 const char *zUses = P("uf"); /* Only show check-ins hold this file */
1251 const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */
1252 const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */
1253 int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
1254 int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */
1255 int forkOnly = PB("forks"); /* Show only forks and their children */
1256 int tagid; /* Tag ID */
1257 int tmFlags = 0; /* Timeline flags */
1258 const char *zThisTag = 0; /* Suppress links to this tag */
1259 const char *zThisUser = 0; /* Suppress links to this user */
1260 HQuery url; /* URL for various branch links */
@@ -1354,10 +1357,30 @@
1357 "CREATE TEMP TABLE rnfile(rid INTEGER PRIMARY KEY);"
1358 "INSERT OR IGNORE INTO rnfile"
1359 " SELECT mid FROM mlink WHERE pfnid>0 AND pfnid!=fnid;"
1360 );
1361 disableY = 1;
1362 }
1363 if( forkOnly ){
1364 db_multi_exec(
1365 "CREATE TEMP TABLE rnfork(rid INTEGER PRIMARY KEY);\n"
1366 "INSERT OR IGNORE INTO rnfork(rid)\n"
1367 " SELECT pid FROM plink\n"
1368 " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=cid)=="
1369 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n"
1370 " GROUP BY pid"
1371 " HAVING count(*)>1;\n"
1372 "INSERT OR IGNORE INTO rnfork(rid)"
1373 " SELECT cid FROM plink\n"
1374 " WHERE (SELECT value FROM tagxref WHERE tagid=%d AND rid=cid)=="
1375 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=pid)\n"
1376 " AND pid IN rnfork;",
1377 TAG_BRANCH, TAG_BRANCH, TAG_BRANCH, TAG_BRANCH
1378 );
1379 tmFlags |= TIMELINE_UNHIDE;
1380 zType = "ci";
1381 disableY = 1;
1382 }
1383
1384 style_header("Timeline");
1385 login_anonymous_available();
1386 timeline_temp_table();
@@ -1484,10 +1507,13 @@
1507 blob_append_sql(&sql, " AND event.objid IN usesfile ");
1508 }
1509 if( renameOnly ){
1510 blob_append_sql(&sql, " AND event.objid IN rnfile ");
1511 }
1512 if( forkOnly ){
1513 blob_append_sql(&sql, " AND event.objid IN rnfork ");
1514 }
1515 if( zYearMonth ){
1516 blob_append_sql(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
1517 zYearMonth);
1518 }
1519 else if( zYearWeek ){
@@ -1656,10 +1682,14 @@
1682 }
1683 if( renameOnly ){
1684 blob_appendf(&desc, " that contain filename changes");
1685 tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
1686 }
1687 if( forkOnly ){
1688 blob_appendf(&desc, " associated with forks");
1689 tmFlags |= TIMELINE_DISJOINT;
1690 }
1691 if( zUser ){
1692 blob_appendf(&desc, " by user %h", zUser);
1693 tmFlags |= TIMELINE_DISJOINT;
1694 }
1695 if( zTagName ){
@@ -2204,10 +2234,15 @@
2234 db_finalize(&q);
2235 }
2236
2237 /*
2238 ** WEBPAGE: test_timewarps
2239 **
2240 ** Show all check-ins that are "timewarps". A timewarp is a
2241 ** check-in that occurs before its parent, according to the
2242 ** timestamp information on the check-in. This can only actually
2243 ** happen, of course, if a users system clock is set incorrectly.
2244 */
2245 void test_timewarp_page(void){
2246 Stmt q;
2247
2248 login_check_credentials();
2249
+1 -1
--- src/tkt.c
+++ src/tkt.c
@@ -441,11 +441,11 @@
441441
442442
/*
443443
** WEBPAGE: tktview
444444
** URL: tktview?name=UUID
445445
**
446
-** View a ticket.
446
+** View a ticket identified by the name= query parameter.
447447
*/
448448
void tktview_page(void){
449449
const char *zScript;
450450
char *zFullName;
451451
const char *zUuid = PD("name","");
452452
--- src/tkt.c
+++ src/tkt.c
@@ -441,11 +441,11 @@
441
442 /*
443 ** WEBPAGE: tktview
444 ** URL: tktview?name=UUID
445 **
446 ** View a ticket.
447 */
448 void tktview_page(void){
449 const char *zScript;
450 char *zFullName;
451 const char *zUuid = PD("name","");
452
--- src/tkt.c
+++ src/tkt.c
@@ -441,11 +441,11 @@
441
442 /*
443 ** WEBPAGE: tktview
444 ** URL: tktview?name=UUID
445 **
446 ** View a ticket identified by the name= query parameter.
447 */
448 void tktview_page(void){
449 const char *zScript;
450 char *zFullName;
451 const char *zUuid = PD("name","");
452
+24 -1
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -21,12 +21,12 @@
2121
#include "config.h"
2222
#include "tktsetup.h"
2323
#include <assert.h>
2424
2525
/*
26
-** Main sub-menu for configuring the ticketing system.
2726
** WEBPAGE: tktsetup
27
+** Main sub-menu for configuring the ticketing system.
2828
*/
2929
void tktsetup_page(void){
3030
login_check_credentials();
3131
if( !g.perm.Setup ){
3232
login_needed(0);
@@ -167,10 +167,12 @@
167167
style_footer();
168168
}
169169
170170
/*
171171
** WEBPAGE: tktsetup_tab
172
+** Administrative page for defining the "ticket" table used
173
+** to hold ticket information.
172174
*/
173175
void tktsetup_tab_page(void){
174176
static const char zDesc[] =
175177
@ Enter a valid CREATE TABLE statement for the "ticket" table. The
176178
@ table must contain columns named "tkt_id", "tkt_uuid", and "tkt_mtime"
@@ -243,10 +245,12 @@
243245
return db_get("ticket-common", (char*)zDefaultTicketCommon);
244246
}
245247
246248
/*
247249
** WEBPAGE: tktsetup_com
250
+** Administrative page used to define TH1 script that is
251
+** common to all ticket screens.
248252
*/
249253
void tktsetup_com_page(void){
250254
static const char zDesc[] =
251255
@ Enter TH1 script that initializes variables prior to generating
252256
@ any of the ticket view, edit, or creation pages.
@@ -273,10 +277,12 @@
273277
return db_get("ticket-change", (char*)zDefaultTicketChange);
274278
}
275279
276280
/*
277281
** WEBPAGE: tktsetup_change
282
+** Adminstrative screen used to view or edit the TH1 script
283
+** that shows ticket changes.
278284
*/
279285
void tktsetup_change_page(void){
280286
static const char zDesc[] =
281287
@ Enter TH1 script that runs after processing the ticket editing
282288
@ and creation pages.
@@ -416,10 +422,12 @@
416422
return db_get("ticket-newpage", (char*)zDefaultNew);
417423
}
418424
419425
/*
420426
** WEBPAGE: tktsetup_newpage
427
+** Administrative page used to view or edit the TH1 script used
428
+** to enter new tickets.
421429
*/
422430
void tktsetup_newpage_page(void){
423431
static const char zDesc[] =
424432
@ Enter HTML with embedded TH1 script that will render the "new ticket"
425433
@ page
@@ -555,10 +563,12 @@
555563
return db_get("ticket-viewpage", (char*)zDefaultView);
556564
}
557565
558566
/*
559567
** WEBPAGE: tktsetup_viewpage
568
+** Administrative page used to view or edit the TH1 script that
569
+** displays individual tickets.
560570
*/
561571
void tktsetup_viewpage_page(void){
562572
static const char zDesc[] =
563573
@ Enter HTML with embedded TH1 script that will render the "view ticket" page
564574
;
@@ -694,10 +704,12 @@
694704
return db_get("ticket-editpage", (char*)zDefaultEdit);
695705
}
696706
697707
/*
698708
** WEBPAGE: tktsetup_editpage
709
+** Administrative page for viewing or editing the TH1 script that
710
+** drives the ticket editing page.
699711
*/
700712
void tktsetup_editpage_page(void){
701713
static const char zDesc[] =
702714
@ Enter HTML with embedded TH1 script that will render the "edit ticket" page
703715
;
@@ -748,10 +760,12 @@
748760
return db_get("ticket-reportlist", (char*)zDefaultReportList);
749761
}
750762
751763
/*
752764
** WEBPAGE: tktsetup_reportlist
765
+** Administrative page used to view or edit the TH1 script that
766
+** defines the "report list" page.
753767
*/
754768
void tktsetup_reportlist(void){
755769
static const char zDesc[] =
756770
@ Enter HTML with embedded TH1 script that will render the "report list" page
757771
;
@@ -795,10 +809,13 @@
795809
return db_get("ticket-report-template", zDefaultReport);
796810
}
797811
798812
/*
799813
** WEBPAGE: tktsetup_rpttplt
814
+**
815
+** Administrative page used to view or edit the ticket report
816
+** template.
800817
*/
801818
void tktsetup_rpttplt_page(void){
802819
static const char zDesc[] =
803820
@ Enter the default ticket report format template. This is the
804821
@ template report format that initially appears when creating a
@@ -836,10 +853,13 @@
836853
return db_get("ticket-key-template", (char*)zDefaultKey);
837854
}
838855
839856
/*
840857
** WEBPAGE: tktsetup_keytplt
858
+**
859
+** Administrative page used to view or edit the Key template
860
+** for tickets.
841861
*/
842862
void tktsetup_keytplt_page(void){
843863
static const char zDesc[] =
844864
@ Enter the default ticket report color-key template. This is the
845865
@ the color-key that initially appears when creating a
@@ -856,10 +876,13 @@
856876
);
857877
}
858878
859879
/*
860880
** WEBPAGE: tktsetup_timeline
881
+**
882
+** Administrative page used ot configure how tickets are
883
+** rendered on timeline views.
861884
*/
862885
void tktsetup_timeline_page(void){
863886
login_check_credentials();
864887
if( !g.perm.Setup ){
865888
login_needed(0);
866889
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -21,12 +21,12 @@
21 #include "config.h"
22 #include "tktsetup.h"
23 #include <assert.h>
24
25 /*
26 ** Main sub-menu for configuring the ticketing system.
27 ** WEBPAGE: tktsetup
 
28 */
29 void tktsetup_page(void){
30 login_check_credentials();
31 if( !g.perm.Setup ){
32 login_needed(0);
@@ -167,10 +167,12 @@
167 style_footer();
168 }
169
170 /*
171 ** WEBPAGE: tktsetup_tab
 
 
172 */
173 void tktsetup_tab_page(void){
174 static const char zDesc[] =
175 @ Enter a valid CREATE TABLE statement for the "ticket" table. The
176 @ table must contain columns named "tkt_id", "tkt_uuid", and "tkt_mtime"
@@ -243,10 +245,12 @@
243 return db_get("ticket-common", (char*)zDefaultTicketCommon);
244 }
245
246 /*
247 ** WEBPAGE: tktsetup_com
 
 
248 */
249 void tktsetup_com_page(void){
250 static const char zDesc[] =
251 @ Enter TH1 script that initializes variables prior to generating
252 @ any of the ticket view, edit, or creation pages.
@@ -273,10 +277,12 @@
273 return db_get("ticket-change", (char*)zDefaultTicketChange);
274 }
275
276 /*
277 ** WEBPAGE: tktsetup_change
 
 
278 */
279 void tktsetup_change_page(void){
280 static const char zDesc[] =
281 @ Enter TH1 script that runs after processing the ticket editing
282 @ and creation pages.
@@ -416,10 +422,12 @@
416 return db_get("ticket-newpage", (char*)zDefaultNew);
417 }
418
419 /*
420 ** WEBPAGE: tktsetup_newpage
 
 
421 */
422 void tktsetup_newpage_page(void){
423 static const char zDesc[] =
424 @ Enter HTML with embedded TH1 script that will render the "new ticket"
425 @ page
@@ -555,10 +563,12 @@
555 return db_get("ticket-viewpage", (char*)zDefaultView);
556 }
557
558 /*
559 ** WEBPAGE: tktsetup_viewpage
 
 
560 */
561 void tktsetup_viewpage_page(void){
562 static const char zDesc[] =
563 @ Enter HTML with embedded TH1 script that will render the "view ticket" page
564 ;
@@ -694,10 +704,12 @@
694 return db_get("ticket-editpage", (char*)zDefaultEdit);
695 }
696
697 /*
698 ** WEBPAGE: tktsetup_editpage
 
 
699 */
700 void tktsetup_editpage_page(void){
701 static const char zDesc[] =
702 @ Enter HTML with embedded TH1 script that will render the "edit ticket" page
703 ;
@@ -748,10 +760,12 @@
748 return db_get("ticket-reportlist", (char*)zDefaultReportList);
749 }
750
751 /*
752 ** WEBPAGE: tktsetup_reportlist
 
 
753 */
754 void tktsetup_reportlist(void){
755 static const char zDesc[] =
756 @ Enter HTML with embedded TH1 script that will render the "report list" page
757 ;
@@ -795,10 +809,13 @@
795 return db_get("ticket-report-template", zDefaultReport);
796 }
797
798 /*
799 ** WEBPAGE: tktsetup_rpttplt
 
 
 
800 */
801 void tktsetup_rpttplt_page(void){
802 static const char zDesc[] =
803 @ Enter the default ticket report format template. This is the
804 @ template report format that initially appears when creating a
@@ -836,10 +853,13 @@
836 return db_get("ticket-key-template", (char*)zDefaultKey);
837 }
838
839 /*
840 ** WEBPAGE: tktsetup_keytplt
 
 
 
841 */
842 void tktsetup_keytplt_page(void){
843 static const char zDesc[] =
844 @ Enter the default ticket report color-key template. This is the
845 @ the color-key that initially appears when creating a
@@ -856,10 +876,13 @@
856 );
857 }
858
859 /*
860 ** WEBPAGE: tktsetup_timeline
 
 
 
861 */
862 void tktsetup_timeline_page(void){
863 login_check_credentials();
864 if( !g.perm.Setup ){
865 login_needed(0);
866
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -21,12 +21,12 @@
21 #include "config.h"
22 #include "tktsetup.h"
23 #include <assert.h>
24
25 /*
 
26 ** WEBPAGE: tktsetup
27 ** Main sub-menu for configuring the ticketing system.
28 */
29 void tktsetup_page(void){
30 login_check_credentials();
31 if( !g.perm.Setup ){
32 login_needed(0);
@@ -167,10 +167,12 @@
167 style_footer();
168 }
169
170 /*
171 ** WEBPAGE: tktsetup_tab
172 ** Administrative page for defining the "ticket" table used
173 ** to hold ticket information.
174 */
175 void tktsetup_tab_page(void){
176 static const char zDesc[] =
177 @ Enter a valid CREATE TABLE statement for the "ticket" table. The
178 @ table must contain columns named "tkt_id", "tkt_uuid", and "tkt_mtime"
@@ -243,10 +245,12 @@
245 return db_get("ticket-common", (char*)zDefaultTicketCommon);
246 }
247
248 /*
249 ** WEBPAGE: tktsetup_com
250 ** Administrative page used to define TH1 script that is
251 ** common to all ticket screens.
252 */
253 void tktsetup_com_page(void){
254 static const char zDesc[] =
255 @ Enter TH1 script that initializes variables prior to generating
256 @ any of the ticket view, edit, or creation pages.
@@ -273,10 +277,12 @@
277 return db_get("ticket-change", (char*)zDefaultTicketChange);
278 }
279
280 /*
281 ** WEBPAGE: tktsetup_change
282 ** Adminstrative screen used to view or edit the TH1 script
283 ** that shows ticket changes.
284 */
285 void tktsetup_change_page(void){
286 static const char zDesc[] =
287 @ Enter TH1 script that runs after processing the ticket editing
288 @ and creation pages.
@@ -416,10 +422,12 @@
422 return db_get("ticket-newpage", (char*)zDefaultNew);
423 }
424
425 /*
426 ** WEBPAGE: tktsetup_newpage
427 ** Administrative page used to view or edit the TH1 script used
428 ** to enter new tickets.
429 */
430 void tktsetup_newpage_page(void){
431 static const char zDesc[] =
432 @ Enter HTML with embedded TH1 script that will render the "new ticket"
433 @ page
@@ -555,10 +563,12 @@
563 return db_get("ticket-viewpage", (char*)zDefaultView);
564 }
565
566 /*
567 ** WEBPAGE: tktsetup_viewpage
568 ** Administrative page used to view or edit the TH1 script that
569 ** displays individual tickets.
570 */
571 void tktsetup_viewpage_page(void){
572 static const char zDesc[] =
573 @ Enter HTML with embedded TH1 script that will render the "view ticket" page
574 ;
@@ -694,10 +704,12 @@
704 return db_get("ticket-editpage", (char*)zDefaultEdit);
705 }
706
707 /*
708 ** WEBPAGE: tktsetup_editpage
709 ** Administrative page for viewing or editing the TH1 script that
710 ** drives the ticket editing page.
711 */
712 void tktsetup_editpage_page(void){
713 static const char zDesc[] =
714 @ Enter HTML with embedded TH1 script that will render the "edit ticket" page
715 ;
@@ -748,10 +760,12 @@
760 return db_get("ticket-reportlist", (char*)zDefaultReportList);
761 }
762
763 /*
764 ** WEBPAGE: tktsetup_reportlist
765 ** Administrative page used to view or edit the TH1 script that
766 ** defines the "report list" page.
767 */
768 void tktsetup_reportlist(void){
769 static const char zDesc[] =
770 @ Enter HTML with embedded TH1 script that will render the "report list" page
771 ;
@@ -795,10 +809,13 @@
809 return db_get("ticket-report-template", zDefaultReport);
810 }
811
812 /*
813 ** WEBPAGE: tktsetup_rpttplt
814 **
815 ** Administrative page used to view or edit the ticket report
816 ** template.
817 */
818 void tktsetup_rpttplt_page(void){
819 static const char zDesc[] =
820 @ Enter the default ticket report format template. This is the
821 @ template report format that initially appears when creating a
@@ -836,10 +853,13 @@
853 return db_get("ticket-key-template", (char*)zDefaultKey);
854 }
855
856 /*
857 ** WEBPAGE: tktsetup_keytplt
858 **
859 ** Administrative page used to view or edit the Key template
860 ** for tickets.
861 */
862 void tktsetup_keytplt_page(void){
863 static const char zDesc[] =
864 @ Enter the default ticket report color-key template. This is the
865 @ the color-key that initially appears when creating a
@@ -856,10 +876,13 @@
876 );
877 }
878
879 /*
880 ** WEBPAGE: tktsetup_timeline
881 **
882 ** Administrative page used ot configure how tickets are
883 ** rendered on timeline views.
884 */
885 void tktsetup_timeline_page(void){
886 login_check_credentials();
887 if( !g.perm.Setup ){
888 login_needed(0);
889
+3 -4
--- src/update.c
+++ src/update.c
@@ -175,14 +175,12 @@
175175
** target as if VERSION were omitted and the --latest flag is present.
176176
*/
177177
latestFlag = 1;
178178
}else{
179179
tid = name_to_typed_rid(g.argv[2],"ci");
180
- if( tid==0 ){
181
- fossil_fatal("no such version: %s", g.argv[2]);
182
- }else if( !is_a_version(tid) ){
183
- fossil_fatal("no such version: %s", g.argv[2]);
180
+ if( tid==0 || !is_a_version(tid) ){
181
+ fossil_fatal("no such check-in: %s", g.argv[2]);
184182
}
185183
}
186184
}
187185
188186
/* If no VERSION is specified on the command-line, then look for a
@@ -544,10 +542,11 @@
544542
fossil_warning("uncommitted %s against %S.",
545543
zLabel, db_column_text(&q, 0));
546544
nMerge++;
547545
}
548546
db_finalize(&q);
547
+ leaf_ambiguity_warning(tid, tid);
549548
550549
if( nConflict ){
551550
if( internalUpdate ){
552551
internalConflictCnt = nConflict;
553552
nConflict = 0;
554553
--- src/update.c
+++ src/update.c
@@ -175,14 +175,12 @@
175 ** target as if VERSION were omitted and the --latest flag is present.
176 */
177 latestFlag = 1;
178 }else{
179 tid = name_to_typed_rid(g.argv[2],"ci");
180 if( tid==0 ){
181 fossil_fatal("no such version: %s", g.argv[2]);
182 }else if( !is_a_version(tid) ){
183 fossil_fatal("no such version: %s", g.argv[2]);
184 }
185 }
186 }
187
188 /* If no VERSION is specified on the command-line, then look for a
@@ -544,10 +542,11 @@
544 fossil_warning("uncommitted %s against %S.",
545 zLabel, db_column_text(&q, 0));
546 nMerge++;
547 }
548 db_finalize(&q);
 
549
550 if( nConflict ){
551 if( internalUpdate ){
552 internalConflictCnt = nConflict;
553 nConflict = 0;
554
--- src/update.c
+++ src/update.c
@@ -175,14 +175,12 @@
175 ** target as if VERSION were omitted and the --latest flag is present.
176 */
177 latestFlag = 1;
178 }else{
179 tid = name_to_typed_rid(g.argv[2],"ci");
180 if( tid==0 || !is_a_version(tid) ){
181 fossil_fatal("no such check-in: %s", g.argv[2]);
 
 
182 }
183 }
184 }
185
186 /* If no VERSION is specified on the command-line, then look for a
@@ -544,10 +542,11 @@
542 fossil_warning("uncommitted %s against %S.",
543 zLabel, db_column_text(&q, 0));
544 nMerge++;
545 }
546 db_finalize(&q);
547 leaf_ambiguity_warning(tid, tid);
548
549 if( nConflict ){
550 if( internalUpdate ){
551 internalConflictCnt = nConflict;
552 nConflict = 0;
553
+9 -4
--- src/user.c
+++ src/user.c
@@ -410,17 +410,22 @@
410410
}
411411
412412
/*
413413
** WEBPAGE: access_log
414414
**
415
-** y=N 1: success only. 2: failure only. 3: both
416
-** n=N Number of entries to show
417
-** o=N Skip this many entries
415
+** Show login attempts, including timestamp and IP address.
416
+** Requires Admin privileges.
417
+**
418
+** Query parameters:
419
+**
420
+** y=N 1: success only. 2: failure only. 3: both (default: 3)
421
+** n=N Number of entries to show (default: 200)
422
+** o=N Skip this many entries (default: 0)
418423
*/
419424
void access_log_page(void){
420425
int y = atoi(PD("y","3"));
421
- int n = atoi(PD("n","50"));
426
+ int n = atoi(PD("n","200"));
422427
int skip = atoi(PD("o","0"));
423428
Blob sql;
424429
Stmt q;
425430
int cnt = 0;
426431
int rc;
427432
--- src/user.c
+++ src/user.c
@@ -410,17 +410,22 @@
410 }
411
412 /*
413 ** WEBPAGE: access_log
414 **
415 ** y=N 1: success only. 2: failure only. 3: both
416 ** n=N Number of entries to show
417 ** o=N Skip this many entries
 
 
 
 
 
418 */
419 void access_log_page(void){
420 int y = atoi(PD("y","3"));
421 int n = atoi(PD("n","50"));
422 int skip = atoi(PD("o","0"));
423 Blob sql;
424 Stmt q;
425 int cnt = 0;
426 int rc;
427
--- src/user.c
+++ src/user.c
@@ -410,17 +410,22 @@
410 }
411
412 /*
413 ** WEBPAGE: access_log
414 **
415 ** Show login attempts, including timestamp and IP address.
416 ** Requires Admin privileges.
417 **
418 ** Query parameters:
419 **
420 ** y=N 1: success only. 2: failure only. 3: both (default: 3)
421 ** n=N Number of entries to show (default: 200)
422 ** o=N Skip this many entries (default: 0)
423 */
424 void access_log_page(void){
425 int y = atoi(PD("y","3"));
426 int n = atoi(PD("n","200"));
427 int skip = atoi(PD("o","0"));
428 Blob sql;
429 Stmt q;
430 int cnt = 0;
431 int rc;
432
+1 -1
--- src/utf8.c
+++ src/utf8.c
@@ -323,11 +323,11 @@
323323
}
324324
325325
/* If blob to be written to the Windows console is not
326326
* UTF-8, convert it to UTF-8 first.
327327
*/
328
- blob_init(&blob, zUtf8, nByte);
328
+ blob_init(&blob, zUtf8, nByte);
329329
blob_to_utf8_no_bom(&blob, 1);
330330
nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
331331
blob_size(&blob), NULL, 0);
332332
zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
333333
if( zUnicode==0 ){
334334
--- src/utf8.c
+++ src/utf8.c
@@ -323,11 +323,11 @@
323 }
324
325 /* If blob to be written to the Windows console is not
326 * UTF-8, convert it to UTF-8 first.
327 */
328 blob_init(&blob, zUtf8, nByte);
329 blob_to_utf8_no_bom(&blob, 1);
330 nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
331 blob_size(&blob), NULL, 0);
332 zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
333 if( zUnicode==0 ){
334
--- src/utf8.c
+++ src/utf8.c
@@ -323,11 +323,11 @@
323 }
324
325 /* If blob to be written to the Windows console is not
326 * UTF-8, convert it to UTF-8 first.
327 */
328 blob_init(&blob, zUtf8, nByte);
329 blob_to_utf8_no_bom(&blob, 1);
330 nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
331 blob_size(&blob), NULL, 0);
332 zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
333 if( zUnicode==0 ){
334
--- src/vfile.c
+++ src/vfile.c
@@ -916,10 +916,15 @@
916916
md5sum_finish(pOut);
917917
}
918918
919919
/*
920920
** COMMAND: test-agg-cksum
921
+**
922
+** Display the aggregate checksum for content computed in several
923
+** different ways. The aggregate checksum is used during "fossil commit"
924
+** to double-check that the information about to be committed to the
925
+** repository exactly matches the information currently in the check-out.
921926
*/
922927
void test_agg_cksum_cmd(void){
923928
int vid;
924929
Blob hash, hash2;
925930
db_must_be_within_tree();
926931
--- src/vfile.c
+++ src/vfile.c
@@ -916,10 +916,15 @@
916 md5sum_finish(pOut);
917 }
918
919 /*
920 ** COMMAND: test-agg-cksum
 
 
 
 
 
921 */
922 void test_agg_cksum_cmd(void){
923 int vid;
924 Blob hash, hash2;
925 db_must_be_within_tree();
926
--- src/vfile.c
+++ src/vfile.c
@@ -916,10 +916,15 @@
916 md5sum_finish(pOut);
917 }
918
919 /*
920 ** COMMAND: test-agg-cksum
921 **
922 ** Display the aggregate checksum for content computed in several
923 ** different ways. The aggregate checksum is used during "fossil commit"
924 ** to double-check that the information about to be committed to the
925 ** repository exactly matches the information currently in the check-out.
926 */
927 void test_agg_cksum_cmd(void){
928 int vid;
929 Blob hash, hash2;
930 db_must_be_within_tree();
931
+9
--- src/wiki.c
+++ src/wiki.c
@@ -76,10 +76,13 @@
7676
7777
/*
7878
** WEBPAGE: home
7979
** WEBPAGE: index
8080
** WEBPAGE: not_found
81
+**
82
+** The /home, /index, and /not_found pages all redirect to the homepage
83
+** configured by the administrator.
8184
*/
8285
void home_page(void){
8386
char *zPageName = db_get("project-name",0);
8487
char *zIndexPage = db_get("index-page",0);
8588
login_check_credentials();
@@ -458,10 +461,12 @@
458461
}
459462
460463
/*
461464
** WEBPAGE: wikiedit
462465
** URL: /wikiedit?name=PAGENAME
466
+**
467
+** Edit a wiki page.
463468
*/
464469
void wikiedit_page(void){
465470
char *zTag;
466471
int rid = 0;
467472
int isSandbox;
@@ -704,10 +709,12 @@
704709
}
705710
706711
/*
707712
** WEBPAGE: wikiappend
708713
** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE
714
+**
715
+** Append text to the end of a wiki page.
709716
*/
710717
void wikiappend_page(void){
711718
char *zTag;
712719
int rid = 0;
713720
int isSandbox;
@@ -995,10 +1002,12 @@
9951002
style_footer();
9961003
}
9971004
9981005
/*
9991006
** WEBPAGE: wiki_rules
1007
+**
1008
+** Show the formatting rules for Fossil wiki.
10001009
*/
10011010
void wikirules_page(void){
10021011
style_header("Wiki Formatting Rules");
10031012
@ <h2>Formatting Rule Summary</h2>
10041013
@ <ol>
10051014
--- src/wiki.c
+++ src/wiki.c
@@ -76,10 +76,13 @@
76
77 /*
78 ** WEBPAGE: home
79 ** WEBPAGE: index
80 ** WEBPAGE: not_found
 
 
 
81 */
82 void home_page(void){
83 char *zPageName = db_get("project-name",0);
84 char *zIndexPage = db_get("index-page",0);
85 login_check_credentials();
@@ -458,10 +461,12 @@
458 }
459
460 /*
461 ** WEBPAGE: wikiedit
462 ** URL: /wikiedit?name=PAGENAME
 
 
463 */
464 void wikiedit_page(void){
465 char *zTag;
466 int rid = 0;
467 int isSandbox;
@@ -704,10 +709,12 @@
704 }
705
706 /*
707 ** WEBPAGE: wikiappend
708 ** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE
 
 
709 */
710 void wikiappend_page(void){
711 char *zTag;
712 int rid = 0;
713 int isSandbox;
@@ -995,10 +1002,12 @@
995 style_footer();
996 }
997
998 /*
999 ** WEBPAGE: wiki_rules
 
 
1000 */
1001 void wikirules_page(void){
1002 style_header("Wiki Formatting Rules");
1003 @ <h2>Formatting Rule Summary</h2>
1004 @ <ol>
1005
--- src/wiki.c
+++ src/wiki.c
@@ -76,10 +76,13 @@
76
77 /*
78 ** WEBPAGE: home
79 ** WEBPAGE: index
80 ** WEBPAGE: not_found
81 **
82 ** The /home, /index, and /not_found pages all redirect to the homepage
83 ** configured by the administrator.
84 */
85 void home_page(void){
86 char *zPageName = db_get("project-name",0);
87 char *zIndexPage = db_get("index-page",0);
88 login_check_credentials();
@@ -458,10 +461,12 @@
461 }
462
463 /*
464 ** WEBPAGE: wikiedit
465 ** URL: /wikiedit?name=PAGENAME
466 **
467 ** Edit a wiki page.
468 */
469 void wikiedit_page(void){
470 char *zTag;
471 int rid = 0;
472 int isSandbox;
@@ -704,10 +709,12 @@
709 }
710
711 /*
712 ** WEBPAGE: wikiappend
713 ** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE
714 **
715 ** Append text to the end of a wiki page.
716 */
717 void wikiappend_page(void){
718 char *zTag;
719 int rid = 0;
720 int isSandbox;
@@ -995,10 +1002,12 @@
1002 style_footer();
1003 }
1004
1005 /*
1006 ** WEBPAGE: wiki_rules
1007 **
1008 ** Show the formatting rules for Fossil wiki.
1009 */
1010 void wikirules_page(void){
1011 style_header("Wiki Formatting Rules");
1012 @ <h2>Formatting Rule Summary</h2>
1013 @ <ol>
1014
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2094,10 +2094,13 @@
20942094
if( iCur ) blob_append(pOut, "\n", 1);
20952095
}
20962096
20972097
/*
20982098
** COMMAND: test-html-tidy
2099
+**
2100
+** Run the htmlTidy() routine on the content of all files named on
2101
+** the command-line and write the results to standard output.
20992102
*/
21002103
void test_html_tidy(void){
21012104
Blob in, out;
21022105
int i;
21032106
@@ -2212,10 +2215,19 @@
22122215
if( nNL==0 ) blob_append(pOut, "\n", 1);
22132216
}
22142217
22152218
/*
22162219
** COMMAND: test-html-to-text
2220
+**
2221
+** Usage: %fossil test-html-to-text FILE ...
2222
+**
2223
+** Read all files named on the command-line. Convert the file
2224
+** content from HTML to text and write the results on standard
2225
+** output.
2226
+**
2227
+** This command is intended as a test and debug interface for
2228
+** the html_to_plaintext() routine.
22172229
*/
22182230
void test_html_to_text(void){
22192231
Blob in, out;
22202232
int i;
22212233
22222234
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2094,10 +2094,13 @@
2094 if( iCur ) blob_append(pOut, "\n", 1);
2095 }
2096
2097 /*
2098 ** COMMAND: test-html-tidy
 
 
 
2099 */
2100 void test_html_tidy(void){
2101 Blob in, out;
2102 int i;
2103
@@ -2212,10 +2215,19 @@
2212 if( nNL==0 ) blob_append(pOut, "\n", 1);
2213 }
2214
2215 /*
2216 ** COMMAND: test-html-to-text
 
 
 
 
 
 
 
 
 
2217 */
2218 void test_html_to_text(void){
2219 Blob in, out;
2220 int i;
2221
2222
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2094,10 +2094,13 @@
2094 if( iCur ) blob_append(pOut, "\n", 1);
2095 }
2096
2097 /*
2098 ** COMMAND: test-html-tidy
2099 **
2100 ** Run the htmlTidy() routine on the content of all files named on
2101 ** the command-line and write the results to standard output.
2102 */
2103 void test_html_tidy(void){
2104 Blob in, out;
2105 int i;
2106
@@ -2212,10 +2215,19 @@
2215 if( nNL==0 ) blob_append(pOut, "\n", 1);
2216 }
2217
2218 /*
2219 ** COMMAND: test-html-to-text
2220 **
2221 ** Usage: %fossil test-html-to-text FILE ...
2222 **
2223 ** Read all files named on the command-line. Convert the file
2224 ** content from HTML to text and write the results on standard
2225 ** output.
2226 **
2227 ** This command is intended as a test and debug interface for
2228 ** the html_to_plaintext() routine.
2229 */
2230 void test_html_to_text(void){
2231 Blob in, out;
2232 int i;
2233
2234
+4
--- src/xfer.c
+++ src/xfer.c
@@ -1971,8 +1971,12 @@
19711971
if( nErr && go==2 ){
19721972
db_multi_exec("DROP TABLE onremote");
19731973
manifest_crosslink_end(MC_PERMIT_HOOKS);
19741974
content_enable_dephantomize(1);
19751975
db_end_transaction(0);
1976
+ }
1977
+ if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978
+ fossil_warning("***** WARNING: a fork has occurred *****\n"
1979
+ "use \"fossil leaves -multiple\" for more details.");
19761980
}
19771981
return nErr;
19781982
}
19791983
--- src/xfer.c
+++ src/xfer.c
@@ -1971,8 +1971,12 @@
1971 if( nErr && go==2 ){
1972 db_multi_exec("DROP TABLE onremote");
1973 manifest_crosslink_end(MC_PERMIT_HOOKS);
1974 content_enable_dephantomize(1);
1975 db_end_transaction(0);
 
 
 
 
1976 }
1977 return nErr;
1978 }
1979
--- src/xfer.c
+++ src/xfer.c
@@ -1971,8 +1971,12 @@
1971 if( nErr && go==2 ){
1972 db_multi_exec("DROP TABLE onremote");
1973 manifest_crosslink_end(MC_PERMIT_HOOKS);
1974 content_enable_dephantomize(1);
1975 db_end_transaction(0);
1976 }
1977 if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978 fossil_warning("***** WARNING: a fork has occurred *****\n"
1979 "use \"fossil leaves -multiple\" for more details.");
1980 }
1981 return nErr;
1982 }
1983
+8 -1
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -21,12 +21,12 @@
2121
#include "config.h"
2222
#include "xfersetup.h"
2323
#include <assert.h>
2424
2525
/*
26
-** Main sub-menu for configuring the transfer system.
2726
** WEBPAGE: xfersetup
27
+** Main sub-menu for configuring the transfer system.
2828
*/
2929
void xfersetup_page(void){
3030
login_check_credentials();
3131
if( !g.perm.Setup ){
3232
login_needed(0);
@@ -157,10 +157,12 @@
157157
158158
static const char *zDefaultXferCommon = 0;
159159
160160
/*
161161
** WEBPAGE: xfersetup_com
162
+** View or edit the TH1 script that runs prior to receiving a
163
+** transfer.
162164
*/
163165
void xfersetup_com_page(void){
164166
static const char zDesc[] =
165167
@ Enter TH1 script that initializes variables prior to running
166168
@ any of the transfer request scripts.
@@ -178,10 +180,11 @@
178180
179181
static const char *zDefaultXferPush = 0;
180182
181183
/*
182184
** WEBPAGE: xfersetup_push
185
+** View or edit the TH1 script that runs after receiving a "push".
183186
*/
184187
void xfersetup_push_page(void){
185188
static const char zDesc[] =
186189
@ Enter TH1 script that runs after processing <strong>push</strong>
187190
@ transfer requests.
@@ -199,10 +202,12 @@
199202
200203
static const char *zDefaultXferCommit = 0;
201204
202205
/*
203206
** WEBPAGE: xfersetup_commit
207
+** View or edit the TH1 script that runs when a transfer commit
208
+** is processed.
204209
*/
205210
void xfersetup_commit_page(void){
206211
static const char zDesc[] =
207212
@ Enter TH1 script that runs when a commit is processed.
208213
;
@@ -219,10 +224,12 @@
219224
220225
static const char *zDefaultXferTicket = 0;
221226
222227
/*
223228
** WEBPAGE: xfersetup_ticket
229
+** View or edit the TH1 script that runs when a ticket change artifact
230
+** is processed during a transfer.
224231
*/
225232
void xfersetup_ticket_page(void){
226233
static const char zDesc[] =
227234
@ Enter TH1 script that runs when a ticket change is processed.
228235
;
229236
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -21,12 +21,12 @@
21 #include "config.h"
22 #include "xfersetup.h"
23 #include <assert.h>
24
25 /*
26 ** Main sub-menu for configuring the transfer system.
27 ** WEBPAGE: xfersetup
 
28 */
29 void xfersetup_page(void){
30 login_check_credentials();
31 if( !g.perm.Setup ){
32 login_needed(0);
@@ -157,10 +157,12 @@
157
158 static const char *zDefaultXferCommon = 0;
159
160 /*
161 ** WEBPAGE: xfersetup_com
 
 
162 */
163 void xfersetup_com_page(void){
164 static const char zDesc[] =
165 @ Enter TH1 script that initializes variables prior to running
166 @ any of the transfer request scripts.
@@ -178,10 +180,11 @@
178
179 static const char *zDefaultXferPush = 0;
180
181 /*
182 ** WEBPAGE: xfersetup_push
 
183 */
184 void xfersetup_push_page(void){
185 static const char zDesc[] =
186 @ Enter TH1 script that runs after processing <strong>push</strong>
187 @ transfer requests.
@@ -199,10 +202,12 @@
199
200 static const char *zDefaultXferCommit = 0;
201
202 /*
203 ** WEBPAGE: xfersetup_commit
 
 
204 */
205 void xfersetup_commit_page(void){
206 static const char zDesc[] =
207 @ Enter TH1 script that runs when a commit is processed.
208 ;
@@ -219,10 +224,12 @@
219
220 static const char *zDefaultXferTicket = 0;
221
222 /*
223 ** WEBPAGE: xfersetup_ticket
 
 
224 */
225 void xfersetup_ticket_page(void){
226 static const char zDesc[] =
227 @ Enter TH1 script that runs when a ticket change is processed.
228 ;
229
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -21,12 +21,12 @@
21 #include "config.h"
22 #include "xfersetup.h"
23 #include <assert.h>
24
25 /*
 
26 ** WEBPAGE: xfersetup
27 ** Main sub-menu for configuring the transfer system.
28 */
29 void xfersetup_page(void){
30 login_check_credentials();
31 if( !g.perm.Setup ){
32 login_needed(0);
@@ -157,10 +157,12 @@
157
158 static const char *zDefaultXferCommon = 0;
159
160 /*
161 ** WEBPAGE: xfersetup_com
162 ** View or edit the TH1 script that runs prior to receiving a
163 ** transfer.
164 */
165 void xfersetup_com_page(void){
166 static const char zDesc[] =
167 @ Enter TH1 script that initializes variables prior to running
168 @ any of the transfer request scripts.
@@ -178,10 +180,11 @@
180
181 static const char *zDefaultXferPush = 0;
182
183 /*
184 ** WEBPAGE: xfersetup_push
185 ** View or edit the TH1 script that runs after receiving a "push".
186 */
187 void xfersetup_push_page(void){
188 static const char zDesc[] =
189 @ Enter TH1 script that runs after processing <strong>push</strong>
190 @ transfer requests.
@@ -199,10 +202,12 @@
202
203 static const char *zDefaultXferCommit = 0;
204
205 /*
206 ** WEBPAGE: xfersetup_commit
207 ** View or edit the TH1 script that runs when a transfer commit
208 ** is processed.
209 */
210 void xfersetup_commit_page(void){
211 static const char zDesc[] =
212 @ Enter TH1 script that runs when a commit is processed.
213 ;
@@ -219,10 +224,12 @@
224
225 static const char *zDefaultXferTicket = 0;
226
227 /*
228 ** WEBPAGE: xfersetup_ticket
229 ** View or edit the TH1 script that runs when a ticket change artifact
230 ** is processed during a transfer.
231 */
232 void xfersetup_ticket_page(void){
233 static const char zDesc[] =
234 @ Enter TH1 script that runs when a ticket change is processed.
235 ;
236
+1 -1
--- src/zip.c
+++ src/zip.c
@@ -399,11 +399,11 @@
399399
int rid;
400400
Blob zip;
401401
const char *zName;
402402
zName = find_option("name", 0, 1);
403403
db_find_and_open_repository(0, 0);
404
-
404
+
405405
/* We should be done with options.. */
406406
verify_all_options();
407407
408408
if( g.argc!=4 ){
409409
usage("VERSION OUTPUTFILE");
410410
--- src/zip.c
+++ src/zip.c
@@ -399,11 +399,11 @@
399 int rid;
400 Blob zip;
401 const char *zName;
402 zName = find_option("name", 0, 1);
403 db_find_and_open_repository(0, 0);
404
405 /* We should be done with options.. */
406 verify_all_options();
407
408 if( g.argc!=4 ){
409 usage("VERSION OUTPUTFILE");
410
--- src/zip.c
+++ src/zip.c
@@ -399,11 +399,11 @@
399 int rid;
400 Blob zip;
401 const char *zName;
402 zName = find_option("name", 0, 1);
403 db_find_and_open_repository(0, 0);
404
405 /* We should be done with options.. */
406 verify_all_options();
407
408 if( g.argc!=4 ){
409 usage("VERSION OUTPUTFILE");
410
--- www/changes.wiki
+++ www/changes.wiki
@@ -9,10 +9,14 @@
99
* Fix some obscure issues with TH1 expression processing.
1010
* Fix titles in search results for documents that are not wiki, markdown,
1111
or HTML.
1212
* Formally translate TH1 to Tcl return codes and vice-versa, where
1313
necessary, in the Tcl integration subsystem.
14
+ * Better fork detection on [/help?cmd=update|fossil update],
15
+ [/help?cmd=status|fossil status] and related commands.
16
+ * Add [/help?cmd=leaves|fossil leaves -multiple], for finding multiple
17
+ leaves on the same branch.
1418
1519
<h2>Changes for Version 1.32 (2015-03-14)</h2>
1620
* When creating a new repository using [/help?cmd=init|fossil init], ensure
1721
that the new repository is fully compatible with historical versions of
1822
Fossil by having a valid manifest as RID 1.
@@ -23,11 +27,11 @@
2327
* Add the --repolist option to server commands such as
2428
[/help?cmd=server|fossil server] or [/help?cmd=http|fossil http].
2529
* Added the "Xekri" skin.
2630
* Enhance the "ln=" query parameter on artifact displays to accept multiple
2731
ranges, separate by spaces (or "+" when URL-encoded).
28
- * Added [/help?cmd=forget|fossil forget] as an alias for
32
+ * Added [/help?cmd=forget|fossil forget] as an alias for
2933
[/help?cmd=rm|fossil rm].
3034
3135
<h2>Changes For Version 1.31 (2015-02-23)</h2>
3236
* Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID
3337
columns to the schema, to support better drawing of file change graphs.
@@ -41,14 +45,12 @@
4145
enhancements to the search capabilities in subsequent releases.
4246
* Added form elements to some submenus (in particular the /timeline)
4347
for easier operation.
4448
* Added the --ifneeded option to [/help?cmd=rebuild|fossil rebuild].
4549
* Added "override skins" using the "skin:" line of the CGI script or
46
- using the --skin LABEL option on the
47
- [/help?cmd=server|server],
48
- [/help?cmd=ui|ui], or
49
- [/help?cmd=http|http] commands.
50
+ using the --skin LABEL option on the [/help?cmd=server|server],
51
+ [/help?cmd=ui|ui], or [/help?cmd=http|http] commands.
5052
* Embedded html documents that begin with
5153
&lt;doc class="fossil-doc"&gt; are displayed with standard
5254
headers and footers added.
5355
* Allow &lt;div style='...'&gt; markup in [/wiki_rules|wiki].
5456
* Renamed "Events" to "Technical Notes", while updating the technote
5557
--- www/changes.wiki
+++ www/changes.wiki
@@ -9,10 +9,14 @@
9 * Fix some obscure issues with TH1 expression processing.
10 * Fix titles in search results for documents that are not wiki, markdown,
11 or HTML.
12 * Formally translate TH1 to Tcl return codes and vice-versa, where
13 necessary, in the Tcl integration subsystem.
 
 
 
 
14
15 <h2>Changes for Version 1.32 (2015-03-14)</h2>
16 * When creating a new repository using [/help?cmd=init|fossil init], ensure
17 that the new repository is fully compatible with historical versions of
18 Fossil by having a valid manifest as RID 1.
@@ -23,11 +27,11 @@
23 * Add the --repolist option to server commands such as
24 [/help?cmd=server|fossil server] or [/help?cmd=http|fossil http].
25 * Added the "Xekri" skin.
26 * Enhance the "ln=" query parameter on artifact displays to accept multiple
27 ranges, separate by spaces (or "+" when URL-encoded).
28 * Added [/help?cmd=forget|fossil forget] as an alias for
29 [/help?cmd=rm|fossil rm].
30
31 <h2>Changes For Version 1.31 (2015-02-23)</h2>
32 * Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID
33 columns to the schema, to support better drawing of file change graphs.
@@ -41,14 +45,12 @@
41 enhancements to the search capabilities in subsequent releases.
42 * Added form elements to some submenus (in particular the /timeline)
43 for easier operation.
44 * Added the --ifneeded option to [/help?cmd=rebuild|fossil rebuild].
45 * Added "override skins" using the "skin:" line of the CGI script or
46 using the --skin LABEL option on the
47 [/help?cmd=server|server],
48 [/help?cmd=ui|ui], or
49 [/help?cmd=http|http] commands.
50 * Embedded html documents that begin with
51 &lt;doc class="fossil-doc"&gt; are displayed with standard
52 headers and footers added.
53 * Allow &lt;div style='...'&gt; markup in [/wiki_rules|wiki].
54 * Renamed "Events" to "Technical Notes", while updating the technote
55
--- www/changes.wiki
+++ www/changes.wiki
@@ -9,10 +9,14 @@
9 * Fix some obscure issues with TH1 expression processing.
10 * Fix titles in search results for documents that are not wiki, markdown,
11 or HTML.
12 * Formally translate TH1 to Tcl return codes and vice-versa, where
13 necessary, in the Tcl integration subsystem.
14 * Better fork detection on [/help?cmd=update|fossil update],
15 [/help?cmd=status|fossil status] and related commands.
16 * Add [/help?cmd=leaves|fossil leaves -multiple], for finding multiple
17 leaves on the same branch.
18
19 <h2>Changes for Version 1.32 (2015-03-14)</h2>
20 * When creating a new repository using [/help?cmd=init|fossil init], ensure
21 that the new repository is fully compatible with historical versions of
22 Fossil by having a valid manifest as RID 1.
@@ -23,11 +27,11 @@
27 * Add the --repolist option to server commands such as
28 [/help?cmd=server|fossil server] or [/help?cmd=http|fossil http].
29 * Added the "Xekri" skin.
30 * Enhance the "ln=" query parameter on artifact displays to accept multiple
31 ranges, separate by spaces (or "+" when URL-encoded).
32 * Added [/help?cmd=forget|fossil forget] as an alias for
33 [/help?cmd=rm|fossil rm].
34
35 <h2>Changes For Version 1.31 (2015-02-23)</h2>
36 * Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID
37 columns to the schema, to support better drawing of file change graphs.
@@ -41,14 +45,12 @@
45 enhancements to the search capabilities in subsequent releases.
46 * Added form elements to some submenus (in particular the /timeline)
47 for easier operation.
48 * Added the --ifneeded option to [/help?cmd=rebuild|fossil rebuild].
49 * Added "override skins" using the "skin:" line of the CGI script or
50 using the --skin LABEL option on the [/help?cmd=server|server],
51 [/help?cmd=ui|ui], or [/help?cmd=http|http] commands.
 
 
52 * Embedded html documents that begin with
53 &lt;doc class="fossil-doc"&gt; are displayed with standard
54 headers and footers added.
55 * Allow &lt;div style='...'&gt; markup in [/wiki_rules|wiki].
56 * Renamed "Events" to "Technical Notes", while updating the technote
57

Keyboard Shortcuts

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