Fossil SCM

Merge in updates from trunk.

andybradford 2015-07-16 05:03 check-in-edit merge
Commit 870c20885ba98d678337c5627a8c7f1040f52658
+11 -1
--- src/allrepo.c
+++ src/allrepo.c
@@ -86,10 +86,14 @@
8686
**
8787
** On Win32 systems, the file is named "_fossil" and is located in
8888
** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
8989
**
9090
** Available operations are:
91
+**
92
+** cache Mangages the cache used for potentially expensive web
93
+** pages. Any additional arguments are passed on verbatim
94
+** to the cache command.
9195
**
9296
** changes Shows all local checkouts that have uncommitted changes.
9397
** This operation has no additional options.
9498
**
9599
** clean Delete all "extra" files in all local checkouts. Extreme
@@ -192,15 +196,17 @@
192196
zCmd = "clean --chdir";
193197
collect_argument(&extra, "allckouts",0);
194198
collect_argument_value(&extra, "case-sensitive");
195199
collect_argument_value(&extra, "clean");
196200
collect_argument(&extra, "dirsonly",0);
201
+ collect_argument(&extra, "disable-undo",0);
197202
collect_argument(&extra, "dotfiles",0);
198203
collect_argument(&extra, "emptydirs",0);
199204
collect_argument(&extra, "force","f");
200205
collect_argument_value(&extra, "ignore");
201206
collect_argument_value(&extra, "keep");
207
+ collect_argument(&extra, "no-prompt",0);
202208
collect_argument(&extra, "temp",0);
203209
collect_argument(&extra, "verbose","v");
204210
collect_argument(&extra, "whatif",0);
205211
useCheckouts = 1;
206212
}else if( strncmp(zCmd, "dbstat", n)==0 ){
@@ -327,13 +333,17 @@
327333
return;
328334
}else if( strncmp(zCmd, "info", n)==0 ){
329335
zCmd = "info";
330336
showLabel = 1;
331337
quiet = 1;
338
+ }else if( strncmp(zCmd, "cache", n)==0 ){
339
+ zCmd = "cache -R";
340
+ showLabel = 1;
341
+ collect_argv(&extra, 3);
332342
}else{
333343
fossil_fatal("\"all\" subcommand should be one of: "
334
- "add changes clean dbstat extras fts-config ignore "
344
+ "add cache changes clean dbstat extras fts-config ignore "
335345
"info list ls pull push rebuild setting sync unset");
336346
}
337347
verify_all_options();
338348
zFossil = quoteFilename(g.nameOfExe);
339349
db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
340350
--- src/allrepo.c
+++ src/allrepo.c
@@ -86,10 +86,14 @@
86 **
87 ** On Win32 systems, the file is named "_fossil" and is located in
88 ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
89 **
90 ** Available operations are:
 
 
 
 
91 **
92 ** changes Shows all local checkouts that have uncommitted changes.
93 ** This operation has no additional options.
94 **
95 ** clean Delete all "extra" files in all local checkouts. Extreme
@@ -192,15 +196,17 @@
192 zCmd = "clean --chdir";
193 collect_argument(&extra, "allckouts",0);
194 collect_argument_value(&extra, "case-sensitive");
195 collect_argument_value(&extra, "clean");
196 collect_argument(&extra, "dirsonly",0);
 
197 collect_argument(&extra, "dotfiles",0);
198 collect_argument(&extra, "emptydirs",0);
199 collect_argument(&extra, "force","f");
200 collect_argument_value(&extra, "ignore");
201 collect_argument_value(&extra, "keep");
 
202 collect_argument(&extra, "temp",0);
203 collect_argument(&extra, "verbose","v");
204 collect_argument(&extra, "whatif",0);
205 useCheckouts = 1;
206 }else if( strncmp(zCmd, "dbstat", n)==0 ){
@@ -327,13 +333,17 @@
327 return;
328 }else if( strncmp(zCmd, "info", n)==0 ){
329 zCmd = "info";
330 showLabel = 1;
331 quiet = 1;
 
 
 
 
332 }else{
333 fossil_fatal("\"all\" subcommand should be one of: "
334 "add changes clean dbstat extras fts-config ignore "
335 "info list ls pull push rebuild setting sync unset");
336 }
337 verify_all_options();
338 zFossil = quoteFilename(g.nameOfExe);
339 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
340
--- src/allrepo.c
+++ src/allrepo.c
@@ -86,10 +86,14 @@
86 **
87 ** On Win32 systems, the file is named "_fossil" and is located in
88 ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
89 **
90 ** Available operations are:
91 **
92 ** cache Mangages the cache used for potentially expensive web
93 ** pages. Any additional arguments are passed on verbatim
94 ** to the cache command.
95 **
96 ** changes Shows all local checkouts that have uncommitted changes.
97 ** This operation has no additional options.
98 **
99 ** clean Delete all "extra" files in all local checkouts. Extreme
@@ -192,15 +196,17 @@
196 zCmd = "clean --chdir";
197 collect_argument(&extra, "allckouts",0);
198 collect_argument_value(&extra, "case-sensitive");
199 collect_argument_value(&extra, "clean");
200 collect_argument(&extra, "dirsonly",0);
201 collect_argument(&extra, "disable-undo",0);
202 collect_argument(&extra, "dotfiles",0);
203 collect_argument(&extra, "emptydirs",0);
204 collect_argument(&extra, "force","f");
205 collect_argument_value(&extra, "ignore");
206 collect_argument_value(&extra, "keep");
207 collect_argument(&extra, "no-prompt",0);
208 collect_argument(&extra, "temp",0);
209 collect_argument(&extra, "verbose","v");
210 collect_argument(&extra, "whatif",0);
211 useCheckouts = 1;
212 }else if( strncmp(zCmd, "dbstat", n)==0 ){
@@ -327,13 +333,17 @@
333 return;
334 }else if( strncmp(zCmd, "info", n)==0 ){
335 zCmd = "info";
336 showLabel = 1;
337 quiet = 1;
338 }else if( strncmp(zCmd, "cache", n)==0 ){
339 zCmd = "cache -R";
340 showLabel = 1;
341 collect_argv(&extra, 3);
342 }else{
343 fossil_fatal("\"all\" subcommand should be one of: "
344 "add cache changes clean dbstat extras fts-config ignore "
345 "info list ls pull push rebuild setting sync unset");
346 }
347 verify_all_options();
348 zFossil = quoteFilename(g.nameOfExe);
349 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
350
+67 -27
--- src/checkin.c
+++ src/checkin.c
@@ -644,11 +644,12 @@
644644
** Files and subdirectories whose names begin with "." are automatically
645645
** ignored unless the --dotfiles option is used.
646646
**
647647
** The --verily option ignores the keep-glob and ignore-glob settings
648648
** and turns on --force, --dotfiles, and --emptydirs. Use the --verily
649
-** option when you really want to clean up everything.
649
+** option when you really want to clean up everything. Extreme care
650
+** should be exercised when using the --verily option.
650651
**
651652
** Options:
652653
** --allckouts Check for empty directories within any checkouts
653654
** that may be nested within the current one. This
654655
** option should be used with great care because the
@@ -657,51 +658,70 @@
657658
** not be checked.
658659
** --case-sensitive <BOOL> override case-sensitive setting
659660
** --dirsonly Only remove empty directories. No files will
660661
** be removed. Using this option will automatically
661662
** enable the --emptydirs option as well.
663
+** --disable-undo WARNING: This option disables use of the undo
664
+** mechanism for this clean operation and should be
665
+** used with extreme caution.
662666
** --dotfiles Include files beginning with a dot (".").
663667
** --emptydirs Remove any empty directories that are not
664668
** explicitly exempted via the empty-dirs setting
665669
** or another applicable setting or command line
666670
** argument. Matching files, if any, are removed
667671
** prior to checking for any empty directories;
668672
** therefore, directories that contain only files
669673
** that were removed will be removed as well.
670674
** -f|--force Remove files without prompting.
671
-** -x|--verily Remove everything that is not a managed file or
672
-** the repository itself. Implies -f --emptydirs
673
-** --dotfiles. Disregard keep-glob and ignore-glob.
674
-** --clean <CSG> Never prompt for files matching this
675
-** comma separated list of glob patterns.
675
+** -x|--verily WARNING: Removes everything that is not a managed
676
+** file or the repository itself. This option
677
+** implies the --force, --emptydirs, --dotfiles, and
678
+** --disable-undo options. Furthermore, it completely
679
+** disregards the keep-glob and ignore-glob settings.
680
+** However, it does honor the --ignore and --keep
681
+** options.
682
+** --clean <CSG> WARNING: Never prompt to delete any files matching
683
+** this comma separated list of glob patterns. Also,
684
+** deletions of any files matching this pattern list
685
+** cannot be undone.
676686
** --ignore <CSG> Ignore files matching patterns from the
677687
** comma separated list of glob patterns.
678688
** --keep <CSG> Keep files matching this comma separated
679689
** list of glob patterns.
680690
** -n|--dry-run Delete nothing, but display what would have been
681691
** deleted.
692
+** --no-prompt This option disables prompting the user for input
693
+** and assumes an answer of 'No' for every question.
682694
** --temp Remove only Fossil-generated temporary files.
683695
** -v|--verbose Show all files as they are removed.
684696
**
685697
** See also: addremove, extras, status
686698
*/
687699
void clean_cmd(void){
688700
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
689701
int emptyDirsFlag, dirsOnlyFlag;
702
+ int disableUndo, noPrompt;
690703
unsigned scanFlags = 0;
691704
int verilyFlag = 0;
692705
const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
693706
Glob *pIgnore, *pKeep, *pClean;
694707
int nRoot;
695708
709
+#ifndef UNDO_SIZE_LIMIT /* TODO: Setting? */
710
+#define UNDO_SIZE_LIMIT (10*1024*1024) /* 10MiB */
711
+#endif
712
+
713
+ undo_capture_command_line();
696714
dryRunFlag = find_option("dry-run","n",0)!=0;
697715
if( !dryRunFlag ){
698716
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
699717
}
700718
if( !dryRunFlag ){
701719
dryRunFlag = find_option("whatif",0,0)!=0;
702720
}
721
+ disableUndo = find_option("disable-undo",0,0)!=0;
722
+ noPrompt = find_option("no-prompt",0,0)!=0;
703723
allFileFlag = allDirFlag = find_option("force","f",0)!=0;
704724
dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
705725
emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
706726
if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
707727
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
@@ -712,10 +732,11 @@
712732
zCleanFlag = find_option("clean",0,1);
713733
db_must_be_within_tree();
714734
if( find_option("verily","x",0)!=0 ){
715735
verilyFlag = allFileFlag = allDirFlag = 1;
716736
emptyDirsFlag = 1;
737
+ disableUndo = 1;
717738
scanFlags |= SCAN_ALL;
718739
zCleanFlag = 0;
719740
}
720741
if( zIgnoreFlag==0 && !verilyFlag ){
721742
zIgnoreFlag = db_get("ignore-glob", 0);
@@ -734,10 +755,11 @@
734755
nRoot = (int)strlen(g.zLocalRoot);
735756
g.allowSymlinks = 1; /* Find symlinks too */
736757
if( !dirsOnlyFlag ){
737758
Stmt q;
738759
Blob repo;
760
+ if( !dryRunFlag && !disableUndo ) undo_begin();
739761
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
740762
db_prepare(&q,
741763
"SELECT %Q || x FROM sfile"
742764
" WHERE x NOT IN (%s)"
743765
" ORDER BY 1",
@@ -754,24 +776,38 @@
754776
fossil_print("KEPT file \"%s\" not removed (due to --keep"
755777
" or \"keep-glob\")\n", zName+nRoot);
756778
}
757779
continue;
758780
}
759
- if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
760
- Blob ans;
761
- char cReply;
762
- char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
763
- zName+nRoot);
764
- prompt_user(prompt, &ans);
765
- cReply = blob_str(&ans)[0];
766
- if( cReply=='a' || cReply=='A' ){
767
- allFileFlag = 1;
768
- }else if( cReply!='y' && cReply!='Y' ){
769
- blob_reset(&ans);
770
- continue;
771
- }
772
- blob_reset(&ans);
781
+ if( !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
782
+ int undoRc = UNDO_NONE;
783
+ if( !disableUndo ){
784
+ undoRc = undo_maybe_save(zName+nRoot, UNDO_SIZE_LIMIT);
785
+ }
786
+ if( undoRc!=UNDO_SAVED_OK ){
787
+ char cReply;
788
+ if( allFileFlag ){
789
+ cReply = 'Y';
790
+ }else if( !noPrompt ){
791
+ Blob ans;
792
+ char *prompt = mprintf("\nWARNING: Deletion of this file will "
793
+ "not be undoable via the 'undo'\n"
794
+ " command because %s.\n\n"
795
+ "Remove unmanaged file \"%s\" (a=all/y/N)? ",
796
+ undo_save_message(undoRc), zName+nRoot);
797
+ prompt_user(prompt, &ans);
798
+ cReply = blob_str(&ans)[0];
799
+ blob_reset(&ans);
800
+ }else{
801
+ cReply = 'N';
802
+ }
803
+ if( cReply=='a' || cReply=='A' ){
804
+ allFileFlag = 1;
805
+ }else if( cReply!='y' && cReply!='Y' ){
806
+ continue;
807
+ }
808
+ }
773809
}
774810
if( dryRunFlag || file_delete(zName)==0 ){
775811
if( verboseFlag || dryRunFlag ){
776812
fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
777813
}
@@ -778,10 +814,11 @@
778814
}else if( verboseFlag ){
779815
fossil_print("Could not remove file: %s\n", zName+nRoot);
780816
}
781817
}
782818
db_finalize(&q);
819
+ if( !dryRunFlag && !disableUndo ) undo_finish();
783820
}
784821
if( emptyDirsFlag ){
785822
Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
786823
Stmt q;
787824
Blob root;
@@ -803,23 +840,26 @@
803840
" or \"keep-glob\")\n", zName+nRoot);
804841
}
805842
continue;
806843
}
807844
if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
808
- Blob ans;
809845
char cReply;
810
- char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
811
- zName+nRoot);
812
- prompt_user(prompt, &ans);
813
- cReply = blob_str(&ans)[0];
846
+ if( !noPrompt ){
847
+ Blob ans;
848
+ char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
849
+ zName+nRoot);
850
+ prompt_user(prompt, &ans);
851
+ cReply = blob_str(&ans)[0];
852
+ blob_reset(&ans);
853
+ }else{
854
+ cReply = 'N';
855
+ }
814856
if( cReply=='a' || cReply=='A' ){
815857
allDirFlag = 1;
816858
}else if( cReply!='y' && cReply!='Y' ){
817
- blob_reset(&ans);
818859
continue;
819860
}
820
- blob_reset(&ans);
821861
}
822862
if( dryRunFlag || file_rmdir(zName)==0 ){
823863
if( verboseFlag || dryRunFlag ){
824864
fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
825865
}
826866
--- src/checkin.c
+++ src/checkin.c
@@ -644,11 +644,12 @@
644 ** Files and subdirectories whose names begin with "." are automatically
645 ** ignored unless the --dotfiles option is used.
646 **
647 ** The --verily option ignores the keep-glob and ignore-glob settings
648 ** and turns on --force, --dotfiles, and --emptydirs. Use the --verily
649 ** option when you really want to clean up everything.
 
650 **
651 ** Options:
652 ** --allckouts Check for empty directories within any checkouts
653 ** that may be nested within the current one. This
654 ** option should be used with great care because the
@@ -657,51 +658,70 @@
657 ** not be checked.
658 ** --case-sensitive <BOOL> override case-sensitive setting
659 ** --dirsonly Only remove empty directories. No files will
660 ** be removed. Using this option will automatically
661 ** enable the --emptydirs option as well.
 
 
 
662 ** --dotfiles Include files beginning with a dot (".").
663 ** --emptydirs Remove any empty directories that are not
664 ** explicitly exempted via the empty-dirs setting
665 ** or another applicable setting or command line
666 ** argument. Matching files, if any, are removed
667 ** prior to checking for any empty directories;
668 ** therefore, directories that contain only files
669 ** that were removed will be removed as well.
670 ** -f|--force Remove files without prompting.
671 ** -x|--verily Remove everything that is not a managed file or
672 ** the repository itself. Implies -f --emptydirs
673 ** --dotfiles. Disregard keep-glob and ignore-glob.
674 ** --clean <CSG> Never prompt for files matching this
675 ** comma separated list of glob patterns.
 
 
 
 
 
 
676 ** --ignore <CSG> Ignore files matching patterns from the
677 ** comma separated list of glob patterns.
678 ** --keep <CSG> Keep files matching this comma separated
679 ** list of glob patterns.
680 ** -n|--dry-run Delete nothing, but display what would have been
681 ** deleted.
 
 
682 ** --temp Remove only Fossil-generated temporary files.
683 ** -v|--verbose Show all files as they are removed.
684 **
685 ** See also: addremove, extras, status
686 */
687 void clean_cmd(void){
688 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
689 int emptyDirsFlag, dirsOnlyFlag;
 
690 unsigned scanFlags = 0;
691 int verilyFlag = 0;
692 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
693 Glob *pIgnore, *pKeep, *pClean;
694 int nRoot;
695
 
 
 
 
 
696 dryRunFlag = find_option("dry-run","n",0)!=0;
697 if( !dryRunFlag ){
698 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
699 }
700 if( !dryRunFlag ){
701 dryRunFlag = find_option("whatif",0,0)!=0;
702 }
 
 
703 allFileFlag = allDirFlag = find_option("force","f",0)!=0;
704 dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
705 emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
706 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
707 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
@@ -712,10 +732,11 @@
712 zCleanFlag = find_option("clean",0,1);
713 db_must_be_within_tree();
714 if( find_option("verily","x",0)!=0 ){
715 verilyFlag = allFileFlag = allDirFlag = 1;
716 emptyDirsFlag = 1;
 
717 scanFlags |= SCAN_ALL;
718 zCleanFlag = 0;
719 }
720 if( zIgnoreFlag==0 && !verilyFlag ){
721 zIgnoreFlag = db_get("ignore-glob", 0);
@@ -734,10 +755,11 @@
734 nRoot = (int)strlen(g.zLocalRoot);
735 g.allowSymlinks = 1; /* Find symlinks too */
736 if( !dirsOnlyFlag ){
737 Stmt q;
738 Blob repo;
 
739 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
740 db_prepare(&q,
741 "SELECT %Q || x FROM sfile"
742 " WHERE x NOT IN (%s)"
743 " ORDER BY 1",
@@ -754,24 +776,38 @@
754 fossil_print("KEPT file \"%s\" not removed (due to --keep"
755 " or \"keep-glob\")\n", zName+nRoot);
756 }
757 continue;
758 }
759 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
760 Blob ans;
761 char cReply;
762 char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
763 zName+nRoot);
764 prompt_user(prompt, &ans);
765 cReply = blob_str(&ans)[0];
766 if( cReply=='a' || cReply=='A' ){
767 allFileFlag = 1;
768 }else if( cReply!='y' && cReply!='Y' ){
769 blob_reset(&ans);
770 continue;
771 }
772 blob_reset(&ans);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773 }
774 if( dryRunFlag || file_delete(zName)==0 ){
775 if( verboseFlag || dryRunFlag ){
776 fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
777 }
@@ -778,10 +814,11 @@
778 }else if( verboseFlag ){
779 fossil_print("Could not remove file: %s\n", zName+nRoot);
780 }
781 }
782 db_finalize(&q);
 
783 }
784 if( emptyDirsFlag ){
785 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
786 Stmt q;
787 Blob root;
@@ -803,23 +840,26 @@
803 " or \"keep-glob\")\n", zName+nRoot);
804 }
805 continue;
806 }
807 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
808 Blob ans;
809 char cReply;
810 char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
811 zName+nRoot);
812 prompt_user(prompt, &ans);
813 cReply = blob_str(&ans)[0];
 
 
 
 
 
 
814 if( cReply=='a' || cReply=='A' ){
815 allDirFlag = 1;
816 }else if( cReply!='y' && cReply!='Y' ){
817 blob_reset(&ans);
818 continue;
819 }
820 blob_reset(&ans);
821 }
822 if( dryRunFlag || file_rmdir(zName)==0 ){
823 if( verboseFlag || dryRunFlag ){
824 fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
825 }
826
--- src/checkin.c
+++ src/checkin.c
@@ -644,11 +644,12 @@
644 ** Files and subdirectories whose names begin with "." are automatically
645 ** ignored unless the --dotfiles option is used.
646 **
647 ** The --verily option ignores the keep-glob and ignore-glob settings
648 ** and turns on --force, --dotfiles, and --emptydirs. Use the --verily
649 ** option when you really want to clean up everything. Extreme care
650 ** should be exercised when using the --verily option.
651 **
652 ** Options:
653 ** --allckouts Check for empty directories within any checkouts
654 ** that may be nested within the current one. This
655 ** option should be used with great care because the
@@ -657,51 +658,70 @@
658 ** not be checked.
659 ** --case-sensitive <BOOL> override case-sensitive setting
660 ** --dirsonly Only remove empty directories. No files will
661 ** be removed. Using this option will automatically
662 ** enable the --emptydirs option as well.
663 ** --disable-undo WARNING: This option disables use of the undo
664 ** mechanism for this clean operation and should be
665 ** used with extreme caution.
666 ** --dotfiles Include files beginning with a dot (".").
667 ** --emptydirs Remove any empty directories that are not
668 ** explicitly exempted via the empty-dirs setting
669 ** or another applicable setting or command line
670 ** argument. Matching files, if any, are removed
671 ** prior to checking for any empty directories;
672 ** therefore, directories that contain only files
673 ** that were removed will be removed as well.
674 ** -f|--force Remove files without prompting.
675 ** -x|--verily WARNING: Removes everything that is not a managed
676 ** file or the repository itself. This option
677 ** implies the --force, --emptydirs, --dotfiles, and
678 ** --disable-undo options. Furthermore, it completely
679 ** disregards the keep-glob and ignore-glob settings.
680 ** However, it does honor the --ignore and --keep
681 ** options.
682 ** --clean <CSG> WARNING: Never prompt to delete any files matching
683 ** this comma separated list of glob patterns. Also,
684 ** deletions of any files matching this pattern list
685 ** cannot be undone.
686 ** --ignore <CSG> Ignore files matching patterns from the
687 ** comma separated list of glob patterns.
688 ** --keep <CSG> Keep files matching this comma separated
689 ** list of glob patterns.
690 ** -n|--dry-run Delete nothing, but display what would have been
691 ** deleted.
692 ** --no-prompt This option disables prompting the user for input
693 ** and assumes an answer of 'No' for every question.
694 ** --temp Remove only Fossil-generated temporary files.
695 ** -v|--verbose Show all files as they are removed.
696 **
697 ** See also: addremove, extras, status
698 */
699 void clean_cmd(void){
700 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
701 int emptyDirsFlag, dirsOnlyFlag;
702 int disableUndo, noPrompt;
703 unsigned scanFlags = 0;
704 int verilyFlag = 0;
705 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
706 Glob *pIgnore, *pKeep, *pClean;
707 int nRoot;
708
709 #ifndef UNDO_SIZE_LIMIT /* TODO: Setting? */
710 #define UNDO_SIZE_LIMIT (10*1024*1024) /* 10MiB */
711 #endif
712
713 undo_capture_command_line();
714 dryRunFlag = find_option("dry-run","n",0)!=0;
715 if( !dryRunFlag ){
716 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
717 }
718 if( !dryRunFlag ){
719 dryRunFlag = find_option("whatif",0,0)!=0;
720 }
721 disableUndo = find_option("disable-undo",0,0)!=0;
722 noPrompt = find_option("no-prompt",0,0)!=0;
723 allFileFlag = allDirFlag = find_option("force","f",0)!=0;
724 dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
725 emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
726 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
727 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
@@ -712,10 +732,11 @@
732 zCleanFlag = find_option("clean",0,1);
733 db_must_be_within_tree();
734 if( find_option("verily","x",0)!=0 ){
735 verilyFlag = allFileFlag = allDirFlag = 1;
736 emptyDirsFlag = 1;
737 disableUndo = 1;
738 scanFlags |= SCAN_ALL;
739 zCleanFlag = 0;
740 }
741 if( zIgnoreFlag==0 && !verilyFlag ){
742 zIgnoreFlag = db_get("ignore-glob", 0);
@@ -734,10 +755,11 @@
755 nRoot = (int)strlen(g.zLocalRoot);
756 g.allowSymlinks = 1; /* Find symlinks too */
757 if( !dirsOnlyFlag ){
758 Stmt q;
759 Blob repo;
760 if( !dryRunFlag && !disableUndo ) undo_begin();
761 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
762 db_prepare(&q,
763 "SELECT %Q || x FROM sfile"
764 " WHERE x NOT IN (%s)"
765 " ORDER BY 1",
@@ -754,24 +776,38 @@
776 fossil_print("KEPT file \"%s\" not removed (due to --keep"
777 " or \"keep-glob\")\n", zName+nRoot);
778 }
779 continue;
780 }
781 if( !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
782 int undoRc = UNDO_NONE;
783 if( !disableUndo ){
784 undoRc = undo_maybe_save(zName+nRoot, UNDO_SIZE_LIMIT);
785 }
786 if( undoRc!=UNDO_SAVED_OK ){
787 char cReply;
788 if( allFileFlag ){
789 cReply = 'Y';
790 }else if( !noPrompt ){
791 Blob ans;
792 char *prompt = mprintf("\nWARNING: Deletion of this file will "
793 "not be undoable via the 'undo'\n"
794 " command because %s.\n\n"
795 "Remove unmanaged file \"%s\" (a=all/y/N)? ",
796 undo_save_message(undoRc), zName+nRoot);
797 prompt_user(prompt, &ans);
798 cReply = blob_str(&ans)[0];
799 blob_reset(&ans);
800 }else{
801 cReply = 'N';
802 }
803 if( cReply=='a' || cReply=='A' ){
804 allFileFlag = 1;
805 }else if( cReply!='y' && cReply!='Y' ){
806 continue;
807 }
808 }
809 }
810 if( dryRunFlag || file_delete(zName)==0 ){
811 if( verboseFlag || dryRunFlag ){
812 fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
813 }
@@ -778,10 +814,11 @@
814 }else if( verboseFlag ){
815 fossil_print("Could not remove file: %s\n", zName+nRoot);
816 }
817 }
818 db_finalize(&q);
819 if( !dryRunFlag && !disableUndo ) undo_finish();
820 }
821 if( emptyDirsFlag ){
822 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
823 Stmt q;
824 Blob root;
@@ -803,23 +840,26 @@
840 " or \"keep-glob\")\n", zName+nRoot);
841 }
842 continue;
843 }
844 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
 
845 char cReply;
846 if( !noPrompt ){
847 Blob ans;
848 char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
849 zName+nRoot);
850 prompt_user(prompt, &ans);
851 cReply = blob_str(&ans)[0];
852 blob_reset(&ans);
853 }else{
854 cReply = 'N';
855 }
856 if( cReply=='a' || cReply=='A' ){
857 allDirFlag = 1;
858 }else if( cReply!='y' && cReply!='Y' ){
 
859 continue;
860 }
 
861 }
862 if( dryRunFlag || file_rmdir(zName)==0 ){
863 if( verboseFlag || dryRunFlag ){
864 fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
865 }
866
+61
--- src/delta.c
+++ src/delta.c
@@ -589,10 +589,71 @@
589589
/* ERROR: generated size does not match predicted size */
590590
return -1;
591591
}
592592
return total;
593593
}
594
+ default: {
595
+ /* ERROR: unknown delta operator */
596
+ return -1;
597
+ }
598
+ }
599
+ }
600
+ /* ERROR: unterminated delta */
601
+ return -1;
602
+}
603
+
604
+/*
605
+** Analyze a delta. Figure out the total number of bytes copied from
606
+** source to target, and the total number of bytes inserted by the delta,
607
+** and return both numbers.
608
+*/
609
+int delta_analyze(
610
+ const char *zDelta, /* Delta to apply to the pattern */
611
+ int lenDelta, /* Length of the delta */
612
+ int *pnCopy, /* OUT: Number of bytes copied */
613
+ int *pnInsert /* OUT: Number of bytes inserted */
614
+){
615
+ unsigned int nInsert = 0;
616
+ unsigned int nCopy = 0;
617
+
618
+ (void)getInt(&zDelta, &lenDelta);
619
+ if( *zDelta!='\n' ){
620
+ /* ERROR: size integer not terminated by "\n" */
621
+ return -1;
622
+ }
623
+ zDelta++; lenDelta--;
624
+ while( *zDelta && lenDelta>0 ){
625
+ unsigned int cnt, ofst;
626
+ cnt = getInt(&zDelta, &lenDelta);
627
+ switch( zDelta[0] ){
628
+ case '@': {
629
+ zDelta++; lenDelta--;
630
+ ofst = getInt(&zDelta, &lenDelta);
631
+ if( lenDelta>0 && zDelta[0]!=',' ){
632
+ /* ERROR: copy command not terminated by ',' */
633
+ return -1;
634
+ }
635
+ zDelta++; lenDelta--;
636
+ nCopy += cnt;
637
+ break;
638
+ }
639
+ case ':': {
640
+ zDelta++; lenDelta--;
641
+ nInsert += cnt;
642
+ if( cnt>lenDelta ){
643
+ /* ERROR: insert count exceeds size of delta */
644
+ return -1;
645
+ }
646
+ zDelta += cnt;
647
+ lenDelta -= cnt;
648
+ break;
649
+ }
650
+ case ';': {
651
+ *pnCopy = nCopy;
652
+ *pnInsert = nInsert;
653
+ return 0;
654
+ }
594655
default: {
595656
/* ERROR: unknown delta operator */
596657
return -1;
597658
}
598659
}
599660
--- src/delta.c
+++ src/delta.c
@@ -589,10 +589,71 @@
589 /* ERROR: generated size does not match predicted size */
590 return -1;
591 }
592 return total;
593 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
594 default: {
595 /* ERROR: unknown delta operator */
596 return -1;
597 }
598 }
599
--- src/delta.c
+++ src/delta.c
@@ -589,10 +589,71 @@
589 /* ERROR: generated size does not match predicted size */
590 return -1;
591 }
592 return total;
593 }
594 default: {
595 /* ERROR: unknown delta operator */
596 return -1;
597 }
598 }
599 }
600 /* ERROR: unterminated delta */
601 return -1;
602 }
603
604 /*
605 ** Analyze a delta. Figure out the total number of bytes copied from
606 ** source to target, and the total number of bytes inserted by the delta,
607 ** and return both numbers.
608 */
609 int delta_analyze(
610 const char *zDelta, /* Delta to apply to the pattern */
611 int lenDelta, /* Length of the delta */
612 int *pnCopy, /* OUT: Number of bytes copied */
613 int *pnInsert /* OUT: Number of bytes inserted */
614 ){
615 unsigned int nInsert = 0;
616 unsigned int nCopy = 0;
617
618 (void)getInt(&zDelta, &lenDelta);
619 if( *zDelta!='\n' ){
620 /* ERROR: size integer not terminated by "\n" */
621 return -1;
622 }
623 zDelta++; lenDelta--;
624 while( *zDelta && lenDelta>0 ){
625 unsigned int cnt, ofst;
626 cnt = getInt(&zDelta, &lenDelta);
627 switch( zDelta[0] ){
628 case '@': {
629 zDelta++; lenDelta--;
630 ofst = getInt(&zDelta, &lenDelta);
631 if( lenDelta>0 && zDelta[0]!=',' ){
632 /* ERROR: copy command not terminated by ',' */
633 return -1;
634 }
635 zDelta++; lenDelta--;
636 nCopy += cnt;
637 break;
638 }
639 case ':': {
640 zDelta++; lenDelta--;
641 nInsert += cnt;
642 if( cnt>lenDelta ){
643 /* ERROR: insert count exceeds size of delta */
644 return -1;
645 }
646 zDelta += cnt;
647 lenDelta -= cnt;
648 break;
649 }
650 case ';': {
651 *pnCopy = nCopy;
652 *pnInsert = nInsert;
653 return 0;
654 }
655 default: {
656 /* ERROR: unknown delta operator */
657 return -1;
658 }
659 }
660
+47 -4
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -43,12 +43,14 @@
4343
}
4444
4545
/*
4646
** COMMAND: test-delta-create
4747
**
48
-** Given two input files, create and output a delta that carries
49
-** the first file into the second.
48
+** Usage: %fossil test-delta-create FILE1 FILE2 DELTA
49
+**
50
+** Create and output a delta that carries FILE1 into FILE2.
51
+** Store the result in DELTA.
5052
*/
5153
void delta_create_cmd(void){
5254
Blob orig, target, delta;
5355
if( g.argc!=5 ){
5456
usage("ORIGIN TARGET DELTA");
@@ -65,10 +67,47 @@
6567
}
6668
blob_reset(&orig);
6769
blob_reset(&target);
6870
blob_reset(&delta);
6971
}
72
+
73
+/*
74
+** COMMAND: test-delta-analyze
75
+**
76
+** Usage: %fossil test-delta-analyze FILE1 FILE2
77
+**
78
+** Create and a delta that carries FILE1 into FILE2. Print the
79
+** number bytes copied and the number of bytes inserted.
80
+*/
81
+void delta_analyze_cmd(void){
82
+ Blob orig, target, delta;
83
+ int nCopy = 0;
84
+ int nInsert = 0;
85
+ int sz1, sz2;
86
+ if( g.argc!=4 ){
87
+ usage("ORIGIN TARGET");
88
+ }
89
+ if( blob_read_from_file(&orig, g.argv[2])<0 ){
90
+ fossil_fatal("cannot read %s\n", g.argv[2]);
91
+ }
92
+ if( blob_read_from_file(&target, g.argv[3])<0 ){
93
+ fossil_fatal("cannot read %s\n", g.argv[3]);
94
+ }
95
+ blob_delta_create(&orig, &target, &delta);
96
+ delta_analyze(blob_buffer(&delta), blob_size(&delta), &nCopy, &nInsert);
97
+ sz1 = blob_size(&orig);
98
+ sz2 = blob_size(&target);
99
+ blob_reset(&orig);
100
+ blob_reset(&target);
101
+ blob_reset(&delta);
102
+ fossil_print("original size: %8d\n", sz1);
103
+ fossil_print("bytes copied: %8d (%.1f%% of target)\n",
104
+ nCopy, (100.0*nCopy)/sz2);
105
+ fossil_print("bytes inserted: %8d (%.1f%% of target)\n",
106
+ nInsert, (100.0*nInsert)/sz2);
107
+ fossil_print("final size: %8d\n", sz2);
108
+}
70109
71110
/*
72111
** Apply the delta in pDelta to the original file pOriginal to generate
73112
** the target file pTarget. The pTarget blob is initialized by this
74113
** routine.
@@ -102,12 +141,13 @@
102141
}
103142
104143
/*
105144
** COMMAND: test-delta-apply
106145
**
107
-** Given an input files and a delta, apply the delta to the input file
108
-** and write the result.
146
+** Usage: %fossil test-delta-apply FILE1 DELTA
147
+**
148
+** Apply DELTA to FILE1 and output the result.
109149
*/
110150
void delta_apply_cmd(void){
111151
Blob orig, target, delta;
112152
if( g.argc!=5 ){
113153
usage("ORIGIN DELTA TARGET");
@@ -124,13 +164,16 @@
124164
}
125165
blob_reset(&orig);
126166
blob_reset(&target);
127167
blob_reset(&delta);
128168
}
169
+
129170
130171
/*
131172
** COMMAND: test-delta
173
+**
174
+** Usage: %fossil test-delta FILE1 FILE2
132175
**
133176
** Read two files named on the command-line. Create and apply deltas
134177
** going in both directions. Verify that the original files are
135178
** correctly recovered.
136179
*/
137180
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -43,12 +43,14 @@
43 }
44
45 /*
46 ** COMMAND: test-delta-create
47 **
48 ** Given two input files, create and output a delta that carries
49 ** the first file into the second.
 
 
50 */
51 void delta_create_cmd(void){
52 Blob orig, target, delta;
53 if( g.argc!=5 ){
54 usage("ORIGIN TARGET DELTA");
@@ -65,10 +67,47 @@
65 }
66 blob_reset(&orig);
67 blob_reset(&target);
68 blob_reset(&delta);
69 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
71 /*
72 ** Apply the delta in pDelta to the original file pOriginal to generate
73 ** the target file pTarget. The pTarget blob is initialized by this
74 ** routine.
@@ -102,12 +141,13 @@
102 }
103
104 /*
105 ** COMMAND: test-delta-apply
106 **
107 ** Given an input files and a delta, apply the delta to the input file
108 ** and write the result.
 
109 */
110 void delta_apply_cmd(void){
111 Blob orig, target, delta;
112 if( g.argc!=5 ){
113 usage("ORIGIN DELTA TARGET");
@@ -124,13 +164,16 @@
124 }
125 blob_reset(&orig);
126 blob_reset(&target);
127 blob_reset(&delta);
128 }
 
129
130 /*
131 ** COMMAND: test-delta
 
 
132 **
133 ** Read two files named on the command-line. Create and apply deltas
134 ** going in both directions. Verify that the original files are
135 ** correctly recovered.
136 */
137
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -43,12 +43,14 @@
43 }
44
45 /*
46 ** COMMAND: test-delta-create
47 **
48 ** Usage: %fossil test-delta-create FILE1 FILE2 DELTA
49 **
50 ** Create and output a delta that carries FILE1 into FILE2.
51 ** Store the result in DELTA.
52 */
53 void delta_create_cmd(void){
54 Blob orig, target, delta;
55 if( g.argc!=5 ){
56 usage("ORIGIN TARGET DELTA");
@@ -65,10 +67,47 @@
67 }
68 blob_reset(&orig);
69 blob_reset(&target);
70 blob_reset(&delta);
71 }
72
73 /*
74 ** COMMAND: test-delta-analyze
75 **
76 ** Usage: %fossil test-delta-analyze FILE1 FILE2
77 **
78 ** Create and a delta that carries FILE1 into FILE2. Print the
79 ** number bytes copied and the number of bytes inserted.
80 */
81 void delta_analyze_cmd(void){
82 Blob orig, target, delta;
83 int nCopy = 0;
84 int nInsert = 0;
85 int sz1, sz2;
86 if( g.argc!=4 ){
87 usage("ORIGIN TARGET");
88 }
89 if( blob_read_from_file(&orig, g.argv[2])<0 ){
90 fossil_fatal("cannot read %s\n", g.argv[2]);
91 }
92 if( blob_read_from_file(&target, g.argv[3])<0 ){
93 fossil_fatal("cannot read %s\n", g.argv[3]);
94 }
95 blob_delta_create(&orig, &target, &delta);
96 delta_analyze(blob_buffer(&delta), blob_size(&delta), &nCopy, &nInsert);
97 sz1 = blob_size(&orig);
98 sz2 = blob_size(&target);
99 blob_reset(&orig);
100 blob_reset(&target);
101 blob_reset(&delta);
102 fossil_print("original size: %8d\n", sz1);
103 fossil_print("bytes copied: %8d (%.1f%% of target)\n",
104 nCopy, (100.0*nCopy)/sz2);
105 fossil_print("bytes inserted: %8d (%.1f%% of target)\n",
106 nInsert, (100.0*nInsert)/sz2);
107 fossil_print("final size: %8d\n", sz2);
108 }
109
110 /*
111 ** Apply the delta in pDelta to the original file pOriginal to generate
112 ** the target file pTarget. The pTarget blob is initialized by this
113 ** routine.
@@ -102,12 +141,13 @@
141 }
142
143 /*
144 ** COMMAND: test-delta-apply
145 **
146 ** Usage: %fossil test-delta-apply FILE1 DELTA
147 **
148 ** Apply DELTA to FILE1 and output the result.
149 */
150 void delta_apply_cmd(void){
151 Blob orig, target, delta;
152 if( g.argc!=5 ){
153 usage("ORIGIN DELTA TARGET");
@@ -124,13 +164,16 @@
164 }
165 blob_reset(&orig);
166 blob_reset(&target);
167 blob_reset(&delta);
168 }
169
170
171 /*
172 ** COMMAND: test-delta
173 **
174 ** Usage: %fossil test-delta FILE1 FILE2
175 **
176 ** Read two files named on the command-line. Create and apply deltas
177 ** going in both directions. Verify that the original files are
178 ** correctly recovered.
179 */
180
+4 -3
--- src/doc.c
+++ src/doc.c
@@ -523,11 +523,11 @@
523523
** it gets checked in.
524524
**
525525
** The file extension is used to decide how to render the file.
526526
**
527527
** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki",
528
-** and "FILE/index.md" are in that order. If none of those are found,
528
+** and "FILE/index.md" are tried in that order. If none of those are found,
529529
** then FILE is completely replaced by "404.md" and tried. If that is
530530
** not found, then a default 404 screen is generated.
531531
*/
532532
void doc_page(void){
533533
const char *zName; /* Argument to the /doc page */
@@ -547,14 +547,15 @@
547547
login_check_credentials();
548548
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
549549
blob_init(&title, 0, 0);
550550
db_begin_transaction();
551551
while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){
552
- zName = PD("name", "tip/index.wiki");
552
+ zName = P("name");
553
+ if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki";
553554
for(i=0; zName[i] && zName[i]!='/'; i++){}
554555
zCheckin = mprintf("%.*s", i, zName);
555
- if( fossil_strcmp(zCheckin,"ckout")==0 && db_open_local(0)==0 ){
556
+ if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
556557
zCheckin = "tip";
557558
}
558559
if( nMiss==ArraySize(azSuffix) ){
559560
zName = "404.md";
560561
}else if( zName[i]==0 ){
561562
--- src/doc.c
+++ src/doc.c
@@ -523,11 +523,11 @@
523 ** it gets checked in.
524 **
525 ** The file extension is used to decide how to render the file.
526 **
527 ** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki",
528 ** and "FILE/index.md" are in that order. If none of those are found,
529 ** then FILE is completely replaced by "404.md" and tried. If that is
530 ** not found, then a default 404 screen is generated.
531 */
532 void doc_page(void){
533 const char *zName; /* Argument to the /doc page */
@@ -547,14 +547,15 @@
547 login_check_credentials();
548 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
549 blob_init(&title, 0, 0);
550 db_begin_transaction();
551 while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){
552 zName = PD("name", "tip/index.wiki");
 
553 for(i=0; zName[i] && zName[i]!='/'; i++){}
554 zCheckin = mprintf("%.*s", i, zName);
555 if( fossil_strcmp(zCheckin,"ckout")==0 && db_open_local(0)==0 ){
556 zCheckin = "tip";
557 }
558 if( nMiss==ArraySize(azSuffix) ){
559 zName = "404.md";
560 }else if( zName[i]==0 ){
561
--- src/doc.c
+++ src/doc.c
@@ -523,11 +523,11 @@
523 ** it gets checked in.
524 **
525 ** The file extension is used to decide how to render the file.
526 **
527 ** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki",
528 ** and "FILE/index.md" are tried in that order. If none of those are found,
529 ** then FILE is completely replaced by "404.md" and tried. If that is
530 ** not found, then a default 404 screen is generated.
531 */
532 void doc_page(void){
533 const char *zName; /* Argument to the /doc page */
@@ -547,14 +547,15 @@
547 login_check_credentials();
548 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
549 blob_init(&title, 0, 0);
550 db_begin_transaction();
551 while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){
552 zName = P("name");
553 if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki";
554 for(i=0; zName[i] && zName[i]!='/'; i++){}
555 zCheckin = mprintf("%.*s", i, zName);
556 if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
557 zCheckin = "tip";
558 }
559 if( nMiss==ArraySize(azSuffix) ){
560 zName = "404.md";
561 }else if( zName[i]==0 ){
562
+5 -4
--- src/foci.c
+++ src/foci.c
@@ -167,17 +167,18 @@
167167
){
168168
FociCursor *pCur = (FociCursor *)pCursor;
169169
manifest_destroy(pCur->pMan);
170170
if( idxNum ){
171171
pCur->pMan = manifest_get(sqlite3_value_int(argv[0]), CFTYPE_MANIFEST, 0);
172
- pCur->iFile = 0;
173
- manifest_file_rewind(pCur->pMan);
174
- pCur->pFile = manifest_file_next(pCur->pMan, 0);
172
+ if( pCur->pMan ){
173
+ manifest_file_rewind(pCur->pMan);
174
+ pCur->pFile = manifest_file_next(pCur->pMan, 0);
175
+ }
175176
}else{
176177
pCur->pMan = 0;
177
- pCur->iFile = 0;
178178
}
179
+ pCur->iFile = 0;
179180
return SQLITE_OK;
180181
}
181182
182183
static int fociColumn(
183184
sqlite3_vtab_cursor *pCursor,
184185
--- src/foci.c
+++ src/foci.c
@@ -167,17 +167,18 @@
167 ){
168 FociCursor *pCur = (FociCursor *)pCursor;
169 manifest_destroy(pCur->pMan);
170 if( idxNum ){
171 pCur->pMan = manifest_get(sqlite3_value_int(argv[0]), CFTYPE_MANIFEST, 0);
172 pCur->iFile = 0;
173 manifest_file_rewind(pCur->pMan);
174 pCur->pFile = manifest_file_next(pCur->pMan, 0);
 
175 }else{
176 pCur->pMan = 0;
177 pCur->iFile = 0;
178 }
 
179 return SQLITE_OK;
180 }
181
182 static int fociColumn(
183 sqlite3_vtab_cursor *pCursor,
184
--- src/foci.c
+++ src/foci.c
@@ -167,17 +167,18 @@
167 ){
168 FociCursor *pCur = (FociCursor *)pCursor;
169 manifest_destroy(pCur->pMan);
170 if( idxNum ){
171 pCur->pMan = manifest_get(sqlite3_value_int(argv[0]), CFTYPE_MANIFEST, 0);
172 if( pCur->pMan ){
173 manifest_file_rewind(pCur->pMan);
174 pCur->pFile = manifest_file_next(pCur->pMan, 0);
175 }
176 }else{
177 pCur->pMan = 0;
 
178 }
179 pCur->iFile = 0;
180 return SQLITE_OK;
181 }
182
183 static int fociColumn(
184 sqlite3_vtab_cursor *pCursor,
185
+1 -1
--- src/info.c
+++ src/info.c
@@ -1886,11 +1886,11 @@
18861886
}
18871887
if( descOnly ){
18881888
style_submenu_element("Content", "Content", "%R/artifact/%s", zUuid);
18891889
}else{
18901890
style_submenu_element("Line Numbers", "Line Numbers",
1891
- "%R/info/%s%s",zUuid,
1891
+ "%R/artifact/%s%s",zUuid,
18921892
((zLn&&*zLn) ? "" : "?txt=1&ln=0"));
18931893
@ <hr />
18941894
content_get(rid, &content);
18951895
if( renderAsWiki ){
18961896
wiki_render_by_mimetype(&content, zMime);
18971897
--- src/info.c
+++ src/info.c
@@ -1886,11 +1886,11 @@
1886 }
1887 if( descOnly ){
1888 style_submenu_element("Content", "Content", "%R/artifact/%s", zUuid);
1889 }else{
1890 style_submenu_element("Line Numbers", "Line Numbers",
1891 "%R/info/%s%s",zUuid,
1892 ((zLn&&*zLn) ? "" : "?txt=1&ln=0"));
1893 @ <hr />
1894 content_get(rid, &content);
1895 if( renderAsWiki ){
1896 wiki_render_by_mimetype(&content, zMime);
1897
--- src/info.c
+++ src/info.c
@@ -1886,11 +1886,11 @@
1886 }
1887 if( descOnly ){
1888 style_submenu_element("Content", "Content", "%R/artifact/%s", zUuid);
1889 }else{
1890 style_submenu_element("Line Numbers", "Line Numbers",
1891 "%R/artifact/%s%s",zUuid,
1892 ((zLn&&*zLn) ? "" : "?txt=1&ln=0"));
1893 @ <hr />
1894 content_get(rid, &content);
1895 if( renderAsWiki ){
1896 wiki_render_by_mimetype(&content, zMime);
1897
+1 -1
--- src/info.c
+++ src/info.c
@@ -1886,11 +1886,11 @@
18861886
}
18871887
if( descOnly ){
18881888
style_submenu_element("Content", "Content", "%R/artifact/%s", zUuid);
18891889
}else{
18901890
style_submenu_element("Line Numbers", "Line Numbers",
1891
- "%R/info/%s%s",zUuid,
1891
+ "%R/artifact/%s%s",zUuid,
18921892
((zLn&&*zLn) ? "" : "?txt=1&ln=0"));
18931893
@ <hr />
18941894
content_get(rid, &content);
18951895
if( renderAsWiki ){
18961896
wiki_render_by_mimetype(&content, zMime);
18971897
--- src/info.c
+++ src/info.c
@@ -1886,11 +1886,11 @@
1886 }
1887 if( descOnly ){
1888 style_submenu_element("Content", "Content", "%R/artifact/%s", zUuid);
1889 }else{
1890 style_submenu_element("Line Numbers", "Line Numbers",
1891 "%R/info/%s%s",zUuid,
1892 ((zLn&&*zLn) ? "" : "?txt=1&ln=0"));
1893 @ <hr />
1894 content_get(rid, &content);
1895 if( renderAsWiki ){
1896 wiki_render_by_mimetype(&content, zMime);
1897
--- src/info.c
+++ src/info.c
@@ -1886,11 +1886,11 @@
1886 }
1887 if( descOnly ){
1888 style_submenu_element("Content", "Content", "%R/artifact/%s", zUuid);
1889 }else{
1890 style_submenu_element("Line Numbers", "Line Numbers",
1891 "%R/artifact/%s%s",zUuid,
1892 ((zLn&&*zLn) ? "" : "?txt=1&ln=0"));
1893 @ <hr />
1894 content_get(rid, &content);
1895 if( renderAsWiki ){
1896 wiki_render_by_mimetype(&content, zMime);
1897
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -597,11 +597,11 @@
597597
#### The directories where the OpenSSL include and library files are located.
598598
# The recommended usage here is to use the Sysinternals junction tool
599599
# to create a hard link between an "openssl-1.x" sub-directory of the
600600
# Fossil source code directory and the target OpenSSL source directory.
601601
#
602
-OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2c
602
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2d
603603
OPENSSLINCDIR = $(OPENSSLDIR)/include
604604
OPENSSLLIBDIR = $(OPENSSLDIR)
605605
606606
#### Either the directory where the Tcl library is installed or the Tcl
607607
# source code directory resides (depending on the value of the macro
@@ -1324,11 +1324,11 @@
13241324
FOSSIL_BUILD_SSL = 0
13251325
!endif
13261326
13271327
# Build the included zlib library?
13281328
!ifndef FOSSIL_BUILD_ZLIB
1329
-FOSSIL_BUILD_ZLIB = 0
1329
+FOSSIL_BUILD_ZLIB = 1
13301330
!endif
13311331
13321332
# Link everything except SQLite dynamically?
13331333
!ifndef FOSSIL_DYNAMIC_BUILD
13341334
FOSSIL_DYNAMIC_BUILD = 0
@@ -1373,11 +1373,11 @@
13731373
!ifndef FOSSIL_ENABLE_WINXP
13741374
FOSSIL_ENABLE_WINXP = 0
13751375
!endif
13761376
13771377
!if $(FOSSIL_ENABLE_SSL)!=0
1378
-SSLDIR = $(B)\compat\openssl-1.0.2c
1378
+SSLDIR = $(B)\compat\openssl-1.0.2d
13791379
SSLINCDIR = $(SSLDIR)\inc32
13801380
!if $(FOSSIL_DYNAMIC_BUILD)!=0
13811381
SSLLIBDIR = $(SSLDIR)\out32dll
13821382
!else
13831383
SSLLIBDIR = $(SSLDIR)\out32
13841384
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -597,11 +597,11 @@
597 #### The directories where the OpenSSL include and library files are located.
598 # The recommended usage here is to use the Sysinternals junction tool
599 # to create a hard link between an "openssl-1.x" sub-directory of the
600 # Fossil source code directory and the target OpenSSL source directory.
601 #
602 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2c
603 OPENSSLINCDIR = $(OPENSSLDIR)/include
604 OPENSSLLIBDIR = $(OPENSSLDIR)
605
606 #### Either the directory where the Tcl library is installed or the Tcl
607 # source code directory resides (depending on the value of the macro
@@ -1324,11 +1324,11 @@
1324 FOSSIL_BUILD_SSL = 0
1325 !endif
1326
1327 # Build the included zlib library?
1328 !ifndef FOSSIL_BUILD_ZLIB
1329 FOSSIL_BUILD_ZLIB = 0
1330 !endif
1331
1332 # Link everything except SQLite dynamically?
1333 !ifndef FOSSIL_DYNAMIC_BUILD
1334 FOSSIL_DYNAMIC_BUILD = 0
@@ -1373,11 +1373,11 @@
1373 !ifndef FOSSIL_ENABLE_WINXP
1374 FOSSIL_ENABLE_WINXP = 0
1375 !endif
1376
1377 !if $(FOSSIL_ENABLE_SSL)!=0
1378 SSLDIR = $(B)\compat\openssl-1.0.2c
1379 SSLINCDIR = $(SSLDIR)\inc32
1380 !if $(FOSSIL_DYNAMIC_BUILD)!=0
1381 SSLLIBDIR = $(SSLDIR)\out32dll
1382 !else
1383 SSLLIBDIR = $(SSLDIR)\out32
1384
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -597,11 +597,11 @@
597 #### The directories where the OpenSSL include and library files are located.
598 # The recommended usage here is to use the Sysinternals junction tool
599 # to create a hard link between an "openssl-1.x" sub-directory of the
600 # Fossil source code directory and the target OpenSSL source directory.
601 #
602 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2d
603 OPENSSLINCDIR = $(OPENSSLDIR)/include
604 OPENSSLLIBDIR = $(OPENSSLDIR)
605
606 #### Either the directory where the Tcl library is installed or the Tcl
607 # source code directory resides (depending on the value of the macro
@@ -1324,11 +1324,11 @@
1324 FOSSIL_BUILD_SSL = 0
1325 !endif
1326
1327 # Build the included zlib library?
1328 !ifndef FOSSIL_BUILD_ZLIB
1329 FOSSIL_BUILD_ZLIB = 1
1330 !endif
1331
1332 # Link everything except SQLite dynamically?
1333 !ifndef FOSSIL_DYNAMIC_BUILD
1334 FOSSIL_DYNAMIC_BUILD = 0
@@ -1373,11 +1373,11 @@
1373 !ifndef FOSSIL_ENABLE_WINXP
1374 FOSSIL_ENABLE_WINXP = 0
1375 !endif
1376
1377 !if $(FOSSIL_ENABLE_SSL)!=0
1378 SSLDIR = $(B)\compat\openssl-1.0.2d
1379 SSLINCDIR = $(SSLDIR)\inc32
1380 !if $(FOSSIL_DYNAMIC_BUILD)!=0
1381 SSLLIBDIR = $(SSLDIR)\out32dll
1382 !else
1383 SSLLIBDIR = $(SSLDIR)\out32
1384
+5 -5
--- src/merge.c
+++ src/merge.c
@@ -592,11 +592,11 @@
592592
}
593593
if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
594594
fossil_print("***** Cannot merge symlink %s\n", zName);
595595
nConflict++;
596596
}else{
597
- undo_save(zName);
597
+ if( !dryRunFlag ) undo_save(zName);
598598
zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
599599
content_get(ridp, &p);
600600
content_get(ridm, &m);
601601
if( isBinary ){
602602
rc = -1;
@@ -643,11 +643,11 @@
643643
fossil_print("DELETE %s\n", zName);
644644
if( chnged ){
645645
fossil_warning("WARNING: local edits lost for %s\n", zName);
646646
nConflict++;
647647
}
648
- undo_save(zName);
648
+ if( !dryRunFlag ) undo_save(zName);
649649
db_multi_exec(
650650
"UPDATE vfile SET deleted=1 WHERE id=%d", idv
651651
);
652652
if( !dryRunFlag ){
653653
char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
@@ -669,12 +669,12 @@
669669
while( db_step(&q)==SQLITE_ROW ){
670670
int idv = db_column_int(&q, 0);
671671
const char *zOldName = db_column_text(&q, 1);
672672
const char *zNewName = db_column_text(&q, 2);
673673
fossil_print("RENAME %s -> %s\n", zOldName, zNewName);
674
- undo_save(zOldName);
675
- undo_save(zNewName);
674
+ if( !dryRunFlag ) undo_save(zOldName);
675
+ if( !dryRunFlag ) undo_save(zNewName);
676676
db_multi_exec(
677677
"UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
678678
" WHERE id=%d AND vid=%d", zNewName, idv, vid
679679
);
680680
if( !dryRunFlag ){
@@ -726,8 +726,8 @@
726726
}else if( integrateFlag ){
727727
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid);
728728
}else{
729729
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
730730
}
731
- undo_finish();
731
+ if( !dryRunFlag ) undo_finish();
732732
db_end_transaction(dryRunFlag);
733733
}
734734
--- src/merge.c
+++ src/merge.c
@@ -592,11 +592,11 @@
592 }
593 if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
594 fossil_print("***** Cannot merge symlink %s\n", zName);
595 nConflict++;
596 }else{
597 undo_save(zName);
598 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
599 content_get(ridp, &p);
600 content_get(ridm, &m);
601 if( isBinary ){
602 rc = -1;
@@ -643,11 +643,11 @@
643 fossil_print("DELETE %s\n", zName);
644 if( chnged ){
645 fossil_warning("WARNING: local edits lost for %s\n", zName);
646 nConflict++;
647 }
648 undo_save(zName);
649 db_multi_exec(
650 "UPDATE vfile SET deleted=1 WHERE id=%d", idv
651 );
652 if( !dryRunFlag ){
653 char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
@@ -669,12 +669,12 @@
669 while( db_step(&q)==SQLITE_ROW ){
670 int idv = db_column_int(&q, 0);
671 const char *zOldName = db_column_text(&q, 1);
672 const char *zNewName = db_column_text(&q, 2);
673 fossil_print("RENAME %s -> %s\n", zOldName, zNewName);
674 undo_save(zOldName);
675 undo_save(zNewName);
676 db_multi_exec(
677 "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
678 " WHERE id=%d AND vid=%d", zNewName, idv, vid
679 );
680 if( !dryRunFlag ){
@@ -726,8 +726,8 @@
726 }else if( integrateFlag ){
727 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid);
728 }else{
729 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
730 }
731 undo_finish();
732 db_end_transaction(dryRunFlag);
733 }
734
--- src/merge.c
+++ src/merge.c
@@ -592,11 +592,11 @@
592 }
593 if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
594 fossil_print("***** Cannot merge symlink %s\n", zName);
595 nConflict++;
596 }else{
597 if( !dryRunFlag ) undo_save(zName);
598 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
599 content_get(ridp, &p);
600 content_get(ridm, &m);
601 if( isBinary ){
602 rc = -1;
@@ -643,11 +643,11 @@
643 fossil_print("DELETE %s\n", zName);
644 if( chnged ){
645 fossil_warning("WARNING: local edits lost for %s\n", zName);
646 nConflict++;
647 }
648 if( !dryRunFlag ) undo_save(zName);
649 db_multi_exec(
650 "UPDATE vfile SET deleted=1 WHERE id=%d", idv
651 );
652 if( !dryRunFlag ){
653 char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
@@ -669,12 +669,12 @@
669 while( db_step(&q)==SQLITE_ROW ){
670 int idv = db_column_int(&q, 0);
671 const char *zOldName = db_column_text(&q, 1);
672 const char *zNewName = db_column_text(&q, 2);
673 fossil_print("RENAME %s -> %s\n", zOldName, zNewName);
674 if( !dryRunFlag ) undo_save(zOldName);
675 if( !dryRunFlag ) undo_save(zNewName);
676 db_multi_exec(
677 "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
678 " WHERE id=%d AND vid=%d", zNewName, idv, vid
679 );
680 if( !dryRunFlag ){
@@ -726,8 +726,8 @@
726 }else if( integrateFlag ){
727 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid);
728 }else{
729 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
730 }
731 if( !dryRunFlag ) undo_finish();
732 db_end_transaction(dryRunFlag);
733 }
734
+233 -92
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -325,11 +325,11 @@
325325
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
326326
** [sqlite_version()] and [sqlite_source_id()].
327327
*/
328328
#define SQLITE_VERSION "3.8.11"
329329
#define SQLITE_VERSION_NUMBER 3008011
330
-#define SQLITE_SOURCE_ID "2015-07-03 17:54:49 030f60a7ba171650ce8c0ac32dc166eab80aca32"
330
+#define SQLITE_SOURCE_ID "2015-07-08 16:22:42 5348ffc3fda5168c1e9e14aa88b0c6aedbda7c94"
331331
332332
/*
333333
** CAPI3REF: Run-Time Library Version Numbers
334334
** KEYWORDS: sqlite3_version, sqlite3_sourceid
335335
**
@@ -6503,10 +6503,13 @@
65036503
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
65046504
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
65056505
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
65066506
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
65076507
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
6508
+#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
6509
+#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
6510
+#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
65086511
65096512
/*
65106513
** CAPI3REF: Retrieve the mutex for a database connection
65116514
** METHOD: sqlite3
65126515
**
@@ -8941,10 +8944,20 @@
89418944
#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS
89428945
# undef SQLITE_MAX_WORKER_THREADS
89438946
# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
89448947
#endif
89458948
8949
+/*
8950
+** The default initial allocation for the pagecache when using separate
8951
+** pagecaches for each database connection. A positive number is the
8952
+** number of pages. A negative number N translations means that a buffer
8953
+** of -1024*N bytes is allocated and used for as many pages as it will hold.
8954
+*/
8955
+#ifndef SQLITE_DEFAULT_PCACHE_INITSZ
8956
+# define SQLITE_DEFAULT_PCACHE_INITSZ 100
8957
+#endif
8958
+
89468959
89478960
/*
89488961
** GCC does not define the offsetof() macro so we'll have to do it
89498962
** ourselves.
89508963
*/
@@ -14043,11 +14056,11 @@
1404314056
(void*)0, /* pScratch */
1404414057
0, /* szScratch */
1404514058
0, /* nScratch */
1404614059
(void*)0, /* pPage */
1404714060
0, /* szPage */
14048
- 0, /* nPage */
14061
+ SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
1404914062
0, /* mxParserStack */
1405014063
0, /* sharedCacheEnabled */
1405114064
SQLITE_SORTER_PMASZ, /* szPma */
1405214065
/* All the rest should always be initialized to zero */
1405314066
0, /* isInit */
@@ -19454,11 +19467,11 @@
1945419467
** The sqlite3_mutex_alloc() routine allocates a new
1945519468
** mutex and returns a pointer to it. If it returns NULL
1945619469
** that means that a mutex could not be allocated.
1945719470
*/
1945819471
static sqlite3_mutex *debugMutexAlloc(int id){
19459
- static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
19472
+ static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1];
1946019473
sqlite3_debug_mutex *pNew = 0;
1946119474
switch( id ){
1946219475
case SQLITE_MUTEX_FAST:
1946319476
case SQLITE_MUTEX_RECURSIVE: {
1946419477
pNew = sqlite3Malloc(sizeof(*pNew));
@@ -19669,10 +19682,13 @@
1966919682
** <li> SQLITE_MUTEX_STATIC_LRU
1967019683
** <li> SQLITE_MUTEX_STATIC_PMEM
1967119684
** <li> SQLITE_MUTEX_STATIC_APP1
1967219685
** <li> SQLITE_MUTEX_STATIC_APP2
1967319686
** <li> SQLITE_MUTEX_STATIC_APP3
19687
+** <li> SQLITE_MUTEX_STATIC_VFS1
19688
+** <li> SQLITE_MUTEX_STATIC_VFS2
19689
+** <li> SQLITE_MUTEX_STATIC_VFS3
1967419690
** </ul>
1967519691
**
1967619692
** The first two constants cause sqlite3_mutex_alloc() to create
1967719693
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
1967819694
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -19697,10 +19713,13 @@
1969719713
** mutex types, the same mutex is returned on every call that has
1969819714
** the same type number.
1969919715
*/
1970019716
static sqlite3_mutex *pthreadMutexAlloc(int iType){
1970119717
static sqlite3_mutex staticMutexes[] = {
19718
+ SQLITE3_MUTEX_INITIALIZER,
19719
+ SQLITE3_MUTEX_INITIALIZER,
19720
+ SQLITE3_MUTEX_INITIALIZER,
1970219721
SQLITE3_MUTEX_INITIALIZER,
1970319722
SQLITE3_MUTEX_INITIALIZER,
1970419723
SQLITE3_MUTEX_INITIALIZER,
1970519724
SQLITE3_MUTEX_INITIALIZER,
1970619725
SQLITE3_MUTEX_INITIALIZER,
@@ -20311,10 +20330,13 @@
2031120330
SQLITE3_MUTEX_INITIALIZER,
2031220331
SQLITE3_MUTEX_INITIALIZER,
2031320332
SQLITE3_MUTEX_INITIALIZER,
2031420333
SQLITE3_MUTEX_INITIALIZER,
2031520334
SQLITE3_MUTEX_INITIALIZER,
20335
+ SQLITE3_MUTEX_INITIALIZER,
20336
+ SQLITE3_MUTEX_INITIALIZER,
20337
+ SQLITE3_MUTEX_INITIALIZER,
2031620338
SQLITE3_MUTEX_INITIALIZER
2031720339
};
2031820340
2031920341
static int winMutex_isInit = 0;
2032020342
static int winMutex_isNt = -1; /* <0 means "need to query" */
@@ -20382,10 +20404,13 @@
2038220404
** <li> SQLITE_MUTEX_STATIC_LRU
2038320405
** <li> SQLITE_MUTEX_STATIC_PMEM
2038420406
** <li> SQLITE_MUTEX_STATIC_APP1
2038520407
** <li> SQLITE_MUTEX_STATIC_APP2
2038620408
** <li> SQLITE_MUTEX_STATIC_APP3
20409
+** <li> SQLITE_MUTEX_STATIC_VFS1
20410
+** <li> SQLITE_MUTEX_STATIC_VFS2
20411
+** <li> SQLITE_MUTEX_STATIC_VFS3
2038720412
** </ul>
2038820413
**
2038920414
** The first two constants cause sqlite3_mutex_alloc() to create
2039020415
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
2039120416
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -20793,14 +20818,13 @@
2079320818
sqlite3GlobalConfig.pScratch = 0;
2079420819
sqlite3GlobalConfig.szScratch = 0;
2079520820
sqlite3GlobalConfig.nScratch = 0;
2079620821
}
2079720822
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
20798
- || sqlite3GlobalConfig.nPage<1 ){
20823
+ || sqlite3GlobalConfig.nPage<=0 ){
2079920824
sqlite3GlobalConfig.pPage = 0;
2080020825
sqlite3GlobalConfig.szPage = 0;
20801
- sqlite3GlobalConfig.nPage = 0;
2080220826
}
2080320827
rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
2080420828
if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
2080520829
return rc;
2080620830
}
@@ -26522,18 +26546,18 @@
2652226546
** unixEnterMutex()
2652326547
** assert( unixMutexHeld() );
2652426548
** unixEnterLeave()
2652526549
*/
2652626550
static void unixEnterMutex(void){
26527
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
26551
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
2652826552
}
2652926553
static void unixLeaveMutex(void){
26530
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
26554
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
2653126555
}
2653226556
#ifdef SQLITE_DEBUG
2653326557
static int unixMutexHeld(void) {
26534
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
26558
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
2653526559
}
2653626560
#endif
2653726561
2653826562
2653926563
#ifdef SQLITE_HAVE_OS_TRACE
@@ -37047,18 +37071,18 @@
3704737071
** winShmEnterMutex()
3704837072
** assert( winShmMutexHeld() );
3704937073
** winShmLeaveMutex()
3705037074
*/
3705137075
static void winShmEnterMutex(void){
37052
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
37076
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
3705337077
}
3705437078
static void winShmLeaveMutex(void){
37055
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
37079
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
3705637080
}
3705737081
#ifndef NDEBUG
3705837082
static int winShmMutexHeld(void) {
37059
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
37083
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
3706037084
}
3706137085
#endif
3706237086
3706337087
/*
3706437088
** Object used to represent a single file opened and mmapped to provide
@@ -40399,12 +40423,75 @@
4039940423
** This file implements the default page cache implementation (the
4040040424
** sqlite3_pcache interface). It also contains part of the implementation
4040140425
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
4040240426
** If the default page cache implementation is overridden, then neither of
4040340427
** these two features are available.
40428
+**
40429
+** A Page cache line looks like this:
40430
+**
40431
+** -------------------------------------------------------------
40432
+** | database page content | PgHdr1 | MemPage | PgHdr |
40433
+** -------------------------------------------------------------
40434
+**
40435
+** The database page content is up front (so that buffer overreads tend to
40436
+** flow harmlessly into the PgHdr1, MemPage, and PgHdr extensions). MemPage
40437
+** is the extension added by the btree.c module containing information such
40438
+** as the database page number and how that database page is used. PgHdr
40439
+** is added by the pcache.c layer and contains information used to keep track
40440
+** of which pages are "dirty". PgHdr1 is an extension added by this
40441
+** module (pcache1.c). The PgHdr1 header is a subclass of sqlite3_pcache_page.
40442
+** PgHdr1 contains information needed to look up a page by its page number.
40443
+** The superclass sqlite3_pcache_page.pBuf points to the start of the
40444
+** database page content and sqlite3_pcache_page.pExtra points to PgHdr.
40445
+**
40446
+** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at
40447
+** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The
40448
+** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this
40449
+** size can vary according to architecture, compile-time options, and
40450
+** SQLite library version number.
40451
+**
40452
+** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
40453
+** using a separate memory allocation from the database page content. This
40454
+** seeks to overcome the "clownshoe" problem (also called "internal
40455
+** fragmentation" in academic literature) of allocating a few bytes more
40456
+** than a power of two with the memory allocator rounding up to the next
40457
+** power of two, and leaving the rounded-up space unused.
40458
+**
40459
+** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
40460
+** with this module. Information is passed back and forth as PgHdr1 pointers.
40461
+**
40462
+** The pcache.c and pager.c modules deal pointers to PgHdr objects.
40463
+** The btree.c module deals with pointers to MemPage objects.
40464
+**
40465
+** SOURCE OF PAGE CACHE MEMORY:
40466
+**
40467
+** Memory for a page might come from any of three sources:
40468
+**
40469
+** (1) The general-purpose memory allocator - sqlite3Malloc()
40470
+** (2) Global page-cache memory provided using sqlite3_config() with
40471
+** SQLITE_CONFIG_PAGECACHE.
40472
+** (3) PCache-local bulk allocation.
40473
+**
40474
+** The third case is a chunk of heap memory (defaulting to 100 pages worth)
40475
+** that is allocated when the page cache is created. The size of the local
40476
+** bulk allocation can be adjusted using
40477
+**
40478
+** sqlite3_config(SQLITE_CONFIG_PCACHE, 0, 0, N).
40479
+**
40480
+** If N is positive, then N pages worth of memory are allocated using a single
40481
+** sqlite3Malloc() call and that memory is used for the first N pages allocated.
40482
+** Or if N is negative, then -1024*N bytes of memory are allocated and used
40483
+** for as many pages as can be accomodated.
40484
+**
40485
+** Only one of (2) or (3) can be used. Once the memory available to (2) or
40486
+** (3) is exhausted, subsequent allocations fail over to the general-purpose
40487
+** memory allocator (1).
40488
+**
40489
+** Earlier versions of SQLite used only methods (1) and (2). But experiments
40490
+** show that method (3) with N==100 provides about a 5% performance boost for
40491
+** common workloads.
4040440492
*/
40405
-
4040640493
4040740494
typedef struct PCache1 PCache1;
4040840495
typedef struct PgHdr1 PgHdr1;
4040940496
typedef struct PgFreeslot PgFreeslot;
4041040497
typedef struct PGroup PGroup;
@@ -40453,12 +40540,13 @@
4045340540
** flag (bPurgeable) are set when the cache is created. nMax may be
4045440541
** modified at any time by a call to the pcache1Cachesize() method.
4045540542
** The PGroup mutex must be held when accessing nMax.
4045640543
*/
4045740544
PGroup *pGroup; /* PGroup this cache belongs to */
40458
- int szPage; /* Size of allocated pages in bytes */
40459
- int szExtra; /* Size of extra space in bytes */
40545
+ int szPage; /* Size of database content section */
40546
+ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
40547
+ int szAlloc; /* Total size of one pcache line */
4046040548
int bPurgeable; /* True if cache is purgeable */
4046140549
unsigned int nMin; /* Minimum number of pages reserved */
4046240550
unsigned int nMax; /* Configured "cache_size" value */
4046340551
unsigned int n90pct; /* nMax*9/10 */
4046440552
unsigned int iMaxKey; /* Largest key seen since xTruncate() */
@@ -40468,10 +40556,12 @@
4046840556
*/
4046940557
unsigned int nRecyclable; /* Number of pages in the LRU list */
4047040558
unsigned int nPage; /* Total number of pages in apHash */
4047140559
unsigned int nHash; /* Number of slots in apHash[] */
4047240560
PgHdr1 **apHash; /* Hash table for fast lookup by key */
40561
+ PgHdr1 *pFree; /* List of unused pcache-local pages */
40562
+ void *pBulk; /* Bulk memory used by pcache-local */
4047340563
};
4047440564
4047540565
/*
4047640566
** Each cache entry is represented by an instance of the following
4047740567
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
@@ -40480,19 +40570,20 @@
4048040570
*/
4048140571
struct PgHdr1 {
4048240572
sqlite3_pcache_page page;
4048340573
unsigned int iKey; /* Key value (page number) */
4048440574
u8 isPinned; /* Page in use, not on the LRU list */
40575
+ u8 isBulkLocal; /* This page from bulk local storage */
4048540576
PgHdr1 *pNext; /* Next in hash table chain */
4048640577
PCache1 *pCache; /* Cache that currently owns this page */
4048740578
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
4048840579
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
4048940580
};
4049040581
4049140582
/*
40492
-** Free slots in the allocator used to divide up the buffer provided using
40493
-** the SQLITE_CONFIG_PAGECACHE mechanism.
40583
+** Free slots in the allocator used to divide up the global page cache
40584
+** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
4049440585
*/
4049540586
struct PgFreeslot {
4049640587
PgFreeslot *pNext; /* Next free slot */
4049740588
};
4049840589
@@ -40506,14 +40597,15 @@
4050640597
** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
4050740598
** fixed at sqlite3_initialize() time and do not require mutex protection.
4050840599
** The nFreeSlot and pFree values do require mutex protection.
4050940600
*/
4051040601
int isInit; /* True if initialized */
40602
+ int separateCache; /* Use a new PGroup for each PCache */
4051140603
int szSlot; /* Size of each free slot */
4051240604
int nSlot; /* The number of pcache slots */
4051340605
int nReserve; /* Try to keep nFreeSlot above this */
40514
- void *pStart, *pEnd; /* Bounds of pagecache malloc range */
40606
+ void *pStart, *pEnd; /* Bounds of global page cache memory */
4051540607
/* Above requires no mutex. Use mutex below for variable that follow. */
4051640608
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
4051740609
PgFreeslot *pFree; /* Free page blocks */
4051840610
int nFreeSlot; /* Number of unused pcache slots */
4051940611
/* The following value requires a mutex to change. We skip the mutex on
@@ -40556,10 +40648,11 @@
4055640648
** to be serialized already. There is no need for further mutexing.
4055740649
*/
4055840650
SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
4055940651
if( pcache1.isInit ){
4056040652
PgFreeslot *p;
40653
+ if( pBuf==0 ) sz = n = 0;
4056140654
sz = ROUNDDOWN8(sz);
4056240655
pcache1.szSlot = sz;
4056340656
pcache1.nSlot = pcache1.nFreeSlot = n;
4056440657
pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
4056540658
pcache1.pStart = pBuf;
@@ -40620,13 +40713,13 @@
4062040713
}
4062140714
4062240715
/*
4062340716
** Free an allocated buffer obtained from pcache1Alloc().
4062440717
*/
40625
-static int pcache1Free(void *p){
40718
+static void pcache1Free(void *p){
4062640719
int nFreed = 0;
40627
- if( p==0 ) return 0;
40720
+ if( p==0 ) return;
4062840721
if( p>=pcache1.pStart && p<pcache1.pEnd ){
4062940722
PgFreeslot *pSlot;
4063040723
sqlite3_mutex_enter(pcache1.mutex);
4063140724
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
4063240725
pSlot = (PgFreeslot*)p;
@@ -40637,19 +40730,18 @@
4063740730
assert( pcache1.nFreeSlot<=pcache1.nSlot );
4063840731
sqlite3_mutex_leave(pcache1.mutex);
4063940732
}else{
4064040733
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
4064140734
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
40642
- nFreed = sqlite3MallocSize(p);
4064340735
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
40736
+ nFreed = sqlite3MallocSize(p);
4064440737
sqlite3_mutex_enter(pcache1.mutex);
4064540738
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
4064640739
sqlite3_mutex_leave(pcache1.mutex);
4064740740
#endif
4064840741
sqlite3_free(p);
4064940742
}
40650
- return nFreed;
4065140743
}
4065240744
4065340745
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
4065440746
/*
4065540747
** Return the size of a pcache allocation
@@ -40673,58 +40765,69 @@
4067340765
*/
4067440766
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
4067540767
PgHdr1 *p = 0;
4067640768
void *pPg;
4067740769
40678
- /* The group mutex must be released before pcache1Alloc() is called. This
40679
- ** is because it may call sqlite3_release_memory(), which assumes that
40680
- ** this mutex is not held. */
4068140770
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
40682
- pcache1LeaveMutex(pCache->pGroup);
40771
+ if( pCache->pFree ){
40772
+ p = pCache->pFree;
40773
+ pCache->pFree = p->pNext;
40774
+ p->pNext = 0;
40775
+ }else{
40776
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40777
+ /* The group mutex must be released before pcache1Alloc() is called. This
40778
+ ** is because it might call sqlite3_release_memory(), which assumes that
40779
+ ** this mutex is not held. */
40780
+ assert( pcache1.separateCache==0 );
40781
+ assert( pCache->pGroup==&pcache1.grp );
40782
+ pcache1LeaveMutex(pCache->pGroup);
40783
+#endif
4068340784
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
40684
- pPg = pcache1Alloc(pCache->szPage);
40685
- p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
40686
- if( !pPg || !p ){
40687
- pcache1Free(pPg);
40688
- sqlite3_free(p);
40689
- pPg = 0;
40690
- }
40785
+ pPg = pcache1Alloc(pCache->szPage);
40786
+ p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
40787
+ if( !pPg || !p ){
40788
+ pcache1Free(pPg);
40789
+ sqlite3_free(p);
40790
+ pPg = 0;
40791
+ }
4069140792
#else
40692
- pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
40693
- p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
40793
+ pPg = pcache1Alloc(pCache->szAlloc);
40794
+ p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
4069440795
#endif
40695
- pcache1EnterMutex(pCache->pGroup);
40696
-
40697
- if( pPg ){
40796
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40797
+ pcache1EnterMutex(pCache->pGroup);
40798
+#endif
40799
+ if( pPg==0 ) return 0;
4069840800
p->page.pBuf = pPg;
4069940801
p->page.pExtra = &p[1];
40700
- if( pCache->bPurgeable ){
40701
- pCache->pGroup->nCurrentPage++;
40702
- }
40703
- return p;
40802
+ p->isBulkLocal = 0;
4070440803
}
40705
- return 0;
40804
+ if( pCache->bPurgeable ){
40805
+ pCache->pGroup->nCurrentPage++;
40806
+ }
40807
+ return p;
4070640808
}
4070740809
4070840810
/*
4070940811
** Free a page object allocated by pcache1AllocPage().
40710
-**
40711
-** The pointer is allowed to be NULL, which is prudent. But it turns out
40712
-** that the current implementation happens to never call this routine
40713
-** with a NULL pointer, so we mark the NULL test with ALWAYS().
4071440812
*/
4071540813
static void pcache1FreePage(PgHdr1 *p){
40716
- if( ALWAYS(p) ){
40717
- PCache1 *pCache = p->pCache;
40718
- assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
40814
+ PCache1 *pCache;
40815
+ assert( p!=0 );
40816
+ pCache = p->pCache;
40817
+ assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
40818
+ if( p->isBulkLocal ){
40819
+ p->pNext = pCache->pFree;
40820
+ pCache->pFree = p;
40821
+ }else{
4071940822
pcache1Free(p->page.pBuf);
4072040823
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
4072140824
sqlite3_free(p);
4072240825
#endif
40723
- if( pCache->bPurgeable ){
40724
- pCache->pGroup->nCurrentPage--;
40725
- }
40826
+ }
40827
+ if( pCache->bPurgeable ){
40828
+ pCache->pGroup->nCurrentPage--;
4072640829
}
4072740830
}
4072840831
4072940832
/*
4073040833
** Malloc function used by SQLite to obtain space from the buffer configured
@@ -40920,10 +41023,35 @@
4092041023
*/
4092141024
static int pcache1Init(void *NotUsed){
4092241025
UNUSED_PARAMETER(NotUsed);
4092341026
assert( pcache1.isInit==0 );
4092441027
memset(&pcache1, 0, sizeof(pcache1));
41028
+
41029
+
41030
+ /*
41031
+ ** The pcache1.separateCache variable is true if each PCache has its own
41032
+ ** private PGroup (mode-1). pcache1.separateCache is false if the single
41033
+ ** PGroup in pcache1.grp is used for all page caches (mode-2).
41034
+ **
41035
+ ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
41036
+ **
41037
+ ** * Use a unified cache in single-threaded applications that have
41038
+ ** configured a start-time buffer for use as page-cache memory using
41039
+ ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
41040
+ ** pBuf argument.
41041
+ **
41042
+ ** * Otherwise use separate caches (mode-1)
41043
+ */
41044
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
41045
+ pcache1.separateCache = 0;
41046
+#elif SQLITE_THREADSAFE
41047
+ pcache1.separateCache = sqlite3GlobalConfig.pPage==0
41048
+ || sqlite3GlobalConfig.bCoreMutex>0;
41049
+#else
41050
+ pcache1.separateCache = sqlite3GlobalConfig.pPage==0;
41051
+#endif
41052
+
4092541053
#if SQLITE_THREADSAFE
4092641054
if( sqlite3GlobalConfig.bCoreMutex ){
4092741055
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
4092841056
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
4092941057
}
@@ -40955,52 +41083,65 @@
4095541083
static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
4095641084
PCache1 *pCache; /* The newly created page cache */
4095741085
PGroup *pGroup; /* The group the new page cache will belong to */
4095841086
int sz; /* Bytes of memory required to allocate the new cache */
4095941087
40960
- /*
40961
- ** The separateCache variable is true if each PCache has its own private
40962
- ** PGroup. In other words, separateCache is true for mode (1) where no
40963
- ** mutexing is required.
40964
- **
40965
- ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
40966
- **
40967
- ** * Always use a unified cache in single-threaded applications
40968
- **
40969
- ** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
40970
- ** use separate caches (mode-1)
40971
- */
40972
-#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
40973
- const int separateCache = 0;
40974
-#else
40975
- int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
40976
-#endif
40977
-
4097841088
assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
4097941089
assert( szExtra < 300 );
4098041090
40981
- sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
41091
+ sz = sizeof(PCache1) + sizeof(PGroup)*pcache1.separateCache;
4098241092
pCache = (PCache1 *)sqlite3MallocZero(sz);
4098341093
if( pCache ){
40984
- if( separateCache ){
41094
+ if( pcache1.separateCache ){
4098541095
pGroup = (PGroup*)&pCache[1];
4098641096
pGroup->mxPinned = 10;
4098741097
}else{
4098841098
pGroup = &pcache1.grp;
4098941099
}
4099041100
pCache->pGroup = pGroup;
4099141101
pCache->szPage = szPage;
4099241102
pCache->szExtra = szExtra;
41103
+ pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1));
4099341104
pCache->bPurgeable = (bPurgeable ? 1 : 0);
4099441105
pcache1EnterMutex(pGroup);
4099541106
pcache1ResizeHash(pCache);
4099641107
if( bPurgeable ){
4099741108
pCache->nMin = 10;
4099841109
pGroup->nMinPage += pCache->nMin;
4099941110
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
4100041111
}
4100141112
pcache1LeaveMutex(pGroup);
41113
+ /* Try to initialize the local bulk pagecache line allocation if using
41114
+ ** separate caches and if nPage!=0 */
41115
+ if( pcache1.separateCache
41116
+ && sqlite3GlobalConfig.nPage!=0
41117
+ && sqlite3GlobalConfig.pPage==0
41118
+ ){
41119
+ int szBulk;
41120
+ char *zBulk;
41121
+ sqlite3BeginBenignMalloc();
41122
+ if( sqlite3GlobalConfig.nPage>0 ){
41123
+ szBulk = pCache->szAlloc * sqlite3GlobalConfig.nPage;
41124
+ }else{
41125
+ szBulk = -1024*sqlite3GlobalConfig.nPage;
41126
+ }
41127
+ zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
41128
+ sqlite3EndBenignMalloc();
41129
+ if( zBulk ){
41130
+ int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
41131
+ int i;
41132
+ for(i=0; i<nBulk; i++){
41133
+ PgHdr1 *pX = (PgHdr1*)&zBulk[szPage];
41134
+ pX->page.pBuf = zBulk;
41135
+ pX->page.pExtra = &pX[1];
41136
+ pX->isBulkLocal = 1;
41137
+ pX->pNext = pCache->pFree;
41138
+ pCache->pFree = pX;
41139
+ zBulk += pCache->szAlloc;
41140
+ }
41141
+ }
41142
+ }
4100241143
if( pCache->nHash==0 ){
4100341144
pcache1Destroy((sqlite3_pcache*)pCache);
4100441145
pCache = 0;
4100541146
}
4100641147
}
@@ -41090,30 +41231,21 @@
4109041231
4109141232
if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
4109241233
assert( pCache->nHash>0 && pCache->apHash );
4109341234
4109441235
/* Step 4. Try to recycle a page. */
41095
- if( pCache->bPurgeable && pGroup->pLruTail && (
41096
- (pCache->nPage+1>=pCache->nMax)
41097
- || pGroup->nCurrentPage>=pGroup->nMaxPage
41098
- || pcache1UnderMemoryPressure(pCache)
41099
- )){
41236
+ if( pCache->bPurgeable
41237
+ && pGroup->pLruTail
41238
+ && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache))
41239
+ ){
4110041240
PCache1 *pOther;
4110141241
pPage = pGroup->pLruTail;
4110241242
assert( pPage->isPinned==0 );
4110341243
pcache1RemoveFromHash(pPage, 0);
4110441244
pcache1PinPage(pPage);
4110541245
pOther = pPage->pCache;
41106
-
41107
- /* We want to verify that szPage and szExtra are the same for pOther
41108
- ** and pCache. Assert that we can verify this by comparing sums. */
41109
- assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
41110
- assert( pCache->szExtra<512 );
41111
- assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
41112
- assert( pOther->szExtra<512 );
41113
-
41114
- if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
41246
+ if( pOther->szAlloc != pCache->szAlloc ){
4111541247
pcache1FreePage(pPage);
4111641248
pPage = 0;
4111741249
}else{
4111841250
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
4111941251
}
@@ -41385,10 +41517,11 @@
4138541517
assert( pGroup->nMinPage >= pCache->nMin );
4138641518
pGroup->nMinPage -= pCache->nMin;
4138741519
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
4138841520
pcache1EnforceMaxPage(pGroup);
4138941521
pcache1LeaveMutex(pGroup);
41522
+ sqlite3_free(pCache->pBulk);
4139041523
sqlite3_free(pCache->apHash);
4139141524
sqlite3_free(pCache);
4139241525
}
4139341526
4139441527
/*
@@ -41440,11 +41573,11 @@
4144041573
*/
4144141574
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
4144241575
int nFree = 0;
4144341576
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
4144441577
assert( sqlite3_mutex_notheld(pcache1.mutex) );
41445
- if( pcache1.pStart==0 ){
41578
+ if( sqlite3GlobalConfig.nPage==0 ){
4144641579
PgHdr1 *p;
4144741580
pcache1EnterMutex(&pcache1.grp);
4144841581
while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
4144941582
nFree += pcache1MemSize(p->page.pBuf);
4145041583
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
@@ -62542,10 +62675,11 @@
6254262675
u32 *heap = 0; /* Min-heap used for checking cell coverage */
6254362676
u32 x, prev = 0; /* Next and previous entry on the min-heap */
6254462677
const char *saved_zPfx = pCheck->zPfx;
6254562678
int saved_v1 = pCheck->v1;
6254662679
int saved_v2 = pCheck->v2;
62680
+ u8 savedIsInit;
6254762681
6254862682
/* Check that the page exists
6254962683
*/
6255062684
pBt = pCheck->pBt;
6255162685
usableSize = pBt->usableSize;
@@ -62559,10 +62693,11 @@
6255962693
goto end_of_check;
6256062694
}
6256162695
6256262696
/* Clear MemPage.isInit to make sure the corruption detection code in
6256362697
** btreeInitPage() is executed. */
62698
+ savedIsInit = pPage->isInit;
6256462699
pPage->isInit = 0;
6256562700
if( (rc = btreeInitPage(pPage))!=0 ){
6256662701
assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
6256762702
checkAppendMsg(pCheck,
6256862703
"btreeInitPage() returns error code %d", rc);
@@ -62700,11 +62835,11 @@
6270062835
while( i>0 ){
6270162836
int size, j;
6270262837
assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */
6270362838
size = get2byte(&data[i+2]);
6270462839
assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */
62705
- btreeHeapInsert(heap, (i<<16)|(i+size-1));
62840
+ btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1));
6270662841
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
6270762842
** big-endian integer which is the offset in the b-tree page of the next
6270862843
** freeblock in the chain, or zero if the freeblock is the last on the
6270962844
** chain. */
6271062845
j = get2byte(&data[i]);
@@ -62751,10 +62886,11 @@
6275162886
nFrag, data[hdr+7], iPage);
6275262887
}
6275362888
}
6275462889
6275562890
end_of_check:
62891
+ if( !doCoverageCheck ) pPage->isInit = savedIsInit;
6275662892
releasePage(pPage);
6275762893
pCheck->zPfx = saved_zPfx;
6275862894
pCheck->v1 = saved_v1;
6275962895
pCheck->v2 = saved_v2;
6276062896
return depth+1;
@@ -69020,10 +69156,11 @@
6902069156
** to ignore the compiler warnings and leave this variable uninitialized.
6902169157
*/
6902269158
/* mem1.u.i = 0; // not needed, here to silence compiler warning */
6902369159
6902469160
idx1 = getVarint32(aKey1, szHdr1);
69161
+ if( szHdr1>98307 ) return SQLITE_CORRUPT;
6902569162
d1 = szHdr1;
6902669163
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
6902769164
assert( pKeyInfo->aSortOrder!=0 );
6902869165
assert( pKeyInfo->nField>0 );
6902969166
assert( idx1<=szHdr1 || CORRUPT_DB );
@@ -109379,14 +109516,18 @@
109379109516
sqlite3VdbeResolveLabel(v, addrCont);
109380109517
109381109518
/* Execute the recursive SELECT taking the single row in Current as
109382109519
** the value for the recursive-table. Store the results in the Queue.
109383109520
*/
109384
- p->pPrior = 0;
109385
- sqlite3Select(pParse, p, &destQueue);
109386
- assert( p->pPrior==0 );
109387
- p->pPrior = pSetup;
109521
+ if( p->selFlags & SF_Aggregate ){
109522
+ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
109523
+ }else{
109524
+ p->pPrior = 0;
109525
+ sqlite3Select(pParse, p, &destQueue);
109526
+ assert( p->pPrior==0 );
109527
+ p->pPrior = pSetup;
109528
+ }
109388109529
109389109530
/* Keep running the loop until the Queue is empty */
109390109531
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
109391109532
sqlite3VdbeResolveLabel(v, addrBreak);
109392109533
109393109534
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -325,11 +325,11 @@
325 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
326 ** [sqlite_version()] and [sqlite_source_id()].
327 */
328 #define SQLITE_VERSION "3.8.11"
329 #define SQLITE_VERSION_NUMBER 3008011
330 #define SQLITE_SOURCE_ID "2015-07-03 17:54:49 030f60a7ba171650ce8c0ac32dc166eab80aca32"
331
332 /*
333 ** CAPI3REF: Run-Time Library Version Numbers
334 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
335 **
@@ -6503,10 +6503,13 @@
6503 #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
6504 #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
6505 #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
6506 #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
6507 #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
 
 
 
6508
6509 /*
6510 ** CAPI3REF: Retrieve the mutex for a database connection
6511 ** METHOD: sqlite3
6512 **
@@ -8941,10 +8944,20 @@
8941 #if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS
8942 # undef SQLITE_MAX_WORKER_THREADS
8943 # define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
8944 #endif
8945
 
 
 
 
 
 
 
 
 
 
8946
8947 /*
8948 ** GCC does not define the offsetof() macro so we'll have to do it
8949 ** ourselves.
8950 */
@@ -14043,11 +14056,11 @@
14043 (void*)0, /* pScratch */
14044 0, /* szScratch */
14045 0, /* nScratch */
14046 (void*)0, /* pPage */
14047 0, /* szPage */
14048 0, /* nPage */
14049 0, /* mxParserStack */
14050 0, /* sharedCacheEnabled */
14051 SQLITE_SORTER_PMASZ, /* szPma */
14052 /* All the rest should always be initialized to zero */
14053 0, /* isInit */
@@ -19454,11 +19467,11 @@
19454 ** The sqlite3_mutex_alloc() routine allocates a new
19455 ** mutex and returns a pointer to it. If it returns NULL
19456 ** that means that a mutex could not be allocated.
19457 */
19458 static sqlite3_mutex *debugMutexAlloc(int id){
19459 static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
19460 sqlite3_debug_mutex *pNew = 0;
19461 switch( id ){
19462 case SQLITE_MUTEX_FAST:
19463 case SQLITE_MUTEX_RECURSIVE: {
19464 pNew = sqlite3Malloc(sizeof(*pNew));
@@ -19669,10 +19682,13 @@
19669 ** <li> SQLITE_MUTEX_STATIC_LRU
19670 ** <li> SQLITE_MUTEX_STATIC_PMEM
19671 ** <li> SQLITE_MUTEX_STATIC_APP1
19672 ** <li> SQLITE_MUTEX_STATIC_APP2
19673 ** <li> SQLITE_MUTEX_STATIC_APP3
 
 
 
19674 ** </ul>
19675 **
19676 ** The first two constants cause sqlite3_mutex_alloc() to create
19677 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
19678 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -19697,10 +19713,13 @@
19697 ** mutex types, the same mutex is returned on every call that has
19698 ** the same type number.
19699 */
19700 static sqlite3_mutex *pthreadMutexAlloc(int iType){
19701 static sqlite3_mutex staticMutexes[] = {
 
 
 
19702 SQLITE3_MUTEX_INITIALIZER,
19703 SQLITE3_MUTEX_INITIALIZER,
19704 SQLITE3_MUTEX_INITIALIZER,
19705 SQLITE3_MUTEX_INITIALIZER,
19706 SQLITE3_MUTEX_INITIALIZER,
@@ -20311,10 +20330,13 @@
20311 SQLITE3_MUTEX_INITIALIZER,
20312 SQLITE3_MUTEX_INITIALIZER,
20313 SQLITE3_MUTEX_INITIALIZER,
20314 SQLITE3_MUTEX_INITIALIZER,
20315 SQLITE3_MUTEX_INITIALIZER,
 
 
 
20316 SQLITE3_MUTEX_INITIALIZER
20317 };
20318
20319 static int winMutex_isInit = 0;
20320 static int winMutex_isNt = -1; /* <0 means "need to query" */
@@ -20382,10 +20404,13 @@
20382 ** <li> SQLITE_MUTEX_STATIC_LRU
20383 ** <li> SQLITE_MUTEX_STATIC_PMEM
20384 ** <li> SQLITE_MUTEX_STATIC_APP1
20385 ** <li> SQLITE_MUTEX_STATIC_APP2
20386 ** <li> SQLITE_MUTEX_STATIC_APP3
 
 
 
20387 ** </ul>
20388 **
20389 ** The first two constants cause sqlite3_mutex_alloc() to create
20390 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
20391 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -20793,14 +20818,13 @@
20793 sqlite3GlobalConfig.pScratch = 0;
20794 sqlite3GlobalConfig.szScratch = 0;
20795 sqlite3GlobalConfig.nScratch = 0;
20796 }
20797 if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
20798 || sqlite3GlobalConfig.nPage<1 ){
20799 sqlite3GlobalConfig.pPage = 0;
20800 sqlite3GlobalConfig.szPage = 0;
20801 sqlite3GlobalConfig.nPage = 0;
20802 }
20803 rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
20804 if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
20805 return rc;
20806 }
@@ -26522,18 +26546,18 @@
26522 ** unixEnterMutex()
26523 ** assert( unixMutexHeld() );
26524 ** unixEnterLeave()
26525 */
26526 static void unixEnterMutex(void){
26527 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
26528 }
26529 static void unixLeaveMutex(void){
26530 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
26531 }
26532 #ifdef SQLITE_DEBUG
26533 static int unixMutexHeld(void) {
26534 return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
26535 }
26536 #endif
26537
26538
26539 #ifdef SQLITE_HAVE_OS_TRACE
@@ -37047,18 +37071,18 @@
37047 ** winShmEnterMutex()
37048 ** assert( winShmMutexHeld() );
37049 ** winShmLeaveMutex()
37050 */
37051 static void winShmEnterMutex(void){
37052 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
37053 }
37054 static void winShmLeaveMutex(void){
37055 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
37056 }
37057 #ifndef NDEBUG
37058 static int winShmMutexHeld(void) {
37059 return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
37060 }
37061 #endif
37062
37063 /*
37064 ** Object used to represent a single file opened and mmapped to provide
@@ -40399,12 +40423,75 @@
40399 ** This file implements the default page cache implementation (the
40400 ** sqlite3_pcache interface). It also contains part of the implementation
40401 ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
40402 ** If the default page cache implementation is overridden, then neither of
40403 ** these two features are available.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40404 */
40405
40406
40407 typedef struct PCache1 PCache1;
40408 typedef struct PgHdr1 PgHdr1;
40409 typedef struct PgFreeslot PgFreeslot;
40410 typedef struct PGroup PGroup;
@@ -40453,12 +40540,13 @@
40453 ** flag (bPurgeable) are set when the cache is created. nMax may be
40454 ** modified at any time by a call to the pcache1Cachesize() method.
40455 ** The PGroup mutex must be held when accessing nMax.
40456 */
40457 PGroup *pGroup; /* PGroup this cache belongs to */
40458 int szPage; /* Size of allocated pages in bytes */
40459 int szExtra; /* Size of extra space in bytes */
 
40460 int bPurgeable; /* True if cache is purgeable */
40461 unsigned int nMin; /* Minimum number of pages reserved */
40462 unsigned int nMax; /* Configured "cache_size" value */
40463 unsigned int n90pct; /* nMax*9/10 */
40464 unsigned int iMaxKey; /* Largest key seen since xTruncate() */
@@ -40468,10 +40556,12 @@
40468 */
40469 unsigned int nRecyclable; /* Number of pages in the LRU list */
40470 unsigned int nPage; /* Total number of pages in apHash */
40471 unsigned int nHash; /* Number of slots in apHash[] */
40472 PgHdr1 **apHash; /* Hash table for fast lookup by key */
 
 
40473 };
40474
40475 /*
40476 ** Each cache entry is represented by an instance of the following
40477 ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
@@ -40480,19 +40570,20 @@
40480 */
40481 struct PgHdr1 {
40482 sqlite3_pcache_page page;
40483 unsigned int iKey; /* Key value (page number) */
40484 u8 isPinned; /* Page in use, not on the LRU list */
 
40485 PgHdr1 *pNext; /* Next in hash table chain */
40486 PCache1 *pCache; /* Cache that currently owns this page */
40487 PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
40488 PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
40489 };
40490
40491 /*
40492 ** Free slots in the allocator used to divide up the buffer provided using
40493 ** the SQLITE_CONFIG_PAGECACHE mechanism.
40494 */
40495 struct PgFreeslot {
40496 PgFreeslot *pNext; /* Next free slot */
40497 };
40498
@@ -40506,14 +40597,15 @@
40506 ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
40507 ** fixed at sqlite3_initialize() time and do not require mutex protection.
40508 ** The nFreeSlot and pFree values do require mutex protection.
40509 */
40510 int isInit; /* True if initialized */
 
40511 int szSlot; /* Size of each free slot */
40512 int nSlot; /* The number of pcache slots */
40513 int nReserve; /* Try to keep nFreeSlot above this */
40514 void *pStart, *pEnd; /* Bounds of pagecache malloc range */
40515 /* Above requires no mutex. Use mutex below for variable that follow. */
40516 sqlite3_mutex *mutex; /* Mutex for accessing the following: */
40517 PgFreeslot *pFree; /* Free page blocks */
40518 int nFreeSlot; /* Number of unused pcache slots */
40519 /* The following value requires a mutex to change. We skip the mutex on
@@ -40556,10 +40648,11 @@
40556 ** to be serialized already. There is no need for further mutexing.
40557 */
40558 SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
40559 if( pcache1.isInit ){
40560 PgFreeslot *p;
 
40561 sz = ROUNDDOWN8(sz);
40562 pcache1.szSlot = sz;
40563 pcache1.nSlot = pcache1.nFreeSlot = n;
40564 pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
40565 pcache1.pStart = pBuf;
@@ -40620,13 +40713,13 @@
40620 }
40621
40622 /*
40623 ** Free an allocated buffer obtained from pcache1Alloc().
40624 */
40625 static int pcache1Free(void *p){
40626 int nFreed = 0;
40627 if( p==0 ) return 0;
40628 if( p>=pcache1.pStart && p<pcache1.pEnd ){
40629 PgFreeslot *pSlot;
40630 sqlite3_mutex_enter(pcache1.mutex);
40631 sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
40632 pSlot = (PgFreeslot*)p;
@@ -40637,19 +40730,18 @@
40637 assert( pcache1.nFreeSlot<=pcache1.nSlot );
40638 sqlite3_mutex_leave(pcache1.mutex);
40639 }else{
40640 assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
40641 sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
40642 nFreed = sqlite3MallocSize(p);
40643 #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
 
40644 sqlite3_mutex_enter(pcache1.mutex);
40645 sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
40646 sqlite3_mutex_leave(pcache1.mutex);
40647 #endif
40648 sqlite3_free(p);
40649 }
40650 return nFreed;
40651 }
40652
40653 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40654 /*
40655 ** Return the size of a pcache allocation
@@ -40673,58 +40765,69 @@
40673 */
40674 static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
40675 PgHdr1 *p = 0;
40676 void *pPg;
40677
40678 /* The group mutex must be released before pcache1Alloc() is called. This
40679 ** is because it may call sqlite3_release_memory(), which assumes that
40680 ** this mutex is not held. */
40681 assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
40682 pcache1LeaveMutex(pCache->pGroup);
 
 
 
 
 
 
 
 
 
 
 
 
40683 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
40684 pPg = pcache1Alloc(pCache->szPage);
40685 p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
40686 if( !pPg || !p ){
40687 pcache1Free(pPg);
40688 sqlite3_free(p);
40689 pPg = 0;
40690 }
40691 #else
40692 pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
40693 p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
40694 #endif
40695 pcache1EnterMutex(pCache->pGroup);
40696
40697 if( pPg ){
 
40698 p->page.pBuf = pPg;
40699 p->page.pExtra = &p[1];
40700 if( pCache->bPurgeable ){
40701 pCache->pGroup->nCurrentPage++;
40702 }
40703 return p;
40704 }
40705 return 0;
 
 
 
40706 }
40707
40708 /*
40709 ** Free a page object allocated by pcache1AllocPage().
40710 **
40711 ** The pointer is allowed to be NULL, which is prudent. But it turns out
40712 ** that the current implementation happens to never call this routine
40713 ** with a NULL pointer, so we mark the NULL test with ALWAYS().
40714 */
40715 static void pcache1FreePage(PgHdr1 *p){
40716 if( ALWAYS(p) ){
40717 PCache1 *pCache = p->pCache;
40718 assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
 
 
 
 
 
40719 pcache1Free(p->page.pBuf);
40720 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
40721 sqlite3_free(p);
40722 #endif
40723 if( pCache->bPurgeable ){
40724 pCache->pGroup->nCurrentPage--;
40725 }
40726 }
40727 }
40728
40729 /*
40730 ** Malloc function used by SQLite to obtain space from the buffer configured
@@ -40920,10 +41023,35 @@
40920 */
40921 static int pcache1Init(void *NotUsed){
40922 UNUSED_PARAMETER(NotUsed);
40923 assert( pcache1.isInit==0 );
40924 memset(&pcache1, 0, sizeof(pcache1));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40925 #if SQLITE_THREADSAFE
40926 if( sqlite3GlobalConfig.bCoreMutex ){
40927 pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
40928 pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
40929 }
@@ -40955,52 +41083,65 @@
40955 static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
40956 PCache1 *pCache; /* The newly created page cache */
40957 PGroup *pGroup; /* The group the new page cache will belong to */
40958 int sz; /* Bytes of memory required to allocate the new cache */
40959
40960 /*
40961 ** The separateCache variable is true if each PCache has its own private
40962 ** PGroup. In other words, separateCache is true for mode (1) where no
40963 ** mutexing is required.
40964 **
40965 ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
40966 **
40967 ** * Always use a unified cache in single-threaded applications
40968 **
40969 ** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
40970 ** use separate caches (mode-1)
40971 */
40972 #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
40973 const int separateCache = 0;
40974 #else
40975 int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
40976 #endif
40977
40978 assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
40979 assert( szExtra < 300 );
40980
40981 sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
40982 pCache = (PCache1 *)sqlite3MallocZero(sz);
40983 if( pCache ){
40984 if( separateCache ){
40985 pGroup = (PGroup*)&pCache[1];
40986 pGroup->mxPinned = 10;
40987 }else{
40988 pGroup = &pcache1.grp;
40989 }
40990 pCache->pGroup = pGroup;
40991 pCache->szPage = szPage;
40992 pCache->szExtra = szExtra;
 
40993 pCache->bPurgeable = (bPurgeable ? 1 : 0);
40994 pcache1EnterMutex(pGroup);
40995 pcache1ResizeHash(pCache);
40996 if( bPurgeable ){
40997 pCache->nMin = 10;
40998 pGroup->nMinPage += pCache->nMin;
40999 pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
41000 }
41001 pcache1LeaveMutex(pGroup);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41002 if( pCache->nHash==0 ){
41003 pcache1Destroy((sqlite3_pcache*)pCache);
41004 pCache = 0;
41005 }
41006 }
@@ -41090,30 +41231,21 @@
41090
41091 if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
41092 assert( pCache->nHash>0 && pCache->apHash );
41093
41094 /* Step 4. Try to recycle a page. */
41095 if( pCache->bPurgeable && pGroup->pLruTail && (
41096 (pCache->nPage+1>=pCache->nMax)
41097 || pGroup->nCurrentPage>=pGroup->nMaxPage
41098 || pcache1UnderMemoryPressure(pCache)
41099 )){
41100 PCache1 *pOther;
41101 pPage = pGroup->pLruTail;
41102 assert( pPage->isPinned==0 );
41103 pcache1RemoveFromHash(pPage, 0);
41104 pcache1PinPage(pPage);
41105 pOther = pPage->pCache;
41106
41107 /* We want to verify that szPage and szExtra are the same for pOther
41108 ** and pCache. Assert that we can verify this by comparing sums. */
41109 assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
41110 assert( pCache->szExtra<512 );
41111 assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
41112 assert( pOther->szExtra<512 );
41113
41114 if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
41115 pcache1FreePage(pPage);
41116 pPage = 0;
41117 }else{
41118 pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
41119 }
@@ -41385,10 +41517,11 @@
41385 assert( pGroup->nMinPage >= pCache->nMin );
41386 pGroup->nMinPage -= pCache->nMin;
41387 pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
41388 pcache1EnforceMaxPage(pGroup);
41389 pcache1LeaveMutex(pGroup);
 
41390 sqlite3_free(pCache->apHash);
41391 sqlite3_free(pCache);
41392 }
41393
41394 /*
@@ -41440,11 +41573,11 @@
41440 */
41441 SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
41442 int nFree = 0;
41443 assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
41444 assert( sqlite3_mutex_notheld(pcache1.mutex) );
41445 if( pcache1.pStart==0 ){
41446 PgHdr1 *p;
41447 pcache1EnterMutex(&pcache1.grp);
41448 while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
41449 nFree += pcache1MemSize(p->page.pBuf);
41450 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
@@ -62542,10 +62675,11 @@
62542 u32 *heap = 0; /* Min-heap used for checking cell coverage */
62543 u32 x, prev = 0; /* Next and previous entry on the min-heap */
62544 const char *saved_zPfx = pCheck->zPfx;
62545 int saved_v1 = pCheck->v1;
62546 int saved_v2 = pCheck->v2;
 
62547
62548 /* Check that the page exists
62549 */
62550 pBt = pCheck->pBt;
62551 usableSize = pBt->usableSize;
@@ -62559,10 +62693,11 @@
62559 goto end_of_check;
62560 }
62561
62562 /* Clear MemPage.isInit to make sure the corruption detection code in
62563 ** btreeInitPage() is executed. */
 
62564 pPage->isInit = 0;
62565 if( (rc = btreeInitPage(pPage))!=0 ){
62566 assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
62567 checkAppendMsg(pCheck,
62568 "btreeInitPage() returns error code %d", rc);
@@ -62700,11 +62835,11 @@
62700 while( i>0 ){
62701 int size, j;
62702 assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */
62703 size = get2byte(&data[i+2]);
62704 assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */
62705 btreeHeapInsert(heap, (i<<16)|(i+size-1));
62706 /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
62707 ** big-endian integer which is the offset in the b-tree page of the next
62708 ** freeblock in the chain, or zero if the freeblock is the last on the
62709 ** chain. */
62710 j = get2byte(&data[i]);
@@ -62751,10 +62886,11 @@
62751 nFrag, data[hdr+7], iPage);
62752 }
62753 }
62754
62755 end_of_check:
 
62756 releasePage(pPage);
62757 pCheck->zPfx = saved_zPfx;
62758 pCheck->v1 = saved_v1;
62759 pCheck->v2 = saved_v2;
62760 return depth+1;
@@ -69020,10 +69156,11 @@
69020 ** to ignore the compiler warnings and leave this variable uninitialized.
69021 */
69022 /* mem1.u.i = 0; // not needed, here to silence compiler warning */
69023
69024 idx1 = getVarint32(aKey1, szHdr1);
 
69025 d1 = szHdr1;
69026 assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
69027 assert( pKeyInfo->aSortOrder!=0 );
69028 assert( pKeyInfo->nField>0 );
69029 assert( idx1<=szHdr1 || CORRUPT_DB );
@@ -109379,14 +109516,18 @@
109379 sqlite3VdbeResolveLabel(v, addrCont);
109380
109381 /* Execute the recursive SELECT taking the single row in Current as
109382 ** the value for the recursive-table. Store the results in the Queue.
109383 */
109384 p->pPrior = 0;
109385 sqlite3Select(pParse, p, &destQueue);
109386 assert( p->pPrior==0 );
109387 p->pPrior = pSetup;
 
 
 
 
109388
109389 /* Keep running the loop until the Queue is empty */
109390 sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
109391 sqlite3VdbeResolveLabel(v, addrBreak);
109392
109393
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -325,11 +325,11 @@
325 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
326 ** [sqlite_version()] and [sqlite_source_id()].
327 */
328 #define SQLITE_VERSION "3.8.11"
329 #define SQLITE_VERSION_NUMBER 3008011
330 #define SQLITE_SOURCE_ID "2015-07-08 16:22:42 5348ffc3fda5168c1e9e14aa88b0c6aedbda7c94"
331
332 /*
333 ** CAPI3REF: Run-Time Library Version Numbers
334 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
335 **
@@ -6503,10 +6503,13 @@
6503 #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
6504 #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
6505 #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
6506 #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
6507 #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
6508 #define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
6509 #define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
6510 #define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
6511
6512 /*
6513 ** CAPI3REF: Retrieve the mutex for a database connection
6514 ** METHOD: sqlite3
6515 **
@@ -8941,10 +8944,20 @@
8944 #if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS
8945 # undef SQLITE_MAX_WORKER_THREADS
8946 # define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
8947 #endif
8948
8949 /*
8950 ** The default initial allocation for the pagecache when using separate
8951 ** pagecaches for each database connection. A positive number is the
8952 ** number of pages. A negative number N translations means that a buffer
8953 ** of -1024*N bytes is allocated and used for as many pages as it will hold.
8954 */
8955 #ifndef SQLITE_DEFAULT_PCACHE_INITSZ
8956 # define SQLITE_DEFAULT_PCACHE_INITSZ 100
8957 #endif
8958
8959
8960 /*
8961 ** GCC does not define the offsetof() macro so we'll have to do it
8962 ** ourselves.
8963 */
@@ -14043,11 +14056,11 @@
14056 (void*)0, /* pScratch */
14057 0, /* szScratch */
14058 0, /* nScratch */
14059 (void*)0, /* pPage */
14060 0, /* szPage */
14061 SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
14062 0, /* mxParserStack */
14063 0, /* sharedCacheEnabled */
14064 SQLITE_SORTER_PMASZ, /* szPma */
14065 /* All the rest should always be initialized to zero */
14066 0, /* isInit */
@@ -19454,11 +19467,11 @@
19467 ** The sqlite3_mutex_alloc() routine allocates a new
19468 ** mutex and returns a pointer to it. If it returns NULL
19469 ** that means that a mutex could not be allocated.
19470 */
19471 static sqlite3_mutex *debugMutexAlloc(int id){
19472 static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1];
19473 sqlite3_debug_mutex *pNew = 0;
19474 switch( id ){
19475 case SQLITE_MUTEX_FAST:
19476 case SQLITE_MUTEX_RECURSIVE: {
19477 pNew = sqlite3Malloc(sizeof(*pNew));
@@ -19669,10 +19682,13 @@
19682 ** <li> SQLITE_MUTEX_STATIC_LRU
19683 ** <li> SQLITE_MUTEX_STATIC_PMEM
19684 ** <li> SQLITE_MUTEX_STATIC_APP1
19685 ** <li> SQLITE_MUTEX_STATIC_APP2
19686 ** <li> SQLITE_MUTEX_STATIC_APP3
19687 ** <li> SQLITE_MUTEX_STATIC_VFS1
19688 ** <li> SQLITE_MUTEX_STATIC_VFS2
19689 ** <li> SQLITE_MUTEX_STATIC_VFS3
19690 ** </ul>
19691 **
19692 ** The first two constants cause sqlite3_mutex_alloc() to create
19693 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
19694 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -19697,10 +19713,13 @@
19713 ** mutex types, the same mutex is returned on every call that has
19714 ** the same type number.
19715 */
19716 static sqlite3_mutex *pthreadMutexAlloc(int iType){
19717 static sqlite3_mutex staticMutexes[] = {
19718 SQLITE3_MUTEX_INITIALIZER,
19719 SQLITE3_MUTEX_INITIALIZER,
19720 SQLITE3_MUTEX_INITIALIZER,
19721 SQLITE3_MUTEX_INITIALIZER,
19722 SQLITE3_MUTEX_INITIALIZER,
19723 SQLITE3_MUTEX_INITIALIZER,
19724 SQLITE3_MUTEX_INITIALIZER,
19725 SQLITE3_MUTEX_INITIALIZER,
@@ -20311,10 +20330,13 @@
20330 SQLITE3_MUTEX_INITIALIZER,
20331 SQLITE3_MUTEX_INITIALIZER,
20332 SQLITE3_MUTEX_INITIALIZER,
20333 SQLITE3_MUTEX_INITIALIZER,
20334 SQLITE3_MUTEX_INITIALIZER,
20335 SQLITE3_MUTEX_INITIALIZER,
20336 SQLITE3_MUTEX_INITIALIZER,
20337 SQLITE3_MUTEX_INITIALIZER,
20338 SQLITE3_MUTEX_INITIALIZER
20339 };
20340
20341 static int winMutex_isInit = 0;
20342 static int winMutex_isNt = -1; /* <0 means "need to query" */
@@ -20382,10 +20404,13 @@
20404 ** <li> SQLITE_MUTEX_STATIC_LRU
20405 ** <li> SQLITE_MUTEX_STATIC_PMEM
20406 ** <li> SQLITE_MUTEX_STATIC_APP1
20407 ** <li> SQLITE_MUTEX_STATIC_APP2
20408 ** <li> SQLITE_MUTEX_STATIC_APP3
20409 ** <li> SQLITE_MUTEX_STATIC_VFS1
20410 ** <li> SQLITE_MUTEX_STATIC_VFS2
20411 ** <li> SQLITE_MUTEX_STATIC_VFS3
20412 ** </ul>
20413 **
20414 ** The first two constants cause sqlite3_mutex_alloc() to create
20415 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
20416 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -20793,14 +20818,13 @@
20818 sqlite3GlobalConfig.pScratch = 0;
20819 sqlite3GlobalConfig.szScratch = 0;
20820 sqlite3GlobalConfig.nScratch = 0;
20821 }
20822 if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
20823 || sqlite3GlobalConfig.nPage<=0 ){
20824 sqlite3GlobalConfig.pPage = 0;
20825 sqlite3GlobalConfig.szPage = 0;
 
20826 }
20827 rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
20828 if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
20829 return rc;
20830 }
@@ -26522,18 +26546,18 @@
26546 ** unixEnterMutex()
26547 ** assert( unixMutexHeld() );
26548 ** unixEnterLeave()
26549 */
26550 static void unixEnterMutex(void){
26551 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
26552 }
26553 static void unixLeaveMutex(void){
26554 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
26555 }
26556 #ifdef SQLITE_DEBUG
26557 static int unixMutexHeld(void) {
26558 return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
26559 }
26560 #endif
26561
26562
26563 #ifdef SQLITE_HAVE_OS_TRACE
@@ -37047,18 +37071,18 @@
37071 ** winShmEnterMutex()
37072 ** assert( winShmMutexHeld() );
37073 ** winShmLeaveMutex()
37074 */
37075 static void winShmEnterMutex(void){
37076 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
37077 }
37078 static void winShmLeaveMutex(void){
37079 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
37080 }
37081 #ifndef NDEBUG
37082 static int winShmMutexHeld(void) {
37083 return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
37084 }
37085 #endif
37086
37087 /*
37088 ** Object used to represent a single file opened and mmapped to provide
@@ -40399,12 +40423,75 @@
40423 ** This file implements the default page cache implementation (the
40424 ** sqlite3_pcache interface). It also contains part of the implementation
40425 ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
40426 ** If the default page cache implementation is overridden, then neither of
40427 ** these two features are available.
40428 **
40429 ** A Page cache line looks like this:
40430 **
40431 ** -------------------------------------------------------------
40432 ** | database page content | PgHdr1 | MemPage | PgHdr |
40433 ** -------------------------------------------------------------
40434 **
40435 ** The database page content is up front (so that buffer overreads tend to
40436 ** flow harmlessly into the PgHdr1, MemPage, and PgHdr extensions). MemPage
40437 ** is the extension added by the btree.c module containing information such
40438 ** as the database page number and how that database page is used. PgHdr
40439 ** is added by the pcache.c layer and contains information used to keep track
40440 ** of which pages are "dirty". PgHdr1 is an extension added by this
40441 ** module (pcache1.c). The PgHdr1 header is a subclass of sqlite3_pcache_page.
40442 ** PgHdr1 contains information needed to look up a page by its page number.
40443 ** The superclass sqlite3_pcache_page.pBuf points to the start of the
40444 ** database page content and sqlite3_pcache_page.pExtra points to PgHdr.
40445 **
40446 ** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at
40447 ** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The
40448 ** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this
40449 ** size can vary according to architecture, compile-time options, and
40450 ** SQLite library version number.
40451 **
40452 ** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
40453 ** using a separate memory allocation from the database page content. This
40454 ** seeks to overcome the "clownshoe" problem (also called "internal
40455 ** fragmentation" in academic literature) of allocating a few bytes more
40456 ** than a power of two with the memory allocator rounding up to the next
40457 ** power of two, and leaving the rounded-up space unused.
40458 **
40459 ** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
40460 ** with this module. Information is passed back and forth as PgHdr1 pointers.
40461 **
40462 ** The pcache.c and pager.c modules deal pointers to PgHdr objects.
40463 ** The btree.c module deals with pointers to MemPage objects.
40464 **
40465 ** SOURCE OF PAGE CACHE MEMORY:
40466 **
40467 ** Memory for a page might come from any of three sources:
40468 **
40469 ** (1) The general-purpose memory allocator - sqlite3Malloc()
40470 ** (2) Global page-cache memory provided using sqlite3_config() with
40471 ** SQLITE_CONFIG_PAGECACHE.
40472 ** (3) PCache-local bulk allocation.
40473 **
40474 ** The third case is a chunk of heap memory (defaulting to 100 pages worth)
40475 ** that is allocated when the page cache is created. The size of the local
40476 ** bulk allocation can be adjusted using
40477 **
40478 ** sqlite3_config(SQLITE_CONFIG_PCACHE, 0, 0, N).
40479 **
40480 ** If N is positive, then N pages worth of memory are allocated using a single
40481 ** sqlite3Malloc() call and that memory is used for the first N pages allocated.
40482 ** Or if N is negative, then -1024*N bytes of memory are allocated and used
40483 ** for as many pages as can be accomodated.
40484 **
40485 ** Only one of (2) or (3) can be used. Once the memory available to (2) or
40486 ** (3) is exhausted, subsequent allocations fail over to the general-purpose
40487 ** memory allocator (1).
40488 **
40489 ** Earlier versions of SQLite used only methods (1) and (2). But experiments
40490 ** show that method (3) with N==100 provides about a 5% performance boost for
40491 ** common workloads.
40492 */
 
40493
40494 typedef struct PCache1 PCache1;
40495 typedef struct PgHdr1 PgHdr1;
40496 typedef struct PgFreeslot PgFreeslot;
40497 typedef struct PGroup PGroup;
@@ -40453,12 +40540,13 @@
40540 ** flag (bPurgeable) are set when the cache is created. nMax may be
40541 ** modified at any time by a call to the pcache1Cachesize() method.
40542 ** The PGroup mutex must be held when accessing nMax.
40543 */
40544 PGroup *pGroup; /* PGroup this cache belongs to */
40545 int szPage; /* Size of database content section */
40546 int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
40547 int szAlloc; /* Total size of one pcache line */
40548 int bPurgeable; /* True if cache is purgeable */
40549 unsigned int nMin; /* Minimum number of pages reserved */
40550 unsigned int nMax; /* Configured "cache_size" value */
40551 unsigned int n90pct; /* nMax*9/10 */
40552 unsigned int iMaxKey; /* Largest key seen since xTruncate() */
@@ -40468,10 +40556,12 @@
40556 */
40557 unsigned int nRecyclable; /* Number of pages in the LRU list */
40558 unsigned int nPage; /* Total number of pages in apHash */
40559 unsigned int nHash; /* Number of slots in apHash[] */
40560 PgHdr1 **apHash; /* Hash table for fast lookup by key */
40561 PgHdr1 *pFree; /* List of unused pcache-local pages */
40562 void *pBulk; /* Bulk memory used by pcache-local */
40563 };
40564
40565 /*
40566 ** Each cache entry is represented by an instance of the following
40567 ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
@@ -40480,19 +40570,20 @@
40570 */
40571 struct PgHdr1 {
40572 sqlite3_pcache_page page;
40573 unsigned int iKey; /* Key value (page number) */
40574 u8 isPinned; /* Page in use, not on the LRU list */
40575 u8 isBulkLocal; /* This page from bulk local storage */
40576 PgHdr1 *pNext; /* Next in hash table chain */
40577 PCache1 *pCache; /* Cache that currently owns this page */
40578 PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
40579 PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
40580 };
40581
40582 /*
40583 ** Free slots in the allocator used to divide up the global page cache
40584 ** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
40585 */
40586 struct PgFreeslot {
40587 PgFreeslot *pNext; /* Next free slot */
40588 };
40589
@@ -40506,14 +40597,15 @@
40597 ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
40598 ** fixed at sqlite3_initialize() time and do not require mutex protection.
40599 ** The nFreeSlot and pFree values do require mutex protection.
40600 */
40601 int isInit; /* True if initialized */
40602 int separateCache; /* Use a new PGroup for each PCache */
40603 int szSlot; /* Size of each free slot */
40604 int nSlot; /* The number of pcache slots */
40605 int nReserve; /* Try to keep nFreeSlot above this */
40606 void *pStart, *pEnd; /* Bounds of global page cache memory */
40607 /* Above requires no mutex. Use mutex below for variable that follow. */
40608 sqlite3_mutex *mutex; /* Mutex for accessing the following: */
40609 PgFreeslot *pFree; /* Free page blocks */
40610 int nFreeSlot; /* Number of unused pcache slots */
40611 /* The following value requires a mutex to change. We skip the mutex on
@@ -40556,10 +40648,11 @@
40648 ** to be serialized already. There is no need for further mutexing.
40649 */
40650 SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
40651 if( pcache1.isInit ){
40652 PgFreeslot *p;
40653 if( pBuf==0 ) sz = n = 0;
40654 sz = ROUNDDOWN8(sz);
40655 pcache1.szSlot = sz;
40656 pcache1.nSlot = pcache1.nFreeSlot = n;
40657 pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
40658 pcache1.pStart = pBuf;
@@ -40620,13 +40713,13 @@
40713 }
40714
40715 /*
40716 ** Free an allocated buffer obtained from pcache1Alloc().
40717 */
40718 static void pcache1Free(void *p){
40719 int nFreed = 0;
40720 if( p==0 ) return;
40721 if( p>=pcache1.pStart && p<pcache1.pEnd ){
40722 PgFreeslot *pSlot;
40723 sqlite3_mutex_enter(pcache1.mutex);
40724 sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
40725 pSlot = (PgFreeslot*)p;
@@ -40637,19 +40730,18 @@
40730 assert( pcache1.nFreeSlot<=pcache1.nSlot );
40731 sqlite3_mutex_leave(pcache1.mutex);
40732 }else{
40733 assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
40734 sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
 
40735 #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
40736 nFreed = sqlite3MallocSize(p);
40737 sqlite3_mutex_enter(pcache1.mutex);
40738 sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
40739 sqlite3_mutex_leave(pcache1.mutex);
40740 #endif
40741 sqlite3_free(p);
40742 }
 
40743 }
40744
40745 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40746 /*
40747 ** Return the size of a pcache allocation
@@ -40673,58 +40765,69 @@
40765 */
40766 static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
40767 PgHdr1 *p = 0;
40768 void *pPg;
40769
 
 
 
40770 assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
40771 if( pCache->pFree ){
40772 p = pCache->pFree;
40773 pCache->pFree = p->pNext;
40774 p->pNext = 0;
40775 }else{
40776 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40777 /* The group mutex must be released before pcache1Alloc() is called. This
40778 ** is because it might call sqlite3_release_memory(), which assumes that
40779 ** this mutex is not held. */
40780 assert( pcache1.separateCache==0 );
40781 assert( pCache->pGroup==&pcache1.grp );
40782 pcache1LeaveMutex(pCache->pGroup);
40783 #endif
40784 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
40785 pPg = pcache1Alloc(pCache->szPage);
40786 p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
40787 if( !pPg || !p ){
40788 pcache1Free(pPg);
40789 sqlite3_free(p);
40790 pPg = 0;
40791 }
40792 #else
40793 pPg = pcache1Alloc(pCache->szAlloc);
40794 p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
40795 #endif
40796 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40797 pcache1EnterMutex(pCache->pGroup);
40798 #endif
40799 if( pPg==0 ) return 0;
40800 p->page.pBuf = pPg;
40801 p->page.pExtra = &p[1];
40802 p->isBulkLocal = 0;
 
 
 
40803 }
40804 if( pCache->bPurgeable ){
40805 pCache->pGroup->nCurrentPage++;
40806 }
40807 return p;
40808 }
40809
40810 /*
40811 ** Free a page object allocated by pcache1AllocPage().
 
 
 
 
40812 */
40813 static void pcache1FreePage(PgHdr1 *p){
40814 PCache1 *pCache;
40815 assert( p!=0 );
40816 pCache = p->pCache;
40817 assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
40818 if( p->isBulkLocal ){
40819 p->pNext = pCache->pFree;
40820 pCache->pFree = p;
40821 }else{
40822 pcache1Free(p->page.pBuf);
40823 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
40824 sqlite3_free(p);
40825 #endif
40826 }
40827 if( pCache->bPurgeable ){
40828 pCache->pGroup->nCurrentPage--;
40829 }
40830 }
40831
40832 /*
40833 ** Malloc function used by SQLite to obtain space from the buffer configured
@@ -40920,10 +41023,35 @@
41023 */
41024 static int pcache1Init(void *NotUsed){
41025 UNUSED_PARAMETER(NotUsed);
41026 assert( pcache1.isInit==0 );
41027 memset(&pcache1, 0, sizeof(pcache1));
41028
41029
41030 /*
41031 ** The pcache1.separateCache variable is true if each PCache has its own
41032 ** private PGroup (mode-1). pcache1.separateCache is false if the single
41033 ** PGroup in pcache1.grp is used for all page caches (mode-2).
41034 **
41035 ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
41036 **
41037 ** * Use a unified cache in single-threaded applications that have
41038 ** configured a start-time buffer for use as page-cache memory using
41039 ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
41040 ** pBuf argument.
41041 **
41042 ** * Otherwise use separate caches (mode-1)
41043 */
41044 #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
41045 pcache1.separateCache = 0;
41046 #elif SQLITE_THREADSAFE
41047 pcache1.separateCache = sqlite3GlobalConfig.pPage==0
41048 || sqlite3GlobalConfig.bCoreMutex>0;
41049 #else
41050 pcache1.separateCache = sqlite3GlobalConfig.pPage==0;
41051 #endif
41052
41053 #if SQLITE_THREADSAFE
41054 if( sqlite3GlobalConfig.bCoreMutex ){
41055 pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
41056 pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
41057 }
@@ -40955,52 +41083,65 @@
41083 static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
41084 PCache1 *pCache; /* The newly created page cache */
41085 PGroup *pGroup; /* The group the new page cache will belong to */
41086 int sz; /* Bytes of memory required to allocate the new cache */
41087
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41088 assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
41089 assert( szExtra < 300 );
41090
41091 sz = sizeof(PCache1) + sizeof(PGroup)*pcache1.separateCache;
41092 pCache = (PCache1 *)sqlite3MallocZero(sz);
41093 if( pCache ){
41094 if( pcache1.separateCache ){
41095 pGroup = (PGroup*)&pCache[1];
41096 pGroup->mxPinned = 10;
41097 }else{
41098 pGroup = &pcache1.grp;
41099 }
41100 pCache->pGroup = pGroup;
41101 pCache->szPage = szPage;
41102 pCache->szExtra = szExtra;
41103 pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1));
41104 pCache->bPurgeable = (bPurgeable ? 1 : 0);
41105 pcache1EnterMutex(pGroup);
41106 pcache1ResizeHash(pCache);
41107 if( bPurgeable ){
41108 pCache->nMin = 10;
41109 pGroup->nMinPage += pCache->nMin;
41110 pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
41111 }
41112 pcache1LeaveMutex(pGroup);
41113 /* Try to initialize the local bulk pagecache line allocation if using
41114 ** separate caches and if nPage!=0 */
41115 if( pcache1.separateCache
41116 && sqlite3GlobalConfig.nPage!=0
41117 && sqlite3GlobalConfig.pPage==0
41118 ){
41119 int szBulk;
41120 char *zBulk;
41121 sqlite3BeginBenignMalloc();
41122 if( sqlite3GlobalConfig.nPage>0 ){
41123 szBulk = pCache->szAlloc * sqlite3GlobalConfig.nPage;
41124 }else{
41125 szBulk = -1024*sqlite3GlobalConfig.nPage;
41126 }
41127 zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
41128 sqlite3EndBenignMalloc();
41129 if( zBulk ){
41130 int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
41131 int i;
41132 for(i=0; i<nBulk; i++){
41133 PgHdr1 *pX = (PgHdr1*)&zBulk[szPage];
41134 pX->page.pBuf = zBulk;
41135 pX->page.pExtra = &pX[1];
41136 pX->isBulkLocal = 1;
41137 pX->pNext = pCache->pFree;
41138 pCache->pFree = pX;
41139 zBulk += pCache->szAlloc;
41140 }
41141 }
41142 }
41143 if( pCache->nHash==0 ){
41144 pcache1Destroy((sqlite3_pcache*)pCache);
41145 pCache = 0;
41146 }
41147 }
@@ -41090,30 +41231,21 @@
41231
41232 if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
41233 assert( pCache->nHash>0 && pCache->apHash );
41234
41235 /* Step 4. Try to recycle a page. */
41236 if( pCache->bPurgeable
41237 && pGroup->pLruTail
41238 && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache))
41239 ){
 
41240 PCache1 *pOther;
41241 pPage = pGroup->pLruTail;
41242 assert( pPage->isPinned==0 );
41243 pcache1RemoveFromHash(pPage, 0);
41244 pcache1PinPage(pPage);
41245 pOther = pPage->pCache;
41246 if( pOther->szAlloc != pCache->szAlloc ){
 
 
 
 
 
 
 
 
41247 pcache1FreePage(pPage);
41248 pPage = 0;
41249 }else{
41250 pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
41251 }
@@ -41385,10 +41517,11 @@
41517 assert( pGroup->nMinPage >= pCache->nMin );
41518 pGroup->nMinPage -= pCache->nMin;
41519 pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
41520 pcache1EnforceMaxPage(pGroup);
41521 pcache1LeaveMutex(pGroup);
41522 sqlite3_free(pCache->pBulk);
41523 sqlite3_free(pCache->apHash);
41524 sqlite3_free(pCache);
41525 }
41526
41527 /*
@@ -41440,11 +41573,11 @@
41573 */
41574 SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
41575 int nFree = 0;
41576 assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
41577 assert( sqlite3_mutex_notheld(pcache1.mutex) );
41578 if( sqlite3GlobalConfig.nPage==0 ){
41579 PgHdr1 *p;
41580 pcache1EnterMutex(&pcache1.grp);
41581 while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
41582 nFree += pcache1MemSize(p->page.pBuf);
41583 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
@@ -62542,10 +62675,11 @@
62675 u32 *heap = 0; /* Min-heap used for checking cell coverage */
62676 u32 x, prev = 0; /* Next and previous entry on the min-heap */
62677 const char *saved_zPfx = pCheck->zPfx;
62678 int saved_v1 = pCheck->v1;
62679 int saved_v2 = pCheck->v2;
62680 u8 savedIsInit;
62681
62682 /* Check that the page exists
62683 */
62684 pBt = pCheck->pBt;
62685 usableSize = pBt->usableSize;
@@ -62559,10 +62693,11 @@
62693 goto end_of_check;
62694 }
62695
62696 /* Clear MemPage.isInit to make sure the corruption detection code in
62697 ** btreeInitPage() is executed. */
62698 savedIsInit = pPage->isInit;
62699 pPage->isInit = 0;
62700 if( (rc = btreeInitPage(pPage))!=0 ){
62701 assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
62702 checkAppendMsg(pCheck,
62703 "btreeInitPage() returns error code %d", rc);
@@ -62700,11 +62835,11 @@
62835 while( i>0 ){
62836 int size, j;
62837 assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */
62838 size = get2byte(&data[i+2]);
62839 assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */
62840 btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1));
62841 /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
62842 ** big-endian integer which is the offset in the b-tree page of the next
62843 ** freeblock in the chain, or zero if the freeblock is the last on the
62844 ** chain. */
62845 j = get2byte(&data[i]);
@@ -62751,10 +62886,11 @@
62886 nFrag, data[hdr+7], iPage);
62887 }
62888 }
62889
62890 end_of_check:
62891 if( !doCoverageCheck ) pPage->isInit = savedIsInit;
62892 releasePage(pPage);
62893 pCheck->zPfx = saved_zPfx;
62894 pCheck->v1 = saved_v1;
62895 pCheck->v2 = saved_v2;
62896 return depth+1;
@@ -69020,10 +69156,11 @@
69156 ** to ignore the compiler warnings and leave this variable uninitialized.
69157 */
69158 /* mem1.u.i = 0; // not needed, here to silence compiler warning */
69159
69160 idx1 = getVarint32(aKey1, szHdr1);
69161 if( szHdr1>98307 ) return SQLITE_CORRUPT;
69162 d1 = szHdr1;
69163 assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
69164 assert( pKeyInfo->aSortOrder!=0 );
69165 assert( pKeyInfo->nField>0 );
69166 assert( idx1<=szHdr1 || CORRUPT_DB );
@@ -109379,14 +109516,18 @@
109516 sqlite3VdbeResolveLabel(v, addrCont);
109517
109518 /* Execute the recursive SELECT taking the single row in Current as
109519 ** the value for the recursive-table. Store the results in the Queue.
109520 */
109521 if( p->selFlags & SF_Aggregate ){
109522 sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
109523 }else{
109524 p->pPrior = 0;
109525 sqlite3Select(pParse, p, &destQueue);
109526 assert( p->pPrior==0 );
109527 p->pPrior = pSetup;
109528 }
109529
109530 /* Keep running the loop until the Queue is empty */
109531 sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
109532 sqlite3VdbeResolveLabel(v, addrBreak);
109533
109534
+4 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -111,11 +111,11 @@
111111
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112112
** [sqlite_version()] and [sqlite_source_id()].
113113
*/
114114
#define SQLITE_VERSION "3.8.11"
115115
#define SQLITE_VERSION_NUMBER 3008011
116
-#define SQLITE_SOURCE_ID "2015-07-03 17:54:49 030f60a7ba171650ce8c0ac32dc166eab80aca32"
116
+#define SQLITE_SOURCE_ID "2015-07-08 16:22:42 5348ffc3fda5168c1e9e14aa88b0c6aedbda7c94"
117117
118118
/*
119119
** CAPI3REF: Run-Time Library Version Numbers
120120
** KEYWORDS: sqlite3_version, sqlite3_sourceid
121121
**
@@ -6289,10 +6289,13 @@
62896289
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
62906290
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
62916291
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
62926292
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
62936293
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
6294
+#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
6295
+#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
6296
+#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
62946297
62956298
/*
62966299
** CAPI3REF: Retrieve the mutex for a database connection
62976300
** METHOD: sqlite3
62986301
**
62996302
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -111,11 +111,11 @@
111 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112 ** [sqlite_version()] and [sqlite_source_id()].
113 */
114 #define SQLITE_VERSION "3.8.11"
115 #define SQLITE_VERSION_NUMBER 3008011
116 #define SQLITE_SOURCE_ID "2015-07-03 17:54:49 030f60a7ba171650ce8c0ac32dc166eab80aca32"
117
118 /*
119 ** CAPI3REF: Run-Time Library Version Numbers
120 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
121 **
@@ -6289,10 +6289,13 @@
6289 #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
6290 #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
6291 #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
6292 #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
6293 #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
 
 
 
6294
6295 /*
6296 ** CAPI3REF: Retrieve the mutex for a database connection
6297 ** METHOD: sqlite3
6298 **
6299
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -111,11 +111,11 @@
111 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112 ** [sqlite_version()] and [sqlite_source_id()].
113 */
114 #define SQLITE_VERSION "3.8.11"
115 #define SQLITE_VERSION_NUMBER 3008011
116 #define SQLITE_SOURCE_ID "2015-07-08 16:22:42 5348ffc3fda5168c1e9e14aa88b0c6aedbda7c94"
117
118 /*
119 ** CAPI3REF: Run-Time Library Version Numbers
120 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
121 **
@@ -6289,10 +6289,13 @@
6289 #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
6290 #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
6291 #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
6292 #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
6293 #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
6294 #define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
6295 #define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
6296 #define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
6297
6298 /*
6299 ** CAPI3REF: Retrieve the mutex for a database connection
6300 ** METHOD: sqlite3
6301 **
6302
--- src/stash.c
+++ src/stash.c
@@ -503,10 +503,11 @@
503503
while( db_step(&q)==SQLITE_ROW ){
504504
newArgv[i++] = mprintf("%s%s", g.zLocalRoot, db_column_text(&q, 0));
505505
}
506506
db_finalize(&q);
507507
newArgv[0] = g.argv[0];
508
+ newArgv[1] = 0;
508509
g.argv = newArgv;
509510
g.argc = nFile+2;
510511
if( nFile==0 ) return;
511512
}
512513
g.argv[1] = "revert";
513514
--- src/stash.c
+++ src/stash.c
@@ -503,10 +503,11 @@
503 while( db_step(&q)==SQLITE_ROW ){
504 newArgv[i++] = mprintf("%s%s", g.zLocalRoot, db_column_text(&q, 0));
505 }
506 db_finalize(&q);
507 newArgv[0] = g.argv[0];
 
508 g.argv = newArgv;
509 g.argc = nFile+2;
510 if( nFile==0 ) return;
511 }
512 g.argv[1] = "revert";
513
--- src/stash.c
+++ src/stash.c
@@ -503,10 +503,11 @@
503 while( db_step(&q)==SQLITE_ROW ){
504 newArgv[i++] = mprintf("%s%s", g.zLocalRoot, db_column_text(&q, 0));
505 }
506 db_finalize(&q);
507 newArgv[0] = g.argv[0];
508 newArgv[1] = 0;
509 g.argv = newArgv;
510 g.argc = nFile+2;
511 if( nFile==0 ) return;
512 }
513 g.argv[1] = "revert";
514
+31 -12
--- src/th_lang.c
+++ src/th_lang.c
@@ -722,27 +722,46 @@
722722
** string is CLASS STRING
723723
*/
724724
static int string_is_command(
725725
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
726726
){
727
- int i;
728
- int iRes = 1;
729727
if( argc!=4 ){
730728
return Th_WrongNumArgs(interp, "string is class string");
731729
}
732
- if( argl[2]!=5 || 0!=memcmp(argv[2], "alnum", 5) ){
733
- Th_ErrorMessage(interp, "Expected alnum, got: ", argv[2], argl[2]);
730
+ if( argl[2]==5 && 0==memcmp(argv[2], "alnum", 5) ){
731
+ int i;
732
+ int iRes = 1;
733
+
734
+ for(i=0; i<argl[3]; i++){
735
+ if( !th_isalnum(argv[3][i]) ){
736
+ iRes = 0;
737
+ }
738
+ }
739
+
740
+ return Th_SetResultInt(interp, iRes);
741
+ }else if( argl[2]==6 && 0==memcmp(argv[2], "double", 6) ){
742
+ double fVal;
743
+ if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){
744
+ return Th_SetResultInt(interp, 1);
745
+ }
746
+ return Th_SetResultInt(interp, 0);
747
+ }else if( argl[2]==7 && 0==memcmp(argv[2], "integer", 7) ){
748
+ int iVal;
749
+ if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){
750
+ return Th_SetResultInt(interp, 1);
751
+ }
752
+ return Th_SetResultInt(interp, 0);
753
+ }else if( argl[2]==4 && 0==memcmp(argv[2], "list", 4) ){
754
+ if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){
755
+ return Th_SetResultInt(interp, 1);
756
+ }
757
+ return Th_SetResultInt(interp, 0);
758
+ }else{
759
+ Th_ErrorMessage(interp,
760
+ "Expected alnum, double, integer, or list, got:", argv[2], argl[2]);
734761
return TH_ERROR;
735762
}
736
-
737
- for(i=0; i<argl[3]; i++){
738
- if( !th_isalnum(argv[3][i]) ){
739
- iRes = 0;
740
- }
741
- }
742
-
743
- return Th_SetResultInt(interp, iRes);
744763
}
745764
746765
/*
747766
** TH Syntax:
748767
**
749768
--- src/th_lang.c
+++ src/th_lang.c
@@ -722,27 +722,46 @@
722 ** string is CLASS STRING
723 */
724 static int string_is_command(
725 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
726 ){
727 int i;
728 int iRes = 1;
729 if( argc!=4 ){
730 return Th_WrongNumArgs(interp, "string is class string");
731 }
732 if( argl[2]!=5 || 0!=memcmp(argv[2], "alnum", 5) ){
733 Th_ErrorMessage(interp, "Expected alnum, got: ", argv[2], argl[2]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734 return TH_ERROR;
735 }
736
737 for(i=0; i<argl[3]; i++){
738 if( !th_isalnum(argv[3][i]) ){
739 iRes = 0;
740 }
741 }
742
743 return Th_SetResultInt(interp, iRes);
744 }
745
746 /*
747 ** TH Syntax:
748 **
749
--- src/th_lang.c
+++ src/th_lang.c
@@ -722,27 +722,46 @@
722 ** string is CLASS STRING
723 */
724 static int string_is_command(
725 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
726 ){
 
 
727 if( argc!=4 ){
728 return Th_WrongNumArgs(interp, "string is class string");
729 }
730 if( argl[2]==5 && 0==memcmp(argv[2], "alnum", 5) ){
731 int i;
732 int iRes = 1;
733
734 for(i=0; i<argl[3]; i++){
735 if( !th_isalnum(argv[3][i]) ){
736 iRes = 0;
737 }
738 }
739
740 return Th_SetResultInt(interp, iRes);
741 }else if( argl[2]==6 && 0==memcmp(argv[2], "double", 6) ){
742 double fVal;
743 if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){
744 return Th_SetResultInt(interp, 1);
745 }
746 return Th_SetResultInt(interp, 0);
747 }else if( argl[2]==7 && 0==memcmp(argv[2], "integer", 7) ){
748 int iVal;
749 if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){
750 return Th_SetResultInt(interp, 1);
751 }
752 return Th_SetResultInt(interp, 0);
753 }else if( argl[2]==4 && 0==memcmp(argv[2], "list", 4) ){
754 if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){
755 return Th_SetResultInt(interp, 1);
756 }
757 return Th_SetResultInt(interp, 0);
758 }else{
759 Th_ErrorMessage(interp,
760 "Expected alnum, double, integer, or list, got:", argv[2], argl[2]);
761 return TH_ERROR;
762 }
 
 
 
 
 
 
 
 
763 }
764
765 /*
766 ** TH Syntax:
767 **
768
+106 -11
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -82,10 +82,11 @@
8282
# if defined(_WIN32)
8383
# if !defined(WIN32_LEAN_AND_MEAN)
8484
# define WIN32_LEAN_AND_MEAN
8585
# endif
8686
# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0502)
87
+# undef _WIN32_WINNT
8788
# define _WIN32_WINNT 0x0502 /* SetDllDirectory, Windows XP SP2 */
8889
# endif
8990
# include <windows.h>
9091
# ifndef TCL_DIRECTORY_SEP
9192
# define TCL_DIRECTORY_SEP '\\'
@@ -342,11 +343,11 @@
342343
*/
343344
static const char *getTclReturnCodeName(
344345
int rc,
345346
int nullIfOk
346347
){
347
- static char zRc[32];
348
+ static char zRc[TCL_INTEGER_SPACE + 17]; /* "Tcl return code\0" */
348349
349350
switch( rc ){
350351
case TCL_OK: return nullIfOk ? 0 : "TCL_OK";
351352
case TCL_ERROR: return "TCL_ERROR";
352353
case TCL_RETURN: return "TCL_RETURN";
@@ -395,11 +396,11 @@
395396
tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
396397
tcl_FinalizeProc *xFinalize; /* Tcl_Finalize() pointer. */
397398
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
398399
int useObjProc; /* Non-zero if an objProc can be called directly. */
399400
int useTip285; /* Non-zero if TIP #285 is available. */
400
- char *setup; /* The optional Tcl setup script. */
401
+ const char *setup; /* The optional Tcl setup script. */
401402
tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
402403
void *pPreContext; /* Optional, provided to xPreEval(). */
403404
tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
404405
void *pPostContext; /* Optional, provided to xPostEval(). */
405406
};
@@ -438,12 +439,12 @@
438439
439440
/*
440441
** TH1 command: tclEval arg ?arg ...?
441442
**
442443
** Evaluates the Tcl script and returns its result verbatim. If a Tcl script
443
-** error is generated, it will be transformed into a TH1 script error. A Tcl
444
-** interpreter will be created automatically if it has not been already.
444
+** error is generated, it will be transformed into a TH1 script error. The
445
+** Tcl interpreter will be created automatically if it has not been already.
445446
*/
446447
static int tclEval_command(
447448
Th_Interp *interp,
448449
void *ctx,
449450
int argc,
@@ -497,11 +498,12 @@
497498
/*
498499
** TH1 command: tclExpr arg ?arg ...?
499500
**
500501
** Evaluates the Tcl expression and returns its result verbatim. If a Tcl
501502
** script error is generated, it will be transformed into a TH1 script error.
502
-** A Tcl interpreter will be created automatically if it has not been already.
503
+** The Tcl interpreter will be created automatically if it has not been
504
+** already.
503505
*/
504506
static int tclExpr_command(
505507
Th_Interp *interp,
506508
void *ctx,
507509
int argc,
@@ -562,12 +564,12 @@
562564
563565
/*
564566
** TH1 command: tclInvoke command ?arg ...?
565567
**
566568
** Invokes the Tcl command using the supplied arguments. No additional
567
-** substitutions are performed on the arguments. A Tcl interpreter will
568
-** be created automatically if it has not been already.
569
+** substitutions are performed on the arguments. The Tcl interpreter
570
+** will be created automatically if it has not been already.
569571
*/
570572
static int tclInvoke_command(
571573
Th_Interp *interp,
572574
void *ctx,
573575
int argc,
@@ -632,10 +634,100 @@
632634
Tcl_Release((ClientData)tclInterp);
633635
rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
634636
getTh1ReturnCode(rc));
635637
return rc;
636638
}
639
+
640
+/*
641
+** TH1 command: tclIsSafe
642
+**
643
+** Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter
644
+** will be created automatically if it has not been already.
645
+*/
646
+static int tclIsSafe_command(
647
+ Th_Interp *interp,
648
+ void *ctx,
649
+ int argc,
650
+ const char **argv,
651
+ int *argl
652
+){
653
+ Tcl_Interp *tclInterp;
654
+
655
+ if( createTclInterp(interp, ctx)!=TH_OK ){
656
+ return TH_ERROR;
657
+ }
658
+ if( argc!=1 ){
659
+ return Th_WrongNumArgs(interp, "tclIsSafe");
660
+ }
661
+ tclInterp = GET_CTX_TCL_INTERP(ctx);
662
+ if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
663
+ Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
664
+ return TH_ERROR;
665
+ }
666
+ Th_SetResultInt(interp, Tcl_IsSafe(tclInterp));
667
+ return TH_OK;
668
+}
669
+
670
+/*
671
+** TH1 command: tclMakeSafe
672
+**
673
+** Forces the Tcl interpreter into "safe" mode by removing all "unsafe"
674
+** commands and variables. This operation cannot be undone. The Tcl
675
+** interpreter will remain "safe" until the process terminates.
676
+*/
677
+static int tclMakeSafe_command(
678
+ Th_Interp *interp,
679
+ void *ctx,
680
+ int argc,
681
+ const char **argv,
682
+ int *argl
683
+){
684
+ static int registerChans = 1;
685
+ Tcl_Interp *tclInterp;
686
+ int rc = TH_OK;
687
+
688
+ if( createTclInterp(interp, ctx)!=TH_OK ){
689
+ return TH_ERROR;
690
+ }
691
+ if( argc!=1 ){
692
+ return Th_WrongNumArgs(interp, "tclMakeSafe");
693
+ }
694
+ tclInterp = GET_CTX_TCL_INTERP(ctx);
695
+ if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
696
+ Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
697
+ return TH_ERROR;
698
+ }
699
+ if( Tcl_IsSafe(tclInterp) ){
700
+ Th_ErrorMessage(interp,
701
+ "Tcl interpreter is already 'safe'", (const char *)"", 0);
702
+ return TH_ERROR;
703
+ }
704
+ if( registerChans ){
705
+ /*
706
+ ** HACK: Prevent the call to Tcl_MakeSafe() from actually closing the
707
+ ** standard channels instead of simply unregistering them from
708
+ ** the Tcl interpreter. This should only need to be done once
709
+ ** per thread (process?).
710
+ */
711
+ registerChans = 0;
712
+ Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDIN));
713
+ Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDOUT));
714
+ Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDERR));
715
+ }
716
+ Tcl_Preserve((ClientData)tclInterp);
717
+ if( Tcl_MakeSafe(tclInterp)!=TCL_OK ){
718
+ int nResult;
719
+ const char *zResult = getTclResult(tclInterp, &nResult);
720
+ Th_ErrorMessage(interp,
721
+ "could not make Tcl interpreter 'safe':", zResult, nResult);
722
+ rc = TH_ERROR;
723
+ }else{
724
+ Th_SetResult(interp, 0, 0);
725
+ }
726
+ Tcl_Release((ClientData)tclInterp);
727
+ return rc;
728
+}
637729
638730
/*
639731
** Tcl command: th1Eval arg
640732
**
641733
** Evaluates the TH1 script and returns its result verbatim. If a TH1 script
@@ -708,13 +800,15 @@
708800
static struct _Command {
709801
const char *zName;
710802
Th_CommandProc xProc;
711803
void *pContext;
712804
} aCommand[] = {
713
- {"tclEval", tclEval_command, 0},
714
- {"tclExpr", tclExpr_command, 0},
715
- {"tclInvoke", tclInvoke_command, 0},
805
+ {"tclEval", tclEval_command, 0},
806
+ {"tclExpr", tclExpr_command, 0},
807
+ {"tclInvoke", tclInvoke_command, 0},
808
+ {"tclIsSafe", tclIsSafe_command, 0},
809
+ {"tclMakeSafe", tclMakeSafe_command, 0},
716810
{0, 0, 0}
717811
};
718812
719813
/*
720814
** Called if the Tcl interpreter is deleted. Removes the Tcl integration
@@ -791,10 +885,11 @@
791885
if( zDirName ){
792886
fossil_free(zDirName); zDirName = 0;
793887
}
794888
#endif /* TCL_USE_SET_DLL_DIRECTORY */
795889
}
890
+ if( !zFileName ) break;
796891
hLibrary = dlopen(zFileName, RTLD_NOW | RTLD_GLOBAL);
797892
/* NOTE: If the file name was allocated, free it now. */
798893
if( zFileName!=aFileName ){
799894
sqlite3_free(zFileName); zFileName = 0;
800895
}
@@ -991,11 +1086,11 @@
9911086
struct TclContext *tclContext = (struct TclContext *)pContext;
9921087
int argc;
9931088
char **argv;
9941089
char *argv0 = 0;
9951090
Tcl_Interp *tclInterp;
996
- char *setup;
1091
+ const char *setup;
9971092
9981093
if( !tclContext ){
9991094
Th_ErrorMessage(interp,
10001095
"invalid Tcl context", (const char *)"", 0);
10011096
return TH_ERROR;
10021097
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -82,10 +82,11 @@
82 # if defined(_WIN32)
83 # if !defined(WIN32_LEAN_AND_MEAN)
84 # define WIN32_LEAN_AND_MEAN
85 # endif
86 # if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0502)
 
87 # define _WIN32_WINNT 0x0502 /* SetDllDirectory, Windows XP SP2 */
88 # endif
89 # include <windows.h>
90 # ifndef TCL_DIRECTORY_SEP
91 # define TCL_DIRECTORY_SEP '\\'
@@ -342,11 +343,11 @@
342 */
343 static const char *getTclReturnCodeName(
344 int rc,
345 int nullIfOk
346 ){
347 static char zRc[32];
348
349 switch( rc ){
350 case TCL_OK: return nullIfOk ? 0 : "TCL_OK";
351 case TCL_ERROR: return "TCL_ERROR";
352 case TCL_RETURN: return "TCL_RETURN";
@@ -395,11 +396,11 @@
395 tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
396 tcl_FinalizeProc *xFinalize; /* Tcl_Finalize() pointer. */
397 Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
398 int useObjProc; /* Non-zero if an objProc can be called directly. */
399 int useTip285; /* Non-zero if TIP #285 is available. */
400 char *setup; /* The optional Tcl setup script. */
401 tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
402 void *pPreContext; /* Optional, provided to xPreEval(). */
403 tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
404 void *pPostContext; /* Optional, provided to xPostEval(). */
405 };
@@ -438,12 +439,12 @@
438
439 /*
440 ** TH1 command: tclEval arg ?arg ...?
441 **
442 ** Evaluates the Tcl script and returns its result verbatim. If a Tcl script
443 ** error is generated, it will be transformed into a TH1 script error. A Tcl
444 ** interpreter will be created automatically if it has not been already.
445 */
446 static int tclEval_command(
447 Th_Interp *interp,
448 void *ctx,
449 int argc,
@@ -497,11 +498,12 @@
497 /*
498 ** TH1 command: tclExpr arg ?arg ...?
499 **
500 ** Evaluates the Tcl expression and returns its result verbatim. If a Tcl
501 ** script error is generated, it will be transformed into a TH1 script error.
502 ** A Tcl interpreter will be created automatically if it has not been already.
 
503 */
504 static int tclExpr_command(
505 Th_Interp *interp,
506 void *ctx,
507 int argc,
@@ -562,12 +564,12 @@
562
563 /*
564 ** TH1 command: tclInvoke command ?arg ...?
565 **
566 ** Invokes the Tcl command using the supplied arguments. No additional
567 ** substitutions are performed on the arguments. A Tcl interpreter will
568 ** be created automatically if it has not been already.
569 */
570 static int tclInvoke_command(
571 Th_Interp *interp,
572 void *ctx,
573 int argc,
@@ -632,10 +634,100 @@
632 Tcl_Release((ClientData)tclInterp);
633 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
634 getTh1ReturnCode(rc));
635 return rc;
636 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
637
638 /*
639 ** Tcl command: th1Eval arg
640 **
641 ** Evaluates the TH1 script and returns its result verbatim. If a TH1 script
@@ -708,13 +800,15 @@
708 static struct _Command {
709 const char *zName;
710 Th_CommandProc xProc;
711 void *pContext;
712 } aCommand[] = {
713 {"tclEval", tclEval_command, 0},
714 {"tclExpr", tclExpr_command, 0},
715 {"tclInvoke", tclInvoke_command, 0},
 
 
716 {0, 0, 0}
717 };
718
719 /*
720 ** Called if the Tcl interpreter is deleted. Removes the Tcl integration
@@ -791,10 +885,11 @@
791 if( zDirName ){
792 fossil_free(zDirName); zDirName = 0;
793 }
794 #endif /* TCL_USE_SET_DLL_DIRECTORY */
795 }
 
796 hLibrary = dlopen(zFileName, RTLD_NOW | RTLD_GLOBAL);
797 /* NOTE: If the file name was allocated, free it now. */
798 if( zFileName!=aFileName ){
799 sqlite3_free(zFileName); zFileName = 0;
800 }
@@ -991,11 +1086,11 @@
991 struct TclContext *tclContext = (struct TclContext *)pContext;
992 int argc;
993 char **argv;
994 char *argv0 = 0;
995 Tcl_Interp *tclInterp;
996 char *setup;
997
998 if( !tclContext ){
999 Th_ErrorMessage(interp,
1000 "invalid Tcl context", (const char *)"", 0);
1001 return TH_ERROR;
1002
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -82,10 +82,11 @@
82 # if defined(_WIN32)
83 # if !defined(WIN32_LEAN_AND_MEAN)
84 # define WIN32_LEAN_AND_MEAN
85 # endif
86 # if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0502)
87 # undef _WIN32_WINNT
88 # define _WIN32_WINNT 0x0502 /* SetDllDirectory, Windows XP SP2 */
89 # endif
90 # include <windows.h>
91 # ifndef TCL_DIRECTORY_SEP
92 # define TCL_DIRECTORY_SEP '\\'
@@ -342,11 +343,11 @@
343 */
344 static const char *getTclReturnCodeName(
345 int rc,
346 int nullIfOk
347 ){
348 static char zRc[TCL_INTEGER_SPACE + 17]; /* "Tcl return code\0" */
349
350 switch( rc ){
351 case TCL_OK: return nullIfOk ? 0 : "TCL_OK";
352 case TCL_ERROR: return "TCL_ERROR";
353 case TCL_RETURN: return "TCL_RETURN";
@@ -395,11 +396,11 @@
396 tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
397 tcl_FinalizeProc *xFinalize; /* Tcl_Finalize() pointer. */
398 Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
399 int useObjProc; /* Non-zero if an objProc can be called directly. */
400 int useTip285; /* Non-zero if TIP #285 is available. */
401 const char *setup; /* The optional Tcl setup script. */
402 tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
403 void *pPreContext; /* Optional, provided to xPreEval(). */
404 tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
405 void *pPostContext; /* Optional, provided to xPostEval(). */
406 };
@@ -438,12 +439,12 @@
439
440 /*
441 ** TH1 command: tclEval arg ?arg ...?
442 **
443 ** Evaluates the Tcl script and returns its result verbatim. If a Tcl script
444 ** error is generated, it will be transformed into a TH1 script error. The
445 ** Tcl interpreter will be created automatically if it has not been already.
446 */
447 static int tclEval_command(
448 Th_Interp *interp,
449 void *ctx,
450 int argc,
@@ -497,11 +498,12 @@
498 /*
499 ** TH1 command: tclExpr arg ?arg ...?
500 **
501 ** Evaluates the Tcl expression and returns its result verbatim. If a Tcl
502 ** script error is generated, it will be transformed into a TH1 script error.
503 ** The Tcl interpreter will be created automatically if it has not been
504 ** already.
505 */
506 static int tclExpr_command(
507 Th_Interp *interp,
508 void *ctx,
509 int argc,
@@ -562,12 +564,12 @@
564
565 /*
566 ** TH1 command: tclInvoke command ?arg ...?
567 **
568 ** Invokes the Tcl command using the supplied arguments. No additional
569 ** substitutions are performed on the arguments. The Tcl interpreter
570 ** will be created automatically if it has not been already.
571 */
572 static int tclInvoke_command(
573 Th_Interp *interp,
574 void *ctx,
575 int argc,
@@ -632,10 +634,100 @@
634 Tcl_Release((ClientData)tclInterp);
635 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
636 getTh1ReturnCode(rc));
637 return rc;
638 }
639
640 /*
641 ** TH1 command: tclIsSafe
642 **
643 ** Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter
644 ** will be created automatically if it has not been already.
645 */
646 static int tclIsSafe_command(
647 Th_Interp *interp,
648 void *ctx,
649 int argc,
650 const char **argv,
651 int *argl
652 ){
653 Tcl_Interp *tclInterp;
654
655 if( createTclInterp(interp, ctx)!=TH_OK ){
656 return TH_ERROR;
657 }
658 if( argc!=1 ){
659 return Th_WrongNumArgs(interp, "tclIsSafe");
660 }
661 tclInterp = GET_CTX_TCL_INTERP(ctx);
662 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
663 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
664 return TH_ERROR;
665 }
666 Th_SetResultInt(interp, Tcl_IsSafe(tclInterp));
667 return TH_OK;
668 }
669
670 /*
671 ** TH1 command: tclMakeSafe
672 **
673 ** Forces the Tcl interpreter into "safe" mode by removing all "unsafe"
674 ** commands and variables. This operation cannot be undone. The Tcl
675 ** interpreter will remain "safe" until the process terminates.
676 */
677 static int tclMakeSafe_command(
678 Th_Interp *interp,
679 void *ctx,
680 int argc,
681 const char **argv,
682 int *argl
683 ){
684 static int registerChans = 1;
685 Tcl_Interp *tclInterp;
686 int rc = TH_OK;
687
688 if( createTclInterp(interp, ctx)!=TH_OK ){
689 return TH_ERROR;
690 }
691 if( argc!=1 ){
692 return Th_WrongNumArgs(interp, "tclMakeSafe");
693 }
694 tclInterp = GET_CTX_TCL_INTERP(ctx);
695 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
696 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
697 return TH_ERROR;
698 }
699 if( Tcl_IsSafe(tclInterp) ){
700 Th_ErrorMessage(interp,
701 "Tcl interpreter is already 'safe'", (const char *)"", 0);
702 return TH_ERROR;
703 }
704 if( registerChans ){
705 /*
706 ** HACK: Prevent the call to Tcl_MakeSafe() from actually closing the
707 ** standard channels instead of simply unregistering them from
708 ** the Tcl interpreter. This should only need to be done once
709 ** per thread (process?).
710 */
711 registerChans = 0;
712 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDIN));
713 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDOUT));
714 Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDERR));
715 }
716 Tcl_Preserve((ClientData)tclInterp);
717 if( Tcl_MakeSafe(tclInterp)!=TCL_OK ){
718 int nResult;
719 const char *zResult = getTclResult(tclInterp, &nResult);
720 Th_ErrorMessage(interp,
721 "could not make Tcl interpreter 'safe':", zResult, nResult);
722 rc = TH_ERROR;
723 }else{
724 Th_SetResult(interp, 0, 0);
725 }
726 Tcl_Release((ClientData)tclInterp);
727 return rc;
728 }
729
730 /*
731 ** Tcl command: th1Eval arg
732 **
733 ** Evaluates the TH1 script and returns its result verbatim. If a TH1 script
@@ -708,13 +800,15 @@
800 static struct _Command {
801 const char *zName;
802 Th_CommandProc xProc;
803 void *pContext;
804 } aCommand[] = {
805 {"tclEval", tclEval_command, 0},
806 {"tclExpr", tclExpr_command, 0},
807 {"tclInvoke", tclInvoke_command, 0},
808 {"tclIsSafe", tclIsSafe_command, 0},
809 {"tclMakeSafe", tclMakeSafe_command, 0},
810 {0, 0, 0}
811 };
812
813 /*
814 ** Called if the Tcl interpreter is deleted. Removes the Tcl integration
@@ -791,10 +885,11 @@
885 if( zDirName ){
886 fossil_free(zDirName); zDirName = 0;
887 }
888 #endif /* TCL_USE_SET_DLL_DIRECTORY */
889 }
890 if( !zFileName ) break;
891 hLibrary = dlopen(zFileName, RTLD_NOW | RTLD_GLOBAL);
892 /* NOTE: If the file name was allocated, free it now. */
893 if( zFileName!=aFileName ){
894 sqlite3_free(zFileName); zFileName = 0;
895 }
@@ -991,11 +1086,11 @@
1086 struct TclContext *tclContext = (struct TclContext *)pContext;
1087 int argc;
1088 char **argv;
1089 char *argv0 = 0;
1090 Tcl_Interp *tclInterp;
1091 const char *setup;
1092
1093 if( !tclContext ){
1094 Th_ErrorMessage(interp,
1095 "invalid Tcl context", (const char *)"", 0);
1096 return TH_ERROR;
1097
+108 -26
--- src/undo.c
+++ src/undo.c
@@ -18,11 +18,20 @@
1818
** This file implements the undo/redo functionality.
1919
*/
2020
#include "config.h"
2121
#include "undo.h"
2222
23
-
23
+#if INTERFACE
24
+/*
25
+** Possible return values from the undo_maybe_save() routine.
26
+*/
27
+#define UNDO_NONE (0) /* Placeholder only used to initialize vars. */
28
+#define UNDO_SAVED_OK (1) /* The specified file was saved succesfully. */
29
+#define UNDO_DISABLED (2) /* File not saved, subsystem is disabled. */
30
+#define UNDO_INACTIVE (3) /* File not saved, subsystem is not active. */
31
+#define UNDO_TOOBIG (4) /* File not saved, it exceeded a size limit. */
32
+#endif
2433
2534
/*
2635
** Undo the change to the file zPathname. zPathname is the pathname
2736
** of the file relative to the root of the repository. If redoFlag is
2837
** true the redo a change. If there is nothing to undo (or redo) then
@@ -261,41 +270,111 @@
261270
** Save the current content of the file zPathname so that it
262271
** will be undoable. The name is relative to the root of the
263272
** tree.
264273
*/
265274
void undo_save(const char *zPathname){
275
+ if( undoDisable ) return;
276
+ if( undo_maybe_save(zPathname, -1)!=UNDO_SAVED_OK ){
277
+ fossil_panic("failed to save undo information for path: %s",
278
+ zPathname);
279
+ }
280
+}
281
+
282
+/*
283
+** Possibly save the current content of the file zPathname so
284
+** that it will be undoable. The name is relative to the root
285
+** of the tree. The limit argument may be used to specify the
286
+** maximum size for the file to be saved. If the size of the
287
+** specified file exceeds this size limit (in bytes), it will
288
+** not be saved and an appropriate code will be returned.
289
+**
290
+** WARNING: Please do NOT call this function with a limit
291
+** value less than zero, call the undo_save()
292
+** function instead.
293
+**
294
+** The return value of this function will always be one of the
295
+** following codes:
296
+**
297
+** UNDO_SAVED_OK: The specified file was saved succesfully.
298
+**
299
+** UNDO_DISABLED: The specified file was NOT saved, because the
300
+** "undo subsystem" is disabled. This error may
301
+** indicate that a call to undo_disable() was
302
+** issued.
303
+**
304
+** UNDO_INACTIVE: The specified file was NOT saved, because the
305
+** "undo subsystem" is not active. This error
306
+** may indicate that a call to undo_begin() is
307
+** missing.
308
+**
309
+** UNDO_TOOBIG: The specified file was NOT saved, because it
310
+** exceeded the specified size limit. It is
311
+** impossible for this value to be returned if
312
+** the specified size limit is less than zero
313
+** (i.e. unlimited).
314
+*/
315
+int undo_maybe_save(const char *zPathname, i64 limit){
266316
char *zFullname;
267
- Blob content;
268
- int existsFlag;
269
- int isLink;
270
- Stmt q;
317
+ i64 size;
318
+ int result;
271319
272
- if( !undoActive ) return;
320
+ if( undoDisable ) return UNDO_DISABLED;
321
+ if( !undoActive ) return UNDO_INACTIVE;
273322
zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
274
- existsFlag = file_wd_size(zFullname)>=0;
275
- isLink = file_wd_islink(zFullname);
276
- db_prepare(&q,
277
- "INSERT OR IGNORE INTO"
278
- " undo(pathname,redoflag,existsflag,isExe,isLink,content)"
279
- " VALUES(%Q,0,%d,%d,%d,:c)",
280
- zPathname, existsFlag, file_wd_isexe(zFullname), isLink
281
- );
282
- if( existsFlag ){
283
- if( isLink ){
284
- blob_read_link(&content, zFullname);
285
- }else{
286
- blob_read_from_file(&content, zFullname);
287
- }
288
- db_bind_blob(&q, ":c", &content);
323
+ size = file_wd_size(zFullname);
324
+ if( limit<0 || size<=limit ){
325
+ int existsFlag = (size>=0);
326
+ int isLink = file_wd_islink(zFullname);
327
+ Stmt q;
328
+ Blob content;
329
+ db_prepare(&q,
330
+ "INSERT OR IGNORE INTO"
331
+ " undo(pathname,redoflag,existsflag,isExe,isLink,content)"
332
+ " VALUES(%Q,0,%d,%d,%d,:c)",
333
+ zPathname, existsFlag, file_wd_isexe(zFullname), isLink
334
+ );
335
+ if( existsFlag ){
336
+ if( isLink ){
337
+ blob_read_link(&content, zFullname);
338
+ }else{
339
+ blob_read_from_file(&content, zFullname);
340
+ }
341
+ db_bind_blob(&q, ":c", &content);
342
+ }
343
+ db_step(&q);
344
+ db_finalize(&q);
345
+ if( existsFlag ){
346
+ blob_reset(&content);
347
+ }
348
+ undoNeedRollback = 1;
349
+ result = UNDO_SAVED_OK;
350
+ }else{
351
+ result = UNDO_TOOBIG;
289352
}
290353
free(zFullname);
291
- db_step(&q);
292
- db_finalize(&q);
293
- if( existsFlag ){
294
- blob_reset(&content);
354
+ return result;
355
+}
356
+
357
+/*
358
+** Returns an error message for the undo_maybe_save() return code.
359
+** Currently, this function assumes that the caller is using the
360
+** returned error message in a context prefixed with "because".
361
+*/
362
+const char *undo_save_message(int rc){
363
+ static char zRc[32];
364
+
365
+ switch( rc ){
366
+ case UNDO_NONE: return "undo is disabled for this operation";
367
+ case UNDO_SAVED_OK: return "the save operation was successful";
368
+ case UNDO_DISABLED: return "the undo subsystem is disabled";
369
+ case UNDO_INACTIVE: return "the undo subsystem is inactive";
370
+ case UNDO_TOOBIG: return "the file is too big";
371
+ default: {
372
+ sqlite3_snprintf(sizeof(zRc), zRc, "of error code %d", rc);
373
+ }
295374
}
296
- undoNeedRollback = 1;
375
+ return zRc;
297376
}
298377
299378
/*
300379
** Make the current state of stashid undoable.
301380
*/
@@ -361,10 +440,13 @@
361440
**
362441
** (1) fossil update (5) fossil stash apply
363442
** (2) fossil merge (6) fossil stash drop
364443
** (3) fossil revert (7) fossil stash goto
365444
** (4) fossil stash pop
445
+**
446
+** The "fossil clean" operation can also be undone; however, this is
447
+** currently limited to files that are less than 10MiB in size.
366448
**
367449
** If FILENAME is specified then restore the content of the named
368450
** file(s) but otherwise leave the update or merge or revert in effect.
369451
** The redo command undoes the effect of the most recent undo.
370452
**
371453
--- src/undo.c
+++ src/undo.c
@@ -18,11 +18,20 @@
18 ** This file implements the undo/redo functionality.
19 */
20 #include "config.h"
21 #include "undo.h"
22
23
 
 
 
 
 
 
 
 
 
24
25 /*
26 ** Undo the change to the file zPathname. zPathname is the pathname
27 ** of the file relative to the root of the repository. If redoFlag is
28 ** true the redo a change. If there is nothing to undo (or redo) then
@@ -261,41 +270,111 @@
261 ** Save the current content of the file zPathname so that it
262 ** will be undoable. The name is relative to the root of the
263 ** tree.
264 */
265 void undo_save(const char *zPathname){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266 char *zFullname;
267 Blob content;
268 int existsFlag;
269 int isLink;
270 Stmt q;
271
272 if( !undoActive ) return;
 
273 zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
274 existsFlag = file_wd_size(zFullname)>=0;
275 isLink = file_wd_islink(zFullname);
276 db_prepare(&q,
277 "INSERT OR IGNORE INTO"
278 " undo(pathname,redoflag,existsflag,isExe,isLink,content)"
279 " VALUES(%Q,0,%d,%d,%d,:c)",
280 zPathname, existsFlag, file_wd_isexe(zFullname), isLink
281 );
282 if( existsFlag ){
283 if( isLink ){
284 blob_read_link(&content, zFullname);
285 }else{
286 blob_read_from_file(&content, zFullname);
287 }
288 db_bind_blob(&q, ":c", &content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289 }
290 free(zFullname);
291 db_step(&q);
292 db_finalize(&q);
293 if( existsFlag ){
294 blob_reset(&content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295 }
296 undoNeedRollback = 1;
297 }
298
299 /*
300 ** Make the current state of stashid undoable.
301 */
@@ -361,10 +440,13 @@
361 **
362 ** (1) fossil update (5) fossil stash apply
363 ** (2) fossil merge (6) fossil stash drop
364 ** (3) fossil revert (7) fossil stash goto
365 ** (4) fossil stash pop
 
 
 
366 **
367 ** If FILENAME is specified then restore the content of the named
368 ** file(s) but otherwise leave the update or merge or revert in effect.
369 ** The redo command undoes the effect of the most recent undo.
370 **
371
--- src/undo.c
+++ src/undo.c
@@ -18,11 +18,20 @@
18 ** This file implements the undo/redo functionality.
19 */
20 #include "config.h"
21 #include "undo.h"
22
23 #if INTERFACE
24 /*
25 ** Possible return values from the undo_maybe_save() routine.
26 */
27 #define UNDO_NONE (0) /* Placeholder only used to initialize vars. */
28 #define UNDO_SAVED_OK (1) /* The specified file was saved succesfully. */
29 #define UNDO_DISABLED (2) /* File not saved, subsystem is disabled. */
30 #define UNDO_INACTIVE (3) /* File not saved, subsystem is not active. */
31 #define UNDO_TOOBIG (4) /* File not saved, it exceeded a size limit. */
32 #endif
33
34 /*
35 ** Undo the change to the file zPathname. zPathname is the pathname
36 ** of the file relative to the root of the repository. If redoFlag is
37 ** true the redo a change. If there is nothing to undo (or redo) then
@@ -261,41 +270,111 @@
270 ** Save the current content of the file zPathname so that it
271 ** will be undoable. The name is relative to the root of the
272 ** tree.
273 */
274 void undo_save(const char *zPathname){
275 if( undoDisable ) return;
276 if( undo_maybe_save(zPathname, -1)!=UNDO_SAVED_OK ){
277 fossil_panic("failed to save undo information for path: %s",
278 zPathname);
279 }
280 }
281
282 /*
283 ** Possibly save the current content of the file zPathname so
284 ** that it will be undoable. The name is relative to the root
285 ** of the tree. The limit argument may be used to specify the
286 ** maximum size for the file to be saved. If the size of the
287 ** specified file exceeds this size limit (in bytes), it will
288 ** not be saved and an appropriate code will be returned.
289 **
290 ** WARNING: Please do NOT call this function with a limit
291 ** value less than zero, call the undo_save()
292 ** function instead.
293 **
294 ** The return value of this function will always be one of the
295 ** following codes:
296 **
297 ** UNDO_SAVED_OK: The specified file was saved succesfully.
298 **
299 ** UNDO_DISABLED: The specified file was NOT saved, because the
300 ** "undo subsystem" is disabled. This error may
301 ** indicate that a call to undo_disable() was
302 ** issued.
303 **
304 ** UNDO_INACTIVE: The specified file was NOT saved, because the
305 ** "undo subsystem" is not active. This error
306 ** may indicate that a call to undo_begin() is
307 ** missing.
308 **
309 ** UNDO_TOOBIG: The specified file was NOT saved, because it
310 ** exceeded the specified size limit. It is
311 ** impossible for this value to be returned if
312 ** the specified size limit is less than zero
313 ** (i.e. unlimited).
314 */
315 int undo_maybe_save(const char *zPathname, i64 limit){
316 char *zFullname;
317 i64 size;
318 int result;
 
 
319
320 if( undoDisable ) return UNDO_DISABLED;
321 if( !undoActive ) return UNDO_INACTIVE;
322 zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
323 size = file_wd_size(zFullname);
324 if( limit<0 || size<=limit ){
325 int existsFlag = (size>=0);
326 int isLink = file_wd_islink(zFullname);
327 Stmt q;
328 Blob content;
329 db_prepare(&q,
330 "INSERT OR IGNORE INTO"
331 " undo(pathname,redoflag,existsflag,isExe,isLink,content)"
332 " VALUES(%Q,0,%d,%d,%d,:c)",
333 zPathname, existsFlag, file_wd_isexe(zFullname), isLink
334 );
335 if( existsFlag ){
336 if( isLink ){
337 blob_read_link(&content, zFullname);
338 }else{
339 blob_read_from_file(&content, zFullname);
340 }
341 db_bind_blob(&q, ":c", &content);
342 }
343 db_step(&q);
344 db_finalize(&q);
345 if( existsFlag ){
346 blob_reset(&content);
347 }
348 undoNeedRollback = 1;
349 result = UNDO_SAVED_OK;
350 }else{
351 result = UNDO_TOOBIG;
352 }
353 free(zFullname);
354 return result;
355 }
356
357 /*
358 ** Returns an error message for the undo_maybe_save() return code.
359 ** Currently, this function assumes that the caller is using the
360 ** returned error message in a context prefixed with "because".
361 */
362 const char *undo_save_message(int rc){
363 static char zRc[32];
364
365 switch( rc ){
366 case UNDO_NONE: return "undo is disabled for this operation";
367 case UNDO_SAVED_OK: return "the save operation was successful";
368 case UNDO_DISABLED: return "the undo subsystem is disabled";
369 case UNDO_INACTIVE: return "the undo subsystem is inactive";
370 case UNDO_TOOBIG: return "the file is too big";
371 default: {
372 sqlite3_snprintf(sizeof(zRc), zRc, "of error code %d", rc);
373 }
374 }
375 return zRc;
376 }
377
378 /*
379 ** Make the current state of stashid undoable.
380 */
@@ -361,10 +440,13 @@
440 **
441 ** (1) fossil update (5) fossil stash apply
442 ** (2) fossil merge (6) fossil stash drop
443 ** (3) fossil revert (7) fossil stash goto
444 ** (4) fossil stash pop
445 **
446 ** The "fossil clean" operation can also be undone; however, this is
447 ** currently limited to files that are less than 10MiB in size.
448 **
449 ** If FILENAME is specified then restore the content of the named
450 ** file(s) but otherwise leave the update or merge or revert in effect.
451 ** The redo command undoes the effect of the most recent undo.
452 **
453
+6 -5
--- src/update.c
+++ src/update.c
@@ -424,26 +424,26 @@
424424
fossil_print("ADD %s - overwrites an unmanaged file\n", zName);
425425
nOverwrite++;
426426
}else{
427427
fossil_print("ADD %s\n", zName);
428428
}
429
- undo_save(zName);
429
+ if( !dryRunFlag && !internalUpdate ) undo_save(zName);
430430
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
431431
}else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){
432432
/* The file is unedited. Change it to the target version */
433
- undo_save(zName);
434433
if( deleted ){
435434
fossil_print("UPDATE %s - change to unmanaged file\n", zName);
436435
}else{
437436
fossil_print("UPDATE %s\n", zName);
438437
}
438
+ if( !dryRunFlag && !internalUpdate ) undo_save(zName);
439439
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
440440
}else if( idt>0 && idv>0 && !deleted && file_wd_size(zFullPath)<0 ){
441441
/* The file missing from the local check-out. Restore it to the
442442
** version that appears in the target. */
443443
fossil_print("UPDATE %s\n", zName);
444
- undo_save(zName);
444
+ if( !dryRunFlag && !internalUpdate ) undo_save(zName);
445445
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
446446
}else if( idt==0 && idv>0 ){
447447
if( ridv==0 ){
448448
/* Added in current checkout. Continue to hold the file as
449449
** as an addition */
@@ -454,11 +454,11 @@
454454
fossil_print("CONFLICT %s - edited locally but deleted by update\n",
455455
zName);
456456
nConflict++;
457457
}else{
458458
fossil_print("REMOVE %s\n", zName);
459
- undo_save(zName);
459
+ if( !dryRunFlag && !internalUpdate ) undo_save(zName);
460460
if( !dryRunFlag ) file_delete(zFullPath);
461461
}
462462
}else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
463463
/* Merge the changes in the current tree into the target version */
464464
Blob r, t, v;
@@ -471,11 +471,11 @@
471471
if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
472472
fossil_print("***** Cannot merge symlink %s\n", zNewName);
473473
nConflict++;
474474
}else{
475475
unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
476
- undo_save(zName);
476
+ if( !dryRunFlag && !internalUpdate ) undo_save(zName);
477477
content_get(ridt, &t);
478478
content_get(ridv, &v);
479479
rc = merge_3way(&v, zFullPath, &t, &r, mergeFlags);
480480
if( rc>=0 ){
481481
if( !dryRunFlag ){
@@ -738,10 +738,11 @@
738738
739739
if( g.argc>2 ){
740740
for(i=2; i<g.argc; i++){
741741
Blob fname;
742742
zFile = mprintf("%/", g.argv[i]);
743
+ blob_zero(&fname);
743744
file_tree_name(zFile, &fname, 0, 1);
744745
db_multi_exec(
745746
"REPLACE INTO torevert VALUES(%B);"
746747
"INSERT OR IGNORE INTO torevert"
747748
" SELECT pathname"
748749
--- src/update.c
+++ src/update.c
@@ -424,26 +424,26 @@
424 fossil_print("ADD %s - overwrites an unmanaged file\n", zName);
425 nOverwrite++;
426 }else{
427 fossil_print("ADD %s\n", zName);
428 }
429 undo_save(zName);
430 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
431 }else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){
432 /* The file is unedited. Change it to the target version */
433 undo_save(zName);
434 if( deleted ){
435 fossil_print("UPDATE %s - change to unmanaged file\n", zName);
436 }else{
437 fossil_print("UPDATE %s\n", zName);
438 }
 
439 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
440 }else if( idt>0 && idv>0 && !deleted && file_wd_size(zFullPath)<0 ){
441 /* The file missing from the local check-out. Restore it to the
442 ** version that appears in the target. */
443 fossil_print("UPDATE %s\n", zName);
444 undo_save(zName);
445 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
446 }else if( idt==0 && idv>0 ){
447 if( ridv==0 ){
448 /* Added in current checkout. Continue to hold the file as
449 ** as an addition */
@@ -454,11 +454,11 @@
454 fossil_print("CONFLICT %s - edited locally but deleted by update\n",
455 zName);
456 nConflict++;
457 }else{
458 fossil_print("REMOVE %s\n", zName);
459 undo_save(zName);
460 if( !dryRunFlag ) file_delete(zFullPath);
461 }
462 }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
463 /* Merge the changes in the current tree into the target version */
464 Blob r, t, v;
@@ -471,11 +471,11 @@
471 if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
472 fossil_print("***** Cannot merge symlink %s\n", zNewName);
473 nConflict++;
474 }else{
475 unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
476 undo_save(zName);
477 content_get(ridt, &t);
478 content_get(ridv, &v);
479 rc = merge_3way(&v, zFullPath, &t, &r, mergeFlags);
480 if( rc>=0 ){
481 if( !dryRunFlag ){
@@ -738,10 +738,11 @@
738
739 if( g.argc>2 ){
740 for(i=2; i<g.argc; i++){
741 Blob fname;
742 zFile = mprintf("%/", g.argv[i]);
 
743 file_tree_name(zFile, &fname, 0, 1);
744 db_multi_exec(
745 "REPLACE INTO torevert VALUES(%B);"
746 "INSERT OR IGNORE INTO torevert"
747 " SELECT pathname"
748
--- src/update.c
+++ src/update.c
@@ -424,26 +424,26 @@
424 fossil_print("ADD %s - overwrites an unmanaged file\n", zName);
425 nOverwrite++;
426 }else{
427 fossil_print("ADD %s\n", zName);
428 }
429 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
430 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
431 }else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){
432 /* The file is unedited. Change it to the target version */
 
433 if( deleted ){
434 fossil_print("UPDATE %s - change to unmanaged file\n", zName);
435 }else{
436 fossil_print("UPDATE %s\n", zName);
437 }
438 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
439 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
440 }else if( idt>0 && idv>0 && !deleted && file_wd_size(zFullPath)<0 ){
441 /* The file missing from the local check-out. Restore it to the
442 ** version that appears in the target. */
443 fossil_print("UPDATE %s\n", zName);
444 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
445 if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
446 }else if( idt==0 && idv>0 ){
447 if( ridv==0 ){
448 /* Added in current checkout. Continue to hold the file as
449 ** as an addition */
@@ -454,11 +454,11 @@
454 fossil_print("CONFLICT %s - edited locally but deleted by update\n",
455 zName);
456 nConflict++;
457 }else{
458 fossil_print("REMOVE %s\n", zName);
459 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
460 if( !dryRunFlag ) file_delete(zFullPath);
461 }
462 }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
463 /* Merge the changes in the current tree into the target version */
464 Blob r, t, v;
@@ -471,11 +471,11 @@
471 if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
472 fossil_print("***** Cannot merge symlink %s\n", zNewName);
473 nConflict++;
474 }else{
475 unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
476 if( !dryRunFlag && !internalUpdate ) undo_save(zName);
477 content_get(ridt, &t);
478 content_get(ridv, &v);
479 rc = merge_3way(&v, zFullPath, &t, &r, mergeFlags);
480 if( rc>=0 ){
481 if( !dryRunFlag ){
@@ -738,10 +738,11 @@
738
739 if( g.argc>2 ){
740 for(i=2; i<g.argc; i++){
741 Blob fname;
742 zFile = mprintf("%/", g.argv[i]);
743 blob_zero(&fname);
744 file_tree_name(zFile, &fname, 0, 1);
745 db_multi_exec(
746 "REPLACE INTO torevert VALUES(%B);"
747 "INSERT OR IGNORE INTO torevert"
748 " SELECT pathname"
749
+14 -9
--- src/utf8.c
+++ src/utf8.c
@@ -77,11 +77,11 @@
7777
** used to store the returned pointer when done.
7878
*/
7979
void *fossil_utf8_to_unicode(const char *zUtf8){
8080
#if defined(_WIN32) || defined(__CYGWIN__)
8181
int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
82
- wchar_t *zUnicode = fossil_malloc( nByte * 2 );
82
+ wchar_t *zUnicode = fossil_malloc( nByte*2 );
8383
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
8484
return zUnicode;
8585
#else
8686
assert( 0 ); /* Never used in unix */
8787
return fossil_strdup(zUtf8); /* TODO: implement for unix */
@@ -304,11 +304,15 @@
304304
** Display UTF-8 on the console. Return the number of
305305
** Characters written. If stdout or stderr is redirected
306306
** to a file, -1 is returned and nothing is written
307307
** to the console.
308308
*/
309
-int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){
309
+int fossil_utf8_to_console(
310
+ const char *zUtf8,
311
+ int nByte,
312
+ int toStdErr
313
+){
310314
#ifdef _WIN32
311315
int nChar, written = 0;
312316
wchar_t *zUnicode; /* Unicode version of zUtf8 */
313317
DWORD dummy;
314318
Blob blob;
@@ -327,27 +331,28 @@
327331
*/
328332
blob_init(&blob, zUtf8, nByte);
329333
blob_to_utf8_no_bom(&blob, 1);
330334
nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
331335
blob_size(&blob), NULL, 0);
332
- zUnicode = malloc( (nChar + 1) *sizeof(zUnicode[0]) );
336
+ zUnicode = fossil_malloc( (nChar+1)*sizeof(zUnicode[0]) );
333337
if( zUnicode==0 ){
334338
return 0;
335339
}
336340
nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
337341
blob_size(&blob), zUnicode, nChar);
338342
blob_reset(&blob);
339
- /* Split WriteConsoleW call into multiple chunks, if necessary. See:
343
+ /* Split WriteConsoleW output into multiple chunks, if necessary. See:
340344
* <https://connect.microsoft.com/VisualStudio/feedback/details/635230> */
341
- while( written < nChar ){
345
+ while( written<nChar ){
342346
int size = nChar-written;
343
- if( size > 26000 ) size = 26000;
344
- WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode+written,
345
- size, &dummy, 0);
347
+ if( size>26000 ) size = 26000;
348
+ WriteConsoleW(GetStdHandle(
349
+ toStdErr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE),
350
+ zUnicode + written, size, &dummy, 0);
346351
written += size;
347352
}
348
- free(zUnicode);
353
+ fossil_free(zUnicode);
349354
return nChar;
350355
#else
351356
return -1; /* No-op on unix */
352357
#endif
353358
}
354359
355360
ADDED test/clean.test
--- src/utf8.c
+++ src/utf8.c
@@ -77,11 +77,11 @@
77 ** used to store the returned pointer when done.
78 */
79 void *fossil_utf8_to_unicode(const char *zUtf8){
80 #if defined(_WIN32) || defined(__CYGWIN__)
81 int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
82 wchar_t *zUnicode = fossil_malloc( nByte * 2 );
83 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
84 return zUnicode;
85 #else
86 assert( 0 ); /* Never used in unix */
87 return fossil_strdup(zUtf8); /* TODO: implement for unix */
@@ -304,11 +304,15 @@
304 ** Display UTF-8 on the console. Return the number of
305 ** Characters written. If stdout or stderr is redirected
306 ** to a file, -1 is returned and nothing is written
307 ** to the console.
308 */
309 int fossil_utf8_to_console(const char *zUtf8, int nByte, int toStdErr){
 
 
 
 
310 #ifdef _WIN32
311 int nChar, written = 0;
312 wchar_t *zUnicode; /* Unicode version of zUtf8 */
313 DWORD dummy;
314 Blob blob;
@@ -327,27 +331,28 @@
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 return 0;
335 }
336 nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
337 blob_size(&blob), zUnicode, nChar);
338 blob_reset(&blob);
339 /* Split WriteConsoleW call into multiple chunks, if necessary. See:
340 * <https://connect.microsoft.com/VisualStudio/feedback/details/635230> */
341 while( written < nChar ){
342 int size = nChar-written;
343 if( size > 26000 ) size = 26000;
344 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE - toStdErr), zUnicode+written,
345 size, &dummy, 0);
 
346 written += size;
347 }
348 free(zUnicode);
349 return nChar;
350 #else
351 return -1; /* No-op on unix */
352 #endif
353 }
354
355 DDED test/clean.test
--- src/utf8.c
+++ src/utf8.c
@@ -77,11 +77,11 @@
77 ** used to store the returned pointer when done.
78 */
79 void *fossil_utf8_to_unicode(const char *zUtf8){
80 #if defined(_WIN32) || defined(__CYGWIN__)
81 int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
82 wchar_t *zUnicode = fossil_malloc( nByte*2 );
83 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
84 return zUnicode;
85 #else
86 assert( 0 ); /* Never used in unix */
87 return fossil_strdup(zUtf8); /* TODO: implement for unix */
@@ -304,11 +304,15 @@
304 ** Display UTF-8 on the console. Return the number of
305 ** Characters written. If stdout or stderr is redirected
306 ** to a file, -1 is returned and nothing is written
307 ** to the console.
308 */
309 int fossil_utf8_to_console(
310 const char *zUtf8,
311 int nByte,
312 int toStdErr
313 ){
314 #ifdef _WIN32
315 int nChar, written = 0;
316 wchar_t *zUnicode; /* Unicode version of zUtf8 */
317 DWORD dummy;
318 Blob blob;
@@ -327,27 +331,28 @@
331 */
332 blob_init(&blob, zUtf8, nByte);
333 blob_to_utf8_no_bom(&blob, 1);
334 nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
335 blob_size(&blob), NULL, 0);
336 zUnicode = fossil_malloc( (nChar+1)*sizeof(zUnicode[0]) );
337 if( zUnicode==0 ){
338 return 0;
339 }
340 nChar = MultiByteToWideChar(CP_UTF8, 0, blob_buffer(&blob),
341 blob_size(&blob), zUnicode, nChar);
342 blob_reset(&blob);
343 /* Split WriteConsoleW output into multiple chunks, if necessary. See:
344 * <https://connect.microsoft.com/VisualStudio/feedback/details/635230> */
345 while( written<nChar ){
346 int size = nChar-written;
347 if( size>26000 ) size = 26000;
348 WriteConsoleW(GetStdHandle(
349 toStdErr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE),
350 zUnicode + written, size, &dummy, 0);
351 written += size;
352 }
353 fossil_free(zUnicode);
354 return nChar;
355 #else
356 return -1; /* No-op on unix */
357 #endif
358 }
359
360 DDED test/clean.test
--- a/test/clean.test
+++ b/test/clean.test
@@ -0,0 +1,157 @@
1
+#
2
+# Copyright (c) 2015 D. Richard Hipp
3
+#
4
+# This program is free software; you can redistribute it and/or
5
+# modify it under the terms of the Simplified BSD License (also
6
+# known as the "2-Clause License" or "FreeBSD License".)
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but without any warranty; without even the implied warranty of
10
+# merchantability or fitness for a particular purpose.
11
+#
12
+# Author contact information:
13
+# [email protected]
14
+# http://www.hwaci.com/drh/
15
+#
16
+############################################################################
17
+#
18
+# Tests of the "clean" command, including the ability to undo it.
19
+#
20
+
21
+repo_init###########
22
+
23
+fossil extra
24
+test clean-0 {[normalize_result] eq {}}
25
+
26
+#############0bute it and/or
27
+# modify it under the terms of the Simplified BSD License (also
28
+# kn#
29
+# Copyright (c) 2015 D. Richard Hipp
30
+#
31
+# This program is free software; you can redistribute it and/or
32
+# modify it under the terms of the Simplified BSD License (also
33
+# known as the "2-Clause License" or "FreeBSD License".)
34
+#
35
+# This program is distributed in the hope that it will be useful,
36
+# but without any warranty; without even the implied warranty of
37
+# merchantability or fitness for a particular purpose.
38
+#
39
+# Author contact information:
40
+# [email protected]
41
+# http://www.hwaci.com/drh/
42
+#
43
+############################################################################
44
+#
45
+# Tests of the "clean" command, including the ability to undo it.
46
+#
47
+
48
+test_setup
49
+
50
+###############################################################################
51
+
52
+fossil extra
53
+test clean-0 {[normalize_result] eq {}}
54
+
55
+###############################################################################
56
+
57
+write_file f1 "f1 line"
58
+fossil add f1
59
+fossil comq {NEW f2}}
60
+te3q {NEW f2}}
61
+test clean-7 {[r####################
62
+
63
+fossil extra
64
+test clean-2 {[normalize_result] eq {}}
65
+
66
+###############################################################################
67
+
68
+write_file f2 "f2 line"
69
+fossil extra
70
+test clean-3 {[normalize_result] eq {f2}}
71
+
72
+###############################################################################
73
+
74
+# clean w/undo enabled, should not prompt, 1 file < 10MiB
75
+fossil clean
76
+test clean-4 {[normalize_result] eq \
77
+{"fossil undo" is available to undo changes to the working checkout.}}
78
+
79
+###############################################################################
80
+
81
+fossil extra
82
+test clean-5 {[normalize_result] eq {}}
83
+
84
+###############################################################################
85
+
86
+fossil undo
87
+testq {NEW f2}}
88
+test clean-7 {[read_file f2] eq "f2 line"}
89
+
90
+###############################################################################
91
+
92
+fossil extra
93
+test clean-8 {[normalize_result] eq {f2}}
94
+
95
+###############################################################################
96
+
97
+write_file f3 [string repeat ABCDEFGHIJK 1048576]
98
+fossil extra
99
+test clean-9 {[normalize_result] eq {f2
100
+f3}}
101
+
102
+###############################################################################
103
+
104
+# clean w/undo enabled, no prompt, 1 file < 10MiB, 1 file > 10MiB
105
+fossil clean --no-prompt
106
+test clean-10 {[normalize_result] eq \
107
+{"fossil undo" is available to undo changes to the working checkout.}}
108
+
109
+####################################
110
+
111
+fossil undo -expectError
112
+test clean-23 {[normalize_result] eq {nothing to undo}}
113
+
114
+###############################################################################
115
+
116
+# clean w/undo disabled, force, 1 file < 10MiB, 1 file > 10MiB
117
+fossil clean --disable-undo --force
118
+test clean-24 {[normalize_result] eq {}}
119
+
120
+###############################################################################
121
+
122
+fossil extra
123
+test clean-25 {[normalize_result] eq {}}
124
+
125
+######################################
126
+test clean-26 {[normalize_result] eq {nothing to undo}}
127
+
128
+###############################################################################
129
+
130
+write_file f5 "f5 line"
131
+fossil extra
132
+test clean-27 {[normalize_result] eq {f5}}
133
+
134
+###############################################################################
135
+
136
+# clean w/undo disabled, should prompt, 1 file < 10MiB
137
+fossil_maybe_answer Y clean --disable-undo
138
+test clean-28 {[normalize_result] eq \
139
+{WARNING: Deletion of this file will not be undoable via the 'undo'
140
+ command because undo is disabled for this operation.
141
+
142
+Remove unmanaged file "f5" (a=all/y/N)?}}
143
+
144
+###############################################################################
145
+
146
+fossil extra
147
+test clean-29 {[normalize_result] eq {}}
148
+
149
+###############################################################################
150
+
151
+fossil undo
152
+test clean-30 {[normalize_result] eq {nothing to undo}}
153
+
154
+###############################################################################
155
+
156
+fossil extra
157
+test clean-31 {[normalize_result] eq {}}
--- a/test/clean.test
+++ b/test/clean.test
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/clean.test
+++ b/test/clean.test
@@ -0,0 +1,157 @@
1 #
2 # Copyright (c) 2015 D. Richard Hipp
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the Simplified BSD License (also
6 # known as the "2-Clause License" or "FreeBSD License".)
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but without any warranty; without even the implied warranty of
10 # merchantability or fitness for a particular purpose.
11 #
12 # Author contact information:
13 # [email protected]
14 # http://www.hwaci.com/drh/
15 #
16 ############################################################################
17 #
18 # Tests of the "clean" command, including the ability to undo it.
19 #
20
21 repo_init###########
22
23 fossil extra
24 test clean-0 {[normalize_result] eq {}}
25
26 #############0bute it and/or
27 # modify it under the terms of the Simplified BSD License (also
28 # kn#
29 # Copyright (c) 2015 D. Richard Hipp
30 #
31 # This program is free software; you can redistribute it and/or
32 # modify it under the terms of the Simplified BSD License (also
33 # known as the "2-Clause License" or "FreeBSD License".)
34 #
35 # This program is distributed in the hope that it will be useful,
36 # but without any warranty; without even the implied warranty of
37 # merchantability or fitness for a particular purpose.
38 #
39 # Author contact information:
40 # [email protected]
41 # http://www.hwaci.com/drh/
42 #
43 ############################################################################
44 #
45 # Tests of the "clean" command, including the ability to undo it.
46 #
47
48 test_setup
49
50 ###############################################################################
51
52 fossil extra
53 test clean-0 {[normalize_result] eq {}}
54
55 ###############################################################################
56
57 write_file f1 "f1 line"
58 fossil add f1
59 fossil comq {NEW f2}}
60 te3q {NEW f2}}
61 test clean-7 {[r####################
62
63 fossil extra
64 test clean-2 {[normalize_result] eq {}}
65
66 ###############################################################################
67
68 write_file f2 "f2 line"
69 fossil extra
70 test clean-3 {[normalize_result] eq {f2}}
71
72 ###############################################################################
73
74 # clean w/undo enabled, should not prompt, 1 file < 10MiB
75 fossil clean
76 test clean-4 {[normalize_result] eq \
77 {"fossil undo" is available to undo changes to the working checkout.}}
78
79 ###############################################################################
80
81 fossil extra
82 test clean-5 {[normalize_result] eq {}}
83
84 ###############################################################################
85
86 fossil undo
87 testq {NEW f2}}
88 test clean-7 {[read_file f2] eq "f2 line"}
89
90 ###############################################################################
91
92 fossil extra
93 test clean-8 {[normalize_result] eq {f2}}
94
95 ###############################################################################
96
97 write_file f3 [string repeat ABCDEFGHIJK 1048576]
98 fossil extra
99 test clean-9 {[normalize_result] eq {f2
100 f3}}
101
102 ###############################################################################
103
104 # clean w/undo enabled, no prompt, 1 file < 10MiB, 1 file > 10MiB
105 fossil clean --no-prompt
106 test clean-10 {[normalize_result] eq \
107 {"fossil undo" is available to undo changes to the working checkout.}}
108
109 ####################################
110
111 fossil undo -expectError
112 test clean-23 {[normalize_result] eq {nothing to undo}}
113
114 ###############################################################################
115
116 # clean w/undo disabled, force, 1 file < 10MiB, 1 file > 10MiB
117 fossil clean --disable-undo --force
118 test clean-24 {[normalize_result] eq {}}
119
120 ###############################################################################
121
122 fossil extra
123 test clean-25 {[normalize_result] eq {}}
124
125 ######################################
126 test clean-26 {[normalize_result] eq {nothing to undo}}
127
128 ###############################################################################
129
130 write_file f5 "f5 line"
131 fossil extra
132 test clean-27 {[normalize_result] eq {f5}}
133
134 ###############################################################################
135
136 # clean w/undo disabled, should prompt, 1 file < 10MiB
137 fossil_maybe_answer Y clean --disable-undo
138 test clean-28 {[normalize_result] eq \
139 {WARNING: Deletion of this file will not be undoable via the 'undo'
140 command because undo is disabled for this operation.
141
142 Remove unmanaged file "f5" (a=all/y/N)?}}
143
144 ###############################################################################
145
146 fossil extra
147 test clean-29 {[normalize_result] eq {}}
148
149 ###############################################################################
150
151 fossil undo
152 test clean-30 {[normalize_result] eq {nothing to undo}}
153
154 ###############################################################################
155
156 fossil extra
157 test clean-31 {[normalize_result] eq {}}
+26 -2
--- test/tester.tcl
+++ test/tester.tcl
@@ -87,22 +87,46 @@
8787
puts $out $msg
8888
close $out
8989
}
9090
}
9191
92
-# Run the fossil program
92
+# Run the Fossil program with the specified arguments.
93
+#
94
+# Consults the VERBOSE global variable to determine if
95
+# diagnostics should be emitted when no error is seen.
96
+# Sets the CODE and RESULT global variables for use in
97
+# test expressions.
9398
#
9499
proc fossil {args} {
100
+ return [uplevel 1 fossil_maybe_answer [list ""] $args]
101
+}
102
+
103
+# Run the Fossil program with the specified arguments
104
+# and possibly answer the first prompt, if any.
105
+#
106
+# Consults the VERBOSE global variable to determine if
107
+# diagnostics should be emitted when no error is seen.
108
+# Sets the CODE and RESULT global variables for use in
109
+# test expressions.
110
+#
111
+proc fossil_maybe_answer {answer args} {
95112
global fossilexe
96113
set cmd $fossilexe
97114
foreach a $args {
98115
lappend cmd $a
99116
}
100117
protOut $cmd
101118
102119
flush stdout
103
- set rc [catch {eval exec $cmd} result]
120
+ if {[string length $answer] > 0} {
121
+ set prompt_file [file join $::tempPath fossil_prompt_answer]
122
+ write_file $prompt_file $answer\n
123
+ set rc [catch {eval exec $cmd <$prompt_file} result]
124
+ file delete $prompt_file
125
+ } else {
126
+ set rc [catch {eval exec $cmd} result]
127
+ }
104128
global RESULT CODE
105129
set CODE $rc
106130
if {$rc} {
107131
protOut "ERROR: $result"
108132
} elseif {$::VERBOSE} {
109133
--- test/tester.tcl
+++ test/tester.tcl
@@ -87,22 +87,46 @@
87 puts $out $msg
88 close $out
89 }
90 }
91
92 # Run the fossil program
 
 
 
 
 
93 #
94 proc fossil {args} {
 
 
 
 
 
 
 
 
 
 
 
 
95 global fossilexe
96 set cmd $fossilexe
97 foreach a $args {
98 lappend cmd $a
99 }
100 protOut $cmd
101
102 flush stdout
103 set rc [catch {eval exec $cmd} result]
 
 
 
 
 
 
 
104 global RESULT CODE
105 set CODE $rc
106 if {$rc} {
107 protOut "ERROR: $result"
108 } elseif {$::VERBOSE} {
109
--- test/tester.tcl
+++ test/tester.tcl
@@ -87,22 +87,46 @@
87 puts $out $msg
88 close $out
89 }
90 }
91
92 # Run the Fossil program with the specified arguments.
93 #
94 # Consults the VERBOSE global variable to determine if
95 # diagnostics should be emitted when no error is seen.
96 # Sets the CODE and RESULT global variables for use in
97 # test expressions.
98 #
99 proc fossil {args} {
100 return [uplevel 1 fossil_maybe_answer [list ""] $args]
101 }
102
103 # Run the Fossil program with the specified arguments
104 # and possibly answer the first prompt, if any.
105 #
106 # Consults the VERBOSE global variable to determine if
107 # diagnostics should be emitted when no error is seen.
108 # Sets the CODE and RESULT global variables for use in
109 # test expressions.
110 #
111 proc fossil_maybe_answer {answer args} {
112 global fossilexe
113 set cmd $fossilexe
114 foreach a $args {
115 lappend cmd $a
116 }
117 protOut $cmd
118
119 flush stdout
120 if {[string length $answer] > 0} {
121 set prompt_file [file join $::tempPath fossil_prompt_answer]
122 write_file $prompt_file $answer\n
123 set rc [catch {eval exec $cmd <$prompt_file} result]
124 file delete $prompt_file
125 } else {
126 set rc [catch {eval exec $cmd} result]
127 }
128 global RESULT CODE
129 set CODE $rc
130 if {$rc} {
131 protOut "ERROR: $result"
132 } elseif {$::VERBOSE} {
133
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -123,5 +123,47 @@
123123
[file nativename [file join $dir th1-tcl9.txt]]
124124
125125
test th1-tcl-9 {[string trim $RESULT] eq [list [file tail $fossilexe] 3 \
126126
[list test-th-render --open-config [file nativename [file join $dir \
127127
th1-tcl9.txt]]]]}
128
+
129
+###############################################################################
130
+
131
+fossil test-th-eval "tclMakeSafe a"
132
+test th1-tcl-10 {[normalize_result] eq \
133
+{TH_ERROR: wrong # args: should be "tclMakeSafe"}}
134
+
135
+###############################################################################
136
+
137
+fossil test-th-eval "list \[tclIsSafe\] \[tclMakeSafe\] \[tclIsSafe\]"
138
+test th1-tcl-11 {[normalize_result] eq {0 {} 1}}
139
+
140
+###############################################################################
141
+
142
+fossil test-th-eval "tclMakeSafe; tclMakeSafe"
143
+test th1-tcl-12 {[normalize_result] eq \
144
+{TH_ERROR: Tcl interpreter is already 'safe'}}
145
+
146
+###############################################################################
147
+
148
+fossil test-th-eval "tclEval pwd; tclMakeSafe; tclEval pwd"
149
+test th1-tcl-13 {[normalize_result] eq {TH_ERROR: invalid command name "pwd"}}
150
+
151
+###############################################################################
152
+
153
+fossil test-th-eval "tclMakeSafe; tclExpr {0 + \[string length \[pwd\]\]}"
154
+test th1-tcl-14 {[normalize_result] eq {TH_ERROR: invalid command name "pwd"}}
155
+
156
+###############################################################################
157
+
158
+fossil test-th-eval "tclInvoke pwd; tclMakeSafe; tclInvoke pwd"
159
+test th1-tcl-15 {[normalize_result] eq {TH_ERROR: Tcl command not found: pwd}}
160
+
161
+###############################################################################
162
+
163
+fossil test-th-eval "tclMakeSafe; tclEval set x 2"
164
+test th1-tcl-16 {[normalize_result] eq {2}}
165
+
166
+###############################################################################
167
+
168
+fossil test-th-eval "tclMakeSafe; tclEval set x 2; tclEval info vars x"
169
+test th1-tcl-17 {[normalize_result] eq {x}}
128170
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -123,5 +123,47 @@
123 [file nativename [file join $dir th1-tcl9.txt]]
124
125 test th1-tcl-9 {[string trim $RESULT] eq [list [file tail $fossilexe] 3 \
126 [list test-th-render --open-config [file nativename [file join $dir \
127 th1-tcl9.txt]]]]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -123,5 +123,47 @@
123 [file nativename [file join $dir th1-tcl9.txt]]
124
125 test th1-tcl-9 {[string trim $RESULT] eq [list [file tail $fossilexe] 3 \
126 [list test-th-render --open-config [file nativename [file join $dir \
127 th1-tcl9.txt]]]]}
128
129 ###############################################################################
130
131 fossil test-th-eval "tclMakeSafe a"
132 test th1-tcl-10 {[normalize_result] eq \
133 {TH_ERROR: wrong # args: should be "tclMakeSafe"}}
134
135 ###############################################################################
136
137 fossil test-th-eval "list \[tclIsSafe\] \[tclMakeSafe\] \[tclIsSafe\]"
138 test th1-tcl-11 {[normalize_result] eq {0 {} 1}}
139
140 ###############################################################################
141
142 fossil test-th-eval "tclMakeSafe; tclMakeSafe"
143 test th1-tcl-12 {[normalize_result] eq \
144 {TH_ERROR: Tcl interpreter is already 'safe'}}
145
146 ###############################################################################
147
148 fossil test-th-eval "tclEval pwd; tclMakeSafe; tclEval pwd"
149 test th1-tcl-13 {[normalize_result] eq {TH_ERROR: invalid command name "pwd"}}
150
151 ###############################################################################
152
153 fossil test-th-eval "tclMakeSafe; tclExpr {0 + \[string length \[pwd\]\]}"
154 test th1-tcl-14 {[normalize_result] eq {TH_ERROR: invalid command name "pwd"}}
155
156 ###############################################################################
157
158 fossil test-th-eval "tclInvoke pwd; tclMakeSafe; tclInvoke pwd"
159 test th1-tcl-15 {[normalize_result] eq {TH_ERROR: Tcl command not found: pwd}}
160
161 ###############################################################################
162
163 fossil test-th-eval "tclMakeSafe; tclEval set x 2"
164 test th1-tcl-16 {[normalize_result] eq {2}}
165
166 ###############################################################################
167
168 fossil test-th-eval "tclMakeSafe; tclEval set x 2; tclEval info vars x"
169 test th1-tcl-17 {[normalize_result] eq {x}}
170
+159
--- test/th1.test
+++ test/th1.test
@@ -1012,5 +1012,164 @@
10121012
10131013
###############################################################################
10141014
10151015
fossil test-th-eval {list [glob_match {a[bd]c} abc] [glob_match abc {a[bd]c}]}
10161016
test th1-glob-match-13 {$RESULT eq "1 0"}
1017
+
1018
+###############################################################################
1019
+
1020
+fossil test-th-eval {string is}
1021
+test th1-string-is-1 {$RESULT eq \
1022
+{TH_ERROR: wrong # args: should be "string is class string"}}
1023
+
1024
+###############################################################################
1025
+
1026
+fossil test-th-eval {string is something}
1027
+test th1-string-is-2 {$RESULT eq \
1028
+{TH_ERROR: wrong # args: should be "string is class string"}}
1029
+
1030
+###############################################################################
1031
+
1032
+fossil test-th-eval {string is not something else}
1033
+test th1-string-is-3 {$RESULT eq \
1034
+{TH_ERROR: wrong # args: should be "string is class string"}}
1035
+
1036
+###############################################################################
1037
+
1038
+fossil test-th-eval {string is other 123}
1039
+test th1-string-is-4 {$RESULT eq \
1040
+"TH_ERROR: Expected alnum, double, integer, or list, got: other"}
1041
+
1042
+###############################################################################
1043
+
1044
+fossil test-th-eval {string is alnum 123}
1045
+test th1-string-is-5 {$RESULT eq "1"}
1046
+
1047
+###############################################################################
1048
+
1049
+fossil test-th-eval {string is alnum abc}
1050
+test th1-string-is-6 {$RESULT eq "1"}
1051
+
1052
+###############################################################################
1053
+
1054
+fossil test-th-eval {string is alnum 123abc}
1055
+test th1-string-is-7 {$RESULT eq "1"}
1056
+
1057
+###############################################################################
1058
+
1059
+fossil test-th-eval {string is alnum abc123}
1060
+test th1-string-is-8 {$RESULT eq "1"}
1061
+
1062
+###############################################################################
1063
+
1064
+fossil test-th-eval {string is alnum _abc123}
1065
+test th1-string-is-9 {$RESULT eq "0"}
1066
+
1067
+###############################################################################
1068
+
1069
+fossil test-th-eval {string is alnum abc.123}
1070
+test th1-string-is-10 {$RESULT eq "0"}
1071
+
1072
+###############################################################################
1073
+
1074
+fossil test-th-eval {string is alnum abc123_}
1075
+test th1-string-is-11 {$RESULT eq "0"}
1076
+
1077
+###############################################################################
1078
+
1079
+fossil test-th-eval {string is list ""}
1080
+test th1-string-is-12 {$RESULT eq "1"}
1081
+
1082
+###############################################################################
1083
+
1084
+fossil test-th-eval {string is list 1}
1085
+test th1-string-is-13 {$RESULT eq "1"}
1086
+
1087
+###############################################################################
1088
+
1089
+fossil test-th-eval {string is list "1 2 3"}
1090
+test th1-string-is-14 {$RESULT eq "1"}
1091
+
1092
+###############################################################################
1093
+
1094
+fossil test-th-eval {string is list "\{"}
1095
+test th1-string-is-15 {$RESULT eq "0"}
1096
+
1097
+###############################################################################
1098
+
1099
+fossil test-th-eval {string is list "1 2 3 \{"}
1100
+test th1-string-is-16 {$RESULT eq "0"}
1101
+
1102
+###############################################################################
1103
+
1104
+fossil test-th-eval {string is list "1 2 3 \{\}"}
1105
+test th1-string-is-17 {$RESULT eq "1"}
1106
+
1107
+###############################################################################
1108
+
1109
+fossil test-th-eval {string is list "1 2 3 \{\{\}"}
1110
+test th1-string-is-18 {$RESULT eq "0"}
1111
+
1112
+###############################################################################
1113
+
1114
+fossil test-th-eval {string is double 123}
1115
+test th1-string-is-19 {$RESULT eq "1"}
1116
+
1117
+###############################################################################
1118
+
1119
+fossil test-th-eval {string is double 123.456}
1120
+test th1-string-is-20 {$RESULT eq "1"}
1121
+
1122
+###############################################################################
1123
+
1124
+fossil test-th-eval {string is double 123abc}
1125
+test th1-string-is-21 {$RESULT eq "0"}
1126
+
1127
+###############################################################################
1128
+
1129
+fossil test-th-eval {string is double 123_456}
1130
+test th1-string-is-22 {$RESULT eq "0"}
1131
+
1132
+###############################################################################
1133
+
1134
+fossil test-th-eval {string is integer 123}
1135
+test th1-string-is-23 {$RESULT eq "1"}
1136
+
1137
+###############################################################################
1138
+
1139
+fossil test-th-eval {string is integer 123.456}
1140
+test th1-string-is-24 {$RESULT eq "0"}
1141
+
1142
+###############################################################################
1143
+
1144
+fossil test-th-eval {string is integer 123abc}
1145
+test th1-string-is-25 {$RESULT eq "0"}
1146
+
1147
+###############################################################################
1148
+
1149
+fossil test-th-eval {string is integer 0b11001001}
1150
+test th1-string-is-26 {$RESULT eq "1"}
1151
+
1152
+###############################################################################
1153
+
1154
+fossil test-th-eval {string is integer 0b11001002}
1155
+test th1-string-is-27 {$RESULT eq "0"}
1156
+
1157
+###############################################################################
1158
+
1159
+fossil test-th-eval {string is integer 0o777}
1160
+test th1-string-is-28 {$RESULT eq "1"}
1161
+
1162
+###############################################################################
1163
+
1164
+fossil test-th-eval {string is integer 0o778}
1165
+test th1-string-is-29 {$RESULT eq "0"}
1166
+
1167
+###############################################################################
1168
+
1169
+fossil test-th-eval {string is integer 0xC0DEF00D}
1170
+test th1-string-is-30 {$RESULT eq "1"}
1171
+
1172
+###############################################################################
1173
+
1174
+fossil test-th-eval {string is integer 0xC0DEF00Z}
1175
+test th1-string-is-31 {$RESULT eq "0"}
10171176
--- test/th1.test
+++ test/th1.test
@@ -1012,5 +1012,164 @@
1012
1013 ###############################################################################
1014
1015 fossil test-th-eval {list [glob_match {a[bd]c} abc] [glob_match abc {a[bd]c}]}
1016 test th1-glob-match-13 {$RESULT eq "1 0"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017
--- test/th1.test
+++ test/th1.test
@@ -1012,5 +1012,164 @@
1012
1013 ###############################################################################
1014
1015 fossil test-th-eval {list [glob_match {a[bd]c} abc] [glob_match abc {a[bd]c}]}
1016 test th1-glob-match-13 {$RESULT eq "1 0"}
1017
1018 ###############################################################################
1019
1020 fossil test-th-eval {string is}
1021 test th1-string-is-1 {$RESULT eq \
1022 {TH_ERROR: wrong # args: should be "string is class string"}}
1023
1024 ###############################################################################
1025
1026 fossil test-th-eval {string is something}
1027 test th1-string-is-2 {$RESULT eq \
1028 {TH_ERROR: wrong # args: should be "string is class string"}}
1029
1030 ###############################################################################
1031
1032 fossil test-th-eval {string is not something else}
1033 test th1-string-is-3 {$RESULT eq \
1034 {TH_ERROR: wrong # args: should be "string is class string"}}
1035
1036 ###############################################################################
1037
1038 fossil test-th-eval {string is other 123}
1039 test th1-string-is-4 {$RESULT eq \
1040 "TH_ERROR: Expected alnum, double, integer, or list, got: other"}
1041
1042 ###############################################################################
1043
1044 fossil test-th-eval {string is alnum 123}
1045 test th1-string-is-5 {$RESULT eq "1"}
1046
1047 ###############################################################################
1048
1049 fossil test-th-eval {string is alnum abc}
1050 test th1-string-is-6 {$RESULT eq "1"}
1051
1052 ###############################################################################
1053
1054 fossil test-th-eval {string is alnum 123abc}
1055 test th1-string-is-7 {$RESULT eq "1"}
1056
1057 ###############################################################################
1058
1059 fossil test-th-eval {string is alnum abc123}
1060 test th1-string-is-8 {$RESULT eq "1"}
1061
1062 ###############################################################################
1063
1064 fossil test-th-eval {string is alnum _abc123}
1065 test th1-string-is-9 {$RESULT eq "0"}
1066
1067 ###############################################################################
1068
1069 fossil test-th-eval {string is alnum abc.123}
1070 test th1-string-is-10 {$RESULT eq "0"}
1071
1072 ###############################################################################
1073
1074 fossil test-th-eval {string is alnum abc123_}
1075 test th1-string-is-11 {$RESULT eq "0"}
1076
1077 ###############################################################################
1078
1079 fossil test-th-eval {string is list ""}
1080 test th1-string-is-12 {$RESULT eq "1"}
1081
1082 ###############################################################################
1083
1084 fossil test-th-eval {string is list 1}
1085 test th1-string-is-13 {$RESULT eq "1"}
1086
1087 ###############################################################################
1088
1089 fossil test-th-eval {string is list "1 2 3"}
1090 test th1-string-is-14 {$RESULT eq "1"}
1091
1092 ###############################################################################
1093
1094 fossil test-th-eval {string is list "\{"}
1095 test th1-string-is-15 {$RESULT eq "0"}
1096
1097 ###############################################################################
1098
1099 fossil test-th-eval {string is list "1 2 3 \{"}
1100 test th1-string-is-16 {$RESULT eq "0"}
1101
1102 ###############################################################################
1103
1104 fossil test-th-eval {string is list "1 2 3 \{\}"}
1105 test th1-string-is-17 {$RESULT eq "1"}
1106
1107 ###############################################################################
1108
1109 fossil test-th-eval {string is list "1 2 3 \{\{\}"}
1110 test th1-string-is-18 {$RESULT eq "0"}
1111
1112 ###############################################################################
1113
1114 fossil test-th-eval {string is double 123}
1115 test th1-string-is-19 {$RESULT eq "1"}
1116
1117 ###############################################################################
1118
1119 fossil test-th-eval {string is double 123.456}
1120 test th1-string-is-20 {$RESULT eq "1"}
1121
1122 ###############################################################################
1123
1124 fossil test-th-eval {string is double 123abc}
1125 test th1-string-is-21 {$RESULT eq "0"}
1126
1127 ###############################################################################
1128
1129 fossil test-th-eval {string is double 123_456}
1130 test th1-string-is-22 {$RESULT eq "0"}
1131
1132 ###############################################################################
1133
1134 fossil test-th-eval {string is integer 123}
1135 test th1-string-is-23 {$RESULT eq "1"}
1136
1137 ###############################################################################
1138
1139 fossil test-th-eval {string is integer 123.456}
1140 test th1-string-is-24 {$RESULT eq "0"}
1141
1142 ###############################################################################
1143
1144 fossil test-th-eval {string is integer 123abc}
1145 test th1-string-is-25 {$RESULT eq "0"}
1146
1147 ###############################################################################
1148
1149 fossil test-th-eval {string is integer 0b11001001}
1150 test th1-string-is-26 {$RESULT eq "1"}
1151
1152 ###############################################################################
1153
1154 fossil test-th-eval {string is integer 0b11001002}
1155 test th1-string-is-27 {$RESULT eq "0"}
1156
1157 ###############################################################################
1158
1159 fossil test-th-eval {string is integer 0o777}
1160 test th1-string-is-28 {$RESULT eq "1"}
1161
1162 ###############################################################################
1163
1164 fossil test-th-eval {string is integer 0o778}
1165 test th1-string-is-29 {$RESULT eq "0"}
1166
1167 ###############################################################################
1168
1169 fossil test-th-eval {string is integer 0xC0DEF00D}
1170 test th1-string-is-30 {$RESULT eq "1"}
1171
1172 ###############################################################################
1173
1174 fossil test-th-eval {string is integer 0xC0DEF00Z}
1175 test th1-string-is-31 {$RESULT eq "0"}
1176
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -150,11 +150,11 @@
150150
#### The directories where the OpenSSL include and library files are located.
151151
# The recommended usage here is to use the Sysinternals junction tool
152152
# to create a hard link between an "openssl-1.x" sub-directory of the
153153
# Fossil source code directory and the target OpenSSL source directory.
154154
#
155
-OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2c
155
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2d
156156
OPENSSLINCDIR = $(OPENSSLDIR)/include
157157
OPENSSLLIBDIR = $(OPENSSLDIR)
158158
159159
#### Either the directory where the Tcl library is installed or the Tcl
160160
# source code directory resides (depending on the value of the macro
161161
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -150,11 +150,11 @@
150 #### The directories where the OpenSSL include and library files are located.
151 # The recommended usage here is to use the Sysinternals junction tool
152 # to create a hard link between an "openssl-1.x" sub-directory of the
153 # Fossil source code directory and the target OpenSSL source directory.
154 #
155 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2c
156 OPENSSLINCDIR = $(OPENSSLDIR)/include
157 OPENSSLLIBDIR = $(OPENSSLDIR)
158
159 #### Either the directory where the Tcl library is installed or the Tcl
160 # source code directory resides (depending on the value of the macro
161
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -150,11 +150,11 @@
150 #### The directories where the OpenSSL include and library files are located.
151 # The recommended usage here is to use the Sysinternals junction tool
152 # to create a hard link between an "openssl-1.x" sub-directory of the
153 # Fossil source code directory and the target OpenSSL source directory.
154 #
155 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2d
156 OPENSSLINCDIR = $(OPENSSLDIR)/include
157 OPENSSLLIBDIR = $(OPENSSLDIR)
158
159 #### Either the directory where the Tcl library is installed or the Tcl
160 # source code directory resides (depending on the value of the macro
161
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -150,11 +150,11 @@
150150
#### The directories where the OpenSSL include and library files are located.
151151
# The recommended usage here is to use the Sysinternals junction tool
152152
# to create a hard link between an "openssl-1.x" sub-directory of the
153153
# Fossil source code directory and the target OpenSSL source directory.
154154
#
155
-OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2c
155
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2d
156156
OPENSSLINCDIR = $(OPENSSLDIR)/include
157157
OPENSSLLIBDIR = $(OPENSSLDIR)
158158
159159
#### Either the directory where the Tcl library is installed or the Tcl
160160
# source code directory resides (depending on the value of the macro
161161
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -150,11 +150,11 @@
150 #### The directories where the OpenSSL include and library files are located.
151 # The recommended usage here is to use the Sysinternals junction tool
152 # to create a hard link between an "openssl-1.x" sub-directory of the
153 # Fossil source code directory and the target OpenSSL source directory.
154 #
155 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2c
156 OPENSSLINCDIR = $(OPENSSLDIR)/include
157 OPENSSLLIBDIR = $(OPENSSLDIR)
158
159 #### Either the directory where the Tcl library is installed or the Tcl
160 # source code directory resides (depending on the value of the macro
161
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -150,11 +150,11 @@
150 #### The directories where the OpenSSL include and library files are located.
151 # The recommended usage here is to use the Sysinternals junction tool
152 # to create a hard link between an "openssl-1.x" sub-directory of the
153 # Fossil source code directory and the target OpenSSL source directory.
154 #
155 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2d
156 OPENSSLINCDIR = $(OPENSSLDIR)/include
157 OPENSSLLIBDIR = $(OPENSSLDIR)
158
159 #### Either the directory where the Tcl library is installed or the Tcl
160 # source code directory resides (depending on the value of the macro
161
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -39,11 +39,11 @@
3939
FOSSIL_BUILD_SSL = 0
4040
!endif
4141
4242
# Build the included zlib library?
4343
!ifndef FOSSIL_BUILD_ZLIB
44
-FOSSIL_BUILD_ZLIB = 0
44
+FOSSIL_BUILD_ZLIB = 1
4545
!endif
4646
4747
# Link everything except SQLite dynamically?
4848
!ifndef FOSSIL_DYNAMIC_BUILD
4949
FOSSIL_DYNAMIC_BUILD = 0
@@ -88,11 +88,11 @@
8888
!ifndef FOSSIL_ENABLE_WINXP
8989
FOSSIL_ENABLE_WINXP = 0
9090
!endif
9191
9292
!if $(FOSSIL_ENABLE_SSL)!=0
93
-SSLDIR = $(B)\compat\openssl-1.0.2c
93
+SSLDIR = $(B)\compat\openssl-1.0.2d
9494
SSLINCDIR = $(SSLDIR)\inc32
9595
!if $(FOSSIL_DYNAMIC_BUILD)!=0
9696
SSLLIBDIR = $(SSLDIR)\out32dll
9797
!else
9898
SSLLIBDIR = $(SSLDIR)\out32
9999
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -39,11 +39,11 @@
39 FOSSIL_BUILD_SSL = 0
40 !endif
41
42 # Build the included zlib library?
43 !ifndef FOSSIL_BUILD_ZLIB
44 FOSSIL_BUILD_ZLIB = 0
45 !endif
46
47 # Link everything except SQLite dynamically?
48 !ifndef FOSSIL_DYNAMIC_BUILD
49 FOSSIL_DYNAMIC_BUILD = 0
@@ -88,11 +88,11 @@
88 !ifndef FOSSIL_ENABLE_WINXP
89 FOSSIL_ENABLE_WINXP = 0
90 !endif
91
92 !if $(FOSSIL_ENABLE_SSL)!=0
93 SSLDIR = $(B)\compat\openssl-1.0.2c
94 SSLINCDIR = $(SSLDIR)\inc32
95 !if $(FOSSIL_DYNAMIC_BUILD)!=0
96 SSLLIBDIR = $(SSLDIR)\out32dll
97 !else
98 SSLLIBDIR = $(SSLDIR)\out32
99
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -39,11 +39,11 @@
39 FOSSIL_BUILD_SSL = 0
40 !endif
41
42 # Build the included zlib library?
43 !ifndef FOSSIL_BUILD_ZLIB
44 FOSSIL_BUILD_ZLIB = 1
45 !endif
46
47 # Link everything except SQLite dynamically?
48 !ifndef FOSSIL_DYNAMIC_BUILD
49 FOSSIL_DYNAMIC_BUILD = 0
@@ -88,11 +88,11 @@
88 !ifndef FOSSIL_ENABLE_WINXP
89 FOSSIL_ENABLE_WINXP = 0
90 !endif
91
92 !if $(FOSSIL_ENABLE_SSL)!=0
93 SSLDIR = $(B)\compat\openssl-1.0.2d
94 SSLINCDIR = $(SSLDIR)\inc32
95 !if $(FOSSIL_DYNAMIC_BUILD)!=0
96 SSLLIBDIR = $(SSLDIR)\out32dll
97 !else
98 SSLLIBDIR = $(SSLDIR)\out32
99
+1 -1
--- www/build.wiki
+++ www/build.wiki
@@ -135,11 +135,11 @@
135135
the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
136136
first <a href="https://www.openssl.org/source/">download the official
137137
source code for OpenSSL</a> and extract it to an appropriately named
138138
"<b>openssl-X.Y.ZA</b>" subdirectory within the local
139139
[/tree?ci=trunk&name=compat | compat] directory (e.g.
140
-"<b>compat/openssl-1.0.2c</b>"), then make sure that some recent
140
+"<b>compat/openssl-1.0.2d</b>"), then make sure that some recent
141141
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
142142
and finally run one of the following commands:
143143
<blockquote><pre>
144144
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
145145
</pre></blockquote>
146146
--- www/build.wiki
+++ www/build.wiki
@@ -135,11 +135,11 @@
135 the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
136 first <a href="https://www.openssl.org/source/">download the official
137 source code for OpenSSL</a> and extract it to an appropriately named
138 "<b>openssl-X.Y.ZA</b>" subdirectory within the local
139 [/tree?ci=trunk&name=compat | compat] directory (e.g.
140 "<b>compat/openssl-1.0.2c</b>"), then make sure that some recent
141 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
142 and finally run one of the following commands:
143 <blockquote><pre>
144 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
145 </pre></blockquote>
146
--- www/build.wiki
+++ www/build.wiki
@@ -135,11 +135,11 @@
135 the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
136 first <a href="https://www.openssl.org/source/">download the official
137 source code for OpenSSL</a> and extract it to an appropriately named
138 "<b>openssl-X.Y.ZA</b>" subdirectory within the local
139 [/tree?ci=trunk&name=compat | compat] directory (e.g.
140 "<b>compat/openssl-1.0.2d</b>"), then make sure that some recent
141 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
142 and finally run one of the following commands:
143 <blockquote><pre>
144 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
145 </pre></blockquote>
146
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,13 +1,18 @@
11
<title>Change Log</title>
22
33
<h2>Changes for Version 1.34 (2015-??-??)</h2>
44
* Fix --hard option to mv/rm to enable them to work properly with certain
55
relative paths.
6
- * Add minimal 'lsearch' command to TH1. Only exact case-sensitive matching
7
- is supported.
8
- * Add 'glob_match' command to TH1.
6
+ * Make the clean command undoable for files less than 10MiB.
7
+ * Add minimal <nowiki>[lsearch]</nowiki> command to TH1. Only exact
8
+ case-sensitive matching is supported.
9
+ * Add the <nowiki>[glob_match]</nowiki> command to TH1.
10
+ * Add the <nowiki>[tclIsSafe] and [tclMakeSafe]</nowiki> TH1 commands to
11
+ the Tcl integration subsystem.
12
+ * Add 'double', 'integer', and 'list' classes to the
13
+ <nowiki>[string is]</nowiki> command in TH1.
914
* Update internal Unicode character tables, used in regular expression
1015
handling, from version 7.0 to 8.0.
1116
1217
<h2>Changes for Version 1.33 (2015-05-23)</h2>
1318
* Improved fork detection on [/help?cmd=update|fossil update],
1419
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,13 +1,18 @@
1 <title>Change Log</title>
2
3 <h2>Changes for Version 1.34 (2015-??-??)</h2>
4 * Fix --hard option to mv/rm to enable them to work properly with certain
5 relative paths.
6 * Add minimal 'lsearch' command to TH1. Only exact case-sensitive matching
7 is supported.
8 * Add 'glob_match' command to TH1.
 
 
 
 
 
9 * Update internal Unicode character tables, used in regular expression
10 handling, from version 7.0 to 8.0.
11
12 <h2>Changes for Version 1.33 (2015-05-23)</h2>
13 * Improved fork detection on [/help?cmd=update|fossil update],
14
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,13 +1,18 @@
1 <title>Change Log</title>
2
3 <h2>Changes for Version 1.34 (2015-??-??)</h2>
4 * Fix --hard option to mv/rm to enable them to work properly with certain
5 relative paths.
6 * Make the clean command undoable for files less than 10MiB.
7 * Add minimal <nowiki>[lsearch]</nowiki> command to TH1. Only exact
8 case-sensitive matching is supported.
9 * Add the <nowiki>[glob_match]</nowiki> command to TH1.
10 * Add the <nowiki>[tclIsSafe] and [tclMakeSafe]</nowiki> TH1 commands to
11 the Tcl integration subsystem.
12 * Add 'double', 'integer', and 'list' classes to the
13 <nowiki>[string is]</nowiki> command in TH1.
14 * Update internal Unicode character tables, used in regular expression
15 handling, from version 7.0 to 8.0.
16
17 <h2>Changes for Version 1.33 (2015-05-23)</h2>
18 * Improved fork detection on [/help?cmd=update|fossil update],
19
+31 -6
--- www/th1.md
+++ www/th1.md
@@ -154,10 +154,12 @@
154154
* styleHeader
155155
* styleFooter
156156
* tclEval
157157
* tclExpr
158158
* tclInvoke
159
+ * tclIsSafe
160
+ * tclMakeSafe
159161
* tclReady
160162
* trace
161163
* stime
162164
* utime
163165
* wiki
@@ -473,34 +475,57 @@
473475
**This command requires the Tcl integration feature.**
474476
475477
* tclEval arg ?arg ...?
476478
477479
Evaluates the Tcl script and returns its result verbatim. If a Tcl script
478
-error is generated, it will be transformed into a TH1 script error. A Tcl
479
-interpreter will be created automatically if it has not been already.
480
+error is generated, it will be transformed into a TH1 script error. The
481
+Tcl interpreter will be created automatically if it has not been already.
480482
481483
<a name="tclExpr"></a>TH1 tclExpr Command
482484
-----------------------------------------
483485
484486
**This command requires the Tcl integration feature.**
485487
486488
* tclExpr arg ?arg ...?
487489
488490
Evaluates the Tcl expression and returns its result verbatim. If a Tcl
489
-script error is generated, it will be transformed into a TH1 script error.
490
-A Tcl interpreter will be created automatically if it has not been already.
491
+script error is generated, it will be transformed into a TH1 script
492
+error. The Tcl interpreter will be created automatically if it has not
493
+been already.
491494
492495
<a name="tclInvoke"></a>TH1 tclInvoke Command
493496
---------------------------------------------
494497
495498
**This command requires the Tcl integration feature.**
496499
497500
* tclInvoke command ?arg ...?
498501
499502
Invokes the Tcl command using the supplied arguments. No additional
500
-substitutions are performed on the arguments. A Tcl interpreter will
501
-be created automatically if it has not been already.
503
+substitutions are performed on the arguments. The Tcl interpreter
504
+will be created automatically if it has not been already.
505
+
506
+<a name="tclIsSafe"></a>TH1 tclIsSafe Command
507
+---------------------------------------------
508
+
509
+**This command requires the Tcl integration feature.**
510
+
511
+ * tclIsSafe
512
+
513
+Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter
514
+will be created automatically if it has not been already.
515
+
516
+<a name="tclMakeSafe"></a>TH1 tclMakeSafe Command
517
+---------------------------------------------
518
+
519
+**This command requires the Tcl integration feature.**
520
+
521
+ * tclMakeSafe
522
+
523
+Forces the Tcl interpreter into "safe" mode by removing all "unsafe"
524
+commands and variables. This operation cannot be undone. The Tcl
525
+interpreter will remain "safe" until the process terminates. The Tcl
526
+interpreter will be created automatically if it has not been already.
502527
503528
<a name="tclReady"></a>TH1 tclReady Command
504529
-------------------------------------------
505530
506531
* tclReady
507532
--- www/th1.md
+++ www/th1.md
@@ -154,10 +154,12 @@
154 * styleHeader
155 * styleFooter
156 * tclEval
157 * tclExpr
158 * tclInvoke
 
 
159 * tclReady
160 * trace
161 * stime
162 * utime
163 * wiki
@@ -473,34 +475,57 @@
473 **This command requires the Tcl integration feature.**
474
475 * tclEval arg ?arg ...?
476
477 Evaluates the Tcl script and returns its result verbatim. If a Tcl script
478 error is generated, it will be transformed into a TH1 script error. A Tcl
479 interpreter will be created automatically if it has not been already.
480
481 <a name="tclExpr"></a>TH1 tclExpr Command
482 -----------------------------------------
483
484 **This command requires the Tcl integration feature.**
485
486 * tclExpr arg ?arg ...?
487
488 Evaluates the Tcl expression and returns its result verbatim. If a Tcl
489 script error is generated, it will be transformed into a TH1 script error.
490 A Tcl interpreter will be created automatically if it has not been already.
 
491
492 <a name="tclInvoke"></a>TH1 tclInvoke Command
493 ---------------------------------------------
494
495 **This command requires the Tcl integration feature.**
496
497 * tclInvoke command ?arg ...?
498
499 Invokes the Tcl command using the supplied arguments. No additional
500 substitutions are performed on the arguments. A Tcl interpreter will
501 be created automatically if it has not been already.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
503 <a name="tclReady"></a>TH1 tclReady Command
504 -------------------------------------------
505
506 * tclReady
507
--- www/th1.md
+++ www/th1.md
@@ -154,10 +154,12 @@
154 * styleHeader
155 * styleFooter
156 * tclEval
157 * tclExpr
158 * tclInvoke
159 * tclIsSafe
160 * tclMakeSafe
161 * tclReady
162 * trace
163 * stime
164 * utime
165 * wiki
@@ -473,34 +475,57 @@
475 **This command requires the Tcl integration feature.**
476
477 * tclEval arg ?arg ...?
478
479 Evaluates the Tcl script and returns its result verbatim. If a Tcl script
480 error is generated, it will be transformed into a TH1 script error. The
481 Tcl interpreter will be created automatically if it has not been already.
482
483 <a name="tclExpr"></a>TH1 tclExpr Command
484 -----------------------------------------
485
486 **This command requires the Tcl integration feature.**
487
488 * tclExpr arg ?arg ...?
489
490 Evaluates the Tcl expression and returns its result verbatim. If a Tcl
491 script error is generated, it will be transformed into a TH1 script
492 error. The Tcl interpreter will be created automatically if it has not
493 been already.
494
495 <a name="tclInvoke"></a>TH1 tclInvoke Command
496 ---------------------------------------------
497
498 **This command requires the Tcl integration feature.**
499
500 * tclInvoke command ?arg ...?
501
502 Invokes the Tcl command using the supplied arguments. No additional
503 substitutions are performed on the arguments. The Tcl interpreter
504 will be created automatically if it has not been already.
505
506 <a name="tclIsSafe"></a>TH1 tclIsSafe Command
507 ---------------------------------------------
508
509 **This command requires the Tcl integration feature.**
510
511 * tclIsSafe
512
513 Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter
514 will be created automatically if it has not been already.
515
516 <a name="tclMakeSafe"></a>TH1 tclMakeSafe Command
517 ---------------------------------------------
518
519 **This command requires the Tcl integration feature.**
520
521 * tclMakeSafe
522
523 Forces the Tcl interpreter into "safe" mode by removing all "unsafe"
524 commands and variables. This operation cannot be undone. The Tcl
525 interpreter will remain "safe" until the process terminates. The Tcl
526 interpreter will be created automatically if it has not been already.
527
528 <a name="tclReady"></a>TH1 tclReady Command
529 -------------------------------------------
530
531 * tclReady
532

Keyboard Shortcuts

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