Fossil SCM

Merge trunk, since cloning local filesystem repositories still does not work

andygoth 2020-08-16 14:45 multi-remote-fix merge
Commit 719dcd29cd8a99d592793211fe60f6c0d39a450087ab5aa440ed193372802a01
99 files changed +1 -1 +4 -1 +1 -1 +2 -2 +16 -16 +15 -2 +1 +1 -1 +2 -1 +5 -6 +1 -1 +459 -10 +2 -16 +8 -8 +5 -5 +3 -3 +9 -7 -1 +4 -1 +1 -1 +131 -19 +375 -21 +2 -2 +3 -3 +80 -8 +16 -11 +4 -1 +1 -1 +26 +221 -144 +2 -2 +7 -11 +1 -1 +33 -3 +41 -8 +3 +93 +23 -9 +8 +126 -104 +46 -10 +43 +65 +45 -8 +1 -1 +33 +1 -1 +1 -1 +1 -1 +104 -48 +2 +5 -4 +50 -4 +9 -13 +13 -5 +7 -1 +4 -1 +2 -2 -11 -6 -6 +9 -1 +1 -1 +58 -12 +1 -1 +2 +2 +54 -22 +1 -1 +9 +772 -531 +1 -1 -13 +28 -10 +69 -231 +47 -190 +185 +5 -4 +5 -4 +6 -2 +1 -1 +2 -2 +716 -236 -328 +2 -2 +6 -6 +1 -1 +5 -5 +1 +6 +4 -10 +9 -13 +15 -12 +19 -3 +1 -1 +1 -1 +10 -6
~ VERSION ~ skins/ardoise/css.txt ~ skins/eagle/css.txt ~ skins/xekri/css.txt ~ src/add.c ~ src/ajax.c ~ src/allrepo.c ~ src/attach.c ~ src/bisect.c ~ src/blob.c ~ src/branch.c ~ src/browse.c ~ src/builtin.c ~ src/bundle.c ~ src/cgi.c ~ src/checkin.c ~ src/checkout.c ~ src/clone.c ~ src/codecheck1.c ~ src/configure.c ~ src/content.c ~ src/db.c ~ src/default.css ~ src/descendants.c ~ src/diff.c ~ src/dispatch.c ~ src/doc.c ~ src/etag.c ~ src/export.c ~ src/file.c ~ src/fileedit.c ~ src/finfo.c ~ src/forum.c ~ src/forum.js ~ src/fossil.bootstrap.js ~ src/fossil.confirmer.js ~ src/fossil.copybutton.js ~ src/fossil.dom.js ~ src/fossil.fetch.js ~ src/fossil.numbered-lines.js ~ src/fossil.page.fileedit.js ~ src/fossil.page.forumpost.js ~ src/fossil.page.wikiedit.js ~ src/fossil.popupwidget.js ~ src/fossil.tabs.js ~ src/fusefs.c ~ src/glob.c ~ src/graph.js ~ src/hook.c ~ src/import.c ~ src/info.c ~ src/json_config.c ~ src/login.c ~ src/main.c ~ src/main.mk ~ src/makemake.tcl ~ src/mkbuiltin.c ~ src/mkindex.c ~ src/piechart.c ~ src/publish.c ~ src/purge.c ~ src/rebuild.c ~ src/rebuild.c ~ src/sbsdiff.js ~ src/scroll.js ~ src/setup.c ~ src/setupuser.c ~ src/sha1.c ~ src/sha3.c ~ src/shell.c ~ src/skins.c ~ src/sqlcmd.c ~ src/sqlite3.c ~ src/sqlite3.h ~ src/stash.c ~ src/stat.c ~ src/style.c ~ src/style.fileedit.css ~ src/style.wikiedit.css ~ src/sync.c ~ src/sync.c ~ src/timeline.c ~ src/undo.c ~ src/update.c ~ src/wiki.c - src/wysiwyg.c ~ src/xfer.c ~ test/merge1.test ~ test/merge3.test ~ test/merge4.test ~ test/tester.tcl ~ test/wiki.test ~ win/Makefile.dmc ~ win/Makefile.mingw ~ win/Makefile.msc ~ www/changes.wiki ~ www/fileedit-page.md ~ www/gitusers.md ~ www/server/openbsd/fastcgi.md
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.12
1
+2.13
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.12
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.13
2
--- skins/ardoise/css.txt
+++ skins/ardoise/css.txt
@@ -497,11 +497,11 @@
497497
border: 0;
498498
border-radius: 5px;
499499
box-shadow: none;
500500
box-sizing: border-box
501501
}
502
-textarea {
502
+textarea, select {
503503
height: initial;
504504
}
505505
input[type=email]:hover,
506506
input[type=number]:hover,
507507
input[type=password]:hover,
@@ -572,10 +572,13 @@
572572
white-space: nowrap;
573573
background: #000;
574574
border: 2px solid #bbb;
575575
border-radius: 5px
576576
}
577
+table.numbered-lines td.file-content > pre {
578
+ margin-top: -2px/*offset CODE tag border*/;
579
+}
577580
pre > code {
578581
padding: 1rem 1.5rem;
579582
white-space: pre
580583
}
581584
td,
582585
--- skins/ardoise/css.txt
+++ skins/ardoise/css.txt
@@ -497,11 +497,11 @@
497 border: 0;
498 border-radius: 5px;
499 box-shadow: none;
500 box-sizing: border-box
501 }
502 textarea {
503 height: initial;
504 }
505 input[type=email]:hover,
506 input[type=number]:hover,
507 input[type=password]:hover,
@@ -572,10 +572,13 @@
572 white-space: nowrap;
573 background: #000;
574 border: 2px solid #bbb;
575 border-radius: 5px
576 }
 
 
 
577 pre > code {
578 padding: 1rem 1.5rem;
579 white-space: pre
580 }
581 td,
582
--- skins/ardoise/css.txt
+++ skins/ardoise/css.txt
@@ -497,11 +497,11 @@
497 border: 0;
498 border-radius: 5px;
499 box-shadow: none;
500 box-sizing: border-box
501 }
502 textarea, select {
503 height: initial;
504 }
505 input[type=email]:hover,
506 input[type=number]:hover,
507 input[type=password]:hover,
@@ -572,10 +572,13 @@
572 white-space: nowrap;
573 background: #000;
574 border: 2px solid #bbb;
575 border-radius: 5px
576 }
577 table.numbered-lines td.file-content > pre {
578 margin-top: -2px/*offset CODE tag border*/;
579 }
580 pre > code {
581 padding: 1rem 1.5rem;
582 white-space: pre
583 }
584 td,
585
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -399,11 +399,11 @@
399399
400400
div.filetreeline:hover {
401401
background-color: #7EA2D9;
402402
}
403403
404
-div.selectedText {
404
+table.numbered-lines td.line-numbers span.selected-line {
405405
background-color: #7EA2D9;
406406
}
407407
408408
.statistics-report-graph-line {
409409
background-color: #7EA2D9;
410410
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -399,11 +399,11 @@
399
400 div.filetreeline:hover {
401 background-color: #7EA2D9;
402 }
403
404 div.selectedText {
405 background-color: #7EA2D9;
406 }
407
408 .statistics-report-graph-line {
409 background-color: #7EA2D9;
410
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -399,11 +399,11 @@
399
400 div.filetreeline:hover {
401 background-color: #7EA2D9;
402 }
403
404 table.numbered-lines td.line-numbers span.selected-line {
405 background-color: #7EA2D9;
406 }
407
408 .statistics-report-graph-line {
409 background-color: #7EA2D9;
410
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -1000,15 +1000,15 @@
10001000
/**************************************
10011001
* Did not encounter these
10021002
*/
10031003
10041004
/* selected lines of text within a linenumbered artifact display */
1005
-div.selectedText {
1005
+table.numbered-lines td.line-numbers span.selected-line {
10061006
font-weight: bold;
10071007
color: #00f;
10081008
background-color: #d5d5ff;
1009
- border: 1px #00f solid;
1009
+ border-color: #00f;
10101010
}
10111011
10121012
/* format for missing privileges note on user setup page */
10131013
p.missingPriv {
10141014
color: #00f;
10151015
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -1000,15 +1000,15 @@
1000 /**************************************
1001 * Did not encounter these
1002 */
1003
1004 /* selected lines of text within a linenumbered artifact display */
1005 div.selectedText {
1006 font-weight: bold;
1007 color: #00f;
1008 background-color: #d5d5ff;
1009 border: 1px #00f solid;
1010 }
1011
1012 /* format for missing privileges note on user setup page */
1013 p.missingPriv {
1014 color: #00f;
1015
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -1000,15 +1000,15 @@
1000 /**************************************
1001 * Did not encounter these
1002 */
1003
1004 /* selected lines of text within a linenumbered artifact display */
1005 table.numbered-lines td.line-numbers span.selected-line {
1006 font-weight: bold;
1007 color: #00f;
1008 background-color: #d5d5ff;
1009 border-color: #00f;
1010 }
1011
1012 /* format for missing privileges note on user setup page */
1013 p.missingPriv {
1014 color: #00f;
1015
+16 -16
--- src/add.c
+++ src/add.c
@@ -320,11 +320,11 @@
320320
** COMMAND: add
321321
**
322322
** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
323323
**
324324
** Make arrangements to add one or more files or directories to the
325
-** current checkout at the next commit.
325
+** current checkout at the next [[commit]].
326326
**
327327
** When adding files or directories recursively, filenames that begin
328328
** with "." are excluded by default. To include such files, add
329329
** the "--dotfiles" option to the command-line.
330330
**
@@ -359,11 +359,11 @@
359359
**
360360
** The following options are only valid with --reset:
361361
** -v|--verbose Outputs information about each --reset file.
362362
** -n|--dry-run Display instead of run actions.
363363
**
364
-** See also: addremove, rm
364
+** See also: [[addremove]], [[rm]]
365365
*/
366366
void add_cmd(void){
367367
int i; /* Loop counter */
368368
int vid; /* Currently checked out version */
369369
int nRoot; /* Full path characters in g.zLocalRoot */
@@ -541,11 +541,11 @@
541541
** than --verbose or --dry-run may be used with
542542
** --reset.
543543
** --verbose|-v Outputs information about each --reset file.
544544
** Only usable with --reset.
545545
**
546
-** See also: addremove, add
546
+** See also: [[addremove]], [[add]]
547547
*/
548548
void delete_cmd(void){
549549
int i;
550550
int removeFiles;
551551
int dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -689,22 +689,22 @@
689689
/*
690690
** COMMAND: addremove
691691
**
692692
** Usage: %fossil addremove ?OPTIONS?
693693
**
694
-** Do all necessary "add" and "rm" commands to synchronize the repository
695
-** with the content of the working checkout:
694
+** Do all necessary "[[add]]" and "[[rm]]" commands to synchronize the
695
+** repository with the content of the working checkout:
696696
**
697697
** * All files in the checkout but not in the repository (that is,
698698
** all files displayed using the "extras" command) are added as
699
-** if by the "add" command.
699
+** if by the "[[add]]" command.
700700
**
701701
** * All files in the repository but missing from the checkout (that is,
702702
** all files that show as MISSING with the "status" command) are
703
-** removed as if by the "rm" command.
703
+** removed as if by the "[[rm]]" command.
704704
**
705
-** The command does not "commit". You must run the "commit" separately
705
+** The command does not "[[commit]]". You must run the "[[commit]]" separately
706706
** as a separate step.
707707
**
708708
** Files and directories whose names begin with "." are ignored unless
709709
** the --dotfiles option is used.
710710
**
@@ -733,11 +733,11 @@
733733
** removed. No flags other than --verbose and
734734
** --dry-run may be used with --reset.
735735
** --verbose|-v Outputs information about each --reset file.
736736
** Only usable with --reset.
737737
**
738
-** See also: add, rm
738
+** See also: [[add]], [[rm]]
739739
*/
740740
void addremove_cmd(void){
741741
Blob path;
742742
const char *zCleanFlag;
743743
const char *zIgnoreFlag;
@@ -953,11 +953,11 @@
953953
** Move or rename one or more files or directories within the repository tree.
954954
** You can either rename a file or directory or move it to another subdirectory.
955955
**
956956
** The 'mv' command does NOT normally rename or move the files on disk.
957957
** This command merely records the fact that file names have changed so
958
-** that appropriate notations can be made at the next commit/check-in.
958
+** that appropriate notations can be made at the next [[commit]].
959959
** However, the default behavior of this command may be overridden via
960960
** command line options listed below and/or the 'mv-rm-files' setting.
961961
**
962962
** The 'rename' command never renames or moves files on disk, even when the
963963
** command line options and/or the 'mv-rm-files' setting would otherwise
@@ -966,17 +966,17 @@
966966
** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files"
967967
** setting is non-zero, files WILL BE renamed or moved on disk
968968
** as well. This does NOT apply to the 'rename' command.
969969
**
970970
** Options:
971
-** --soft Skip moving files within the checkout.
972
-** This supersedes the --hard option.
973
-** --hard Move files within the checkout.
974
-** --case-sensitive <BOOL> Override the case-sensitive setting.
975
-** -n|--dry-run If given, display instead of run actions.
971
+** --soft Skip moving files within the checkout.
972
+** This supersedes the --hard option.
973
+** --hard Move files within the checkout.
974
+** --case-sensitive <BOOL> Override the case-sensitive setting.
975
+** -n|--dry-run If given, display instead of run actions.
976976
**
977
-** See also: changes, status
977
+** See also: [[changes]], [[status]]
978978
*/
979979
void mv_cmd(void){
980980
int i;
981981
int vid;
982982
int moveFiles;
983983
--- src/add.c
+++ src/add.c
@@ -320,11 +320,11 @@
320 ** COMMAND: add
321 **
322 ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
323 **
324 ** Make arrangements to add one or more files or directories to the
325 ** current checkout at the next commit.
326 **
327 ** When adding files or directories recursively, filenames that begin
328 ** with "." are excluded by default. To include such files, add
329 ** the "--dotfiles" option to the command-line.
330 **
@@ -359,11 +359,11 @@
359 **
360 ** The following options are only valid with --reset:
361 ** -v|--verbose Outputs information about each --reset file.
362 ** -n|--dry-run Display instead of run actions.
363 **
364 ** See also: addremove, rm
365 */
366 void add_cmd(void){
367 int i; /* Loop counter */
368 int vid; /* Currently checked out version */
369 int nRoot; /* Full path characters in g.zLocalRoot */
@@ -541,11 +541,11 @@
541 ** than --verbose or --dry-run may be used with
542 ** --reset.
543 ** --verbose|-v Outputs information about each --reset file.
544 ** Only usable with --reset.
545 **
546 ** See also: addremove, add
547 */
548 void delete_cmd(void){
549 int i;
550 int removeFiles;
551 int dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -689,22 +689,22 @@
689 /*
690 ** COMMAND: addremove
691 **
692 ** Usage: %fossil addremove ?OPTIONS?
693 **
694 ** Do all necessary "add" and "rm" commands to synchronize the repository
695 ** with the content of the working checkout:
696 **
697 ** * All files in the checkout but not in the repository (that is,
698 ** all files displayed using the "extras" command) are added as
699 ** if by the "add" command.
700 **
701 ** * All files in the repository but missing from the checkout (that is,
702 ** all files that show as MISSING with the "status" command) are
703 ** removed as if by the "rm" command.
704 **
705 ** The command does not "commit". You must run the "commit" separately
706 ** as a separate step.
707 **
708 ** Files and directories whose names begin with "." are ignored unless
709 ** the --dotfiles option is used.
710 **
@@ -733,11 +733,11 @@
733 ** removed. No flags other than --verbose and
734 ** --dry-run may be used with --reset.
735 ** --verbose|-v Outputs information about each --reset file.
736 ** Only usable with --reset.
737 **
738 ** See also: add, rm
739 */
740 void addremove_cmd(void){
741 Blob path;
742 const char *zCleanFlag;
743 const char *zIgnoreFlag;
@@ -953,11 +953,11 @@
953 ** Move or rename one or more files or directories within the repository tree.
954 ** You can either rename a file or directory or move it to another subdirectory.
955 **
956 ** The 'mv' command does NOT normally rename or move the files on disk.
957 ** This command merely records the fact that file names have changed so
958 ** that appropriate notations can be made at the next commit/check-in.
959 ** However, the default behavior of this command may be overridden via
960 ** command line options listed below and/or the 'mv-rm-files' setting.
961 **
962 ** The 'rename' command never renames or moves files on disk, even when the
963 ** command line options and/or the 'mv-rm-files' setting would otherwise
@@ -966,17 +966,17 @@
966 ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files"
967 ** setting is non-zero, files WILL BE renamed or moved on disk
968 ** as well. This does NOT apply to the 'rename' command.
969 **
970 ** Options:
971 ** --soft Skip moving files within the checkout.
972 ** This supersedes the --hard option.
973 ** --hard Move files within the checkout.
974 ** --case-sensitive <BOOL> Override the case-sensitive setting.
975 ** -n|--dry-run If given, display instead of run actions.
976 **
977 ** See also: changes, status
978 */
979 void mv_cmd(void){
980 int i;
981 int vid;
982 int moveFiles;
983
--- src/add.c
+++ src/add.c
@@ -320,11 +320,11 @@
320 ** COMMAND: add
321 **
322 ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
323 **
324 ** Make arrangements to add one or more files or directories to the
325 ** current checkout at the next [[commit]].
326 **
327 ** When adding files or directories recursively, filenames that begin
328 ** with "." are excluded by default. To include such files, add
329 ** the "--dotfiles" option to the command-line.
330 **
@@ -359,11 +359,11 @@
359 **
360 ** The following options are only valid with --reset:
361 ** -v|--verbose Outputs information about each --reset file.
362 ** -n|--dry-run Display instead of run actions.
363 **
364 ** See also: [[addremove]], [[rm]]
365 */
366 void add_cmd(void){
367 int i; /* Loop counter */
368 int vid; /* Currently checked out version */
369 int nRoot; /* Full path characters in g.zLocalRoot */
@@ -541,11 +541,11 @@
541 ** than --verbose or --dry-run may be used with
542 ** --reset.
543 ** --verbose|-v Outputs information about each --reset file.
544 ** Only usable with --reset.
545 **
546 ** See also: [[addremove]], [[add]]
547 */
548 void delete_cmd(void){
549 int i;
550 int removeFiles;
551 int dryRunFlag = find_option("dry-run","n",0)!=0;
@@ -689,22 +689,22 @@
689 /*
690 ** COMMAND: addremove
691 **
692 ** Usage: %fossil addremove ?OPTIONS?
693 **
694 ** Do all necessary "[[add]]" and "[[rm]]" commands to synchronize the
695 ** repository with the content of the working checkout:
696 **
697 ** * All files in the checkout but not in the repository (that is,
698 ** all files displayed using the "extras" command) are added as
699 ** if by the "[[add]]" command.
700 **
701 ** * All files in the repository but missing from the checkout (that is,
702 ** all files that show as MISSING with the "status" command) are
703 ** removed as if by the "[[rm]]" command.
704 **
705 ** The command does not "[[commit]]". You must run the "[[commit]]" separately
706 ** as a separate step.
707 **
708 ** Files and directories whose names begin with "." are ignored unless
709 ** the --dotfiles option is used.
710 **
@@ -733,11 +733,11 @@
733 ** removed. No flags other than --verbose and
734 ** --dry-run may be used with --reset.
735 ** --verbose|-v Outputs information about each --reset file.
736 ** Only usable with --reset.
737 **
738 ** See also: [[add]], [[rm]]
739 */
740 void addremove_cmd(void){
741 Blob path;
742 const char *zCleanFlag;
743 const char *zIgnoreFlag;
@@ -953,11 +953,11 @@
953 ** Move or rename one or more files or directories within the repository tree.
954 ** You can either rename a file or directory or move it to another subdirectory.
955 **
956 ** The 'mv' command does NOT normally rename or move the files on disk.
957 ** This command merely records the fact that file names have changed so
958 ** that appropriate notations can be made at the next [[commit]].
959 ** However, the default behavior of this command may be overridden via
960 ** command line options listed below and/or the 'mv-rm-files' setting.
961 **
962 ** The 'rename' command never renames or moves files on disk, even when the
963 ** command line options and/or the 'mv-rm-files' setting would otherwise
@@ -966,17 +966,17 @@
966 ** WARNING: If the "--hard" option is specified -OR- the "mv-rm-files"
967 ** setting is non-zero, files WILL BE renamed or moved on disk
968 ** as well. This does NOT apply to the 'rename' command.
969 **
970 ** Options:
971 ** --soft Skip moving files within the checkout.
972 ** This supersedes the --hard option.
973 ** --hard Move files within the checkout.
974 ** --case-sensitive <BOOL> Override the case-sensitive setting.
975 ** -n|--dry-run If given, display instead of run actions.
976 **
977 ** See also: [[changes]], [[status]]
978 */
979 void mv_cmd(void){
980 int i;
981 int vid;
982 int moveFiles;
983
+15 -2
--- src/ajax.c
+++ src/ajax.c
@@ -130,11 +130,12 @@
130130
wiki_render_by_mimetype(pContent, zMime);
131131
break;
132132
default:{
133133
const char *zContent = blob_str(pContent);
134134
if(AJAX_PREVIEW_LINE_NUMBERS & flags){
135
- output_text_with_line_numbers(zContent, "on");
135
+ output_text_with_line_numbers(zContent, blob_size(pContent),
136
+ zName, "on");
136137
}else{
137138
const char *zExt = strrchr(zName,'.');
138139
if(zExt && zExt[1]){
139140
CX("<pre><code class='language-%s'>%h</code></pre>",
140141
zExt+1, zContent);
@@ -163,10 +164,20 @@
163164
}else{
164165
CX("<pre class='udiff'>%b</pre>",&out);
165166
}
166167
blob_reset(&out);
167168
}
169
+
170
+/*
171
+** Uses P(zKey) to fetch a CGI environment variable. If that var is
172
+** NULL or starts with '0' or 'f' then this function returns false,
173
+** else it returns true.
174
+*/
175
+int ajax_p_bool(char const *zKey){
176
+ const char * zVal = P(zKey);
177
+ return (!zVal || '0'==*zVal || 'f'==*zVal) ? 0 : 1;
178
+}
168179
169180
/*
170181
** Helper for /ajax routes. Clears the CGI content buffer, sets an
171182
** HTTP error status code, and queues up a JSON response in the form
172183
** of an object:
@@ -323,10 +334,11 @@
323334
if(zRenderMode!=0){
324335
cgi_printf_header("x-ajax-render-mode: %s\r\n", zRenderMode);
325336
}
326337
}
327338
339
+#if INTERFACE
328340
/*
329341
** Internal mapping of ajax sub-route names to various metadata.
330342
*/
331343
struct AjaxRoute {
332344
const char *zName; /* Name part of the route after "ajax/" */
@@ -334,16 +346,17 @@
334346
int bWriteMode; /* True if requires write mode */
335347
int bPost; /* True if requires POST (i.e. CSRF
336348
** verification) */
337349
};
338350
typedef struct AjaxRoute AjaxRoute;
351
+#endif /*INTERFACE*/
339352
340353
/*
341354
** Comparison function for bsearch() for searching an AjaxRoute
342355
** list for a matching name.
343356
*/
344
-static int cmp_ajax_route_name(const void *a, const void *b){
357
+int cmp_ajax_route_name(const void *a, const void *b){
345358
const AjaxRoute * rA = (const AjaxRoute*)a;
346359
const AjaxRoute * rB = (const AjaxRoute*)b;
347360
return fossil_strcmp(rA->zName, rB->zName);
348361
}
349362
350363
--- src/ajax.c
+++ src/ajax.c
@@ -130,11 +130,12 @@
130 wiki_render_by_mimetype(pContent, zMime);
131 break;
132 default:{
133 const char *zContent = blob_str(pContent);
134 if(AJAX_PREVIEW_LINE_NUMBERS & flags){
135 output_text_with_line_numbers(zContent, "on");
 
136 }else{
137 const char *zExt = strrchr(zName,'.');
138 if(zExt && zExt[1]){
139 CX("<pre><code class='language-%s'>%h</code></pre>",
140 zExt+1, zContent);
@@ -163,10 +164,20 @@
163 }else{
164 CX("<pre class='udiff'>%b</pre>",&out);
165 }
166 blob_reset(&out);
167 }
 
 
 
 
 
 
 
 
 
 
168
169 /*
170 ** Helper for /ajax routes. Clears the CGI content buffer, sets an
171 ** HTTP error status code, and queues up a JSON response in the form
172 ** of an object:
@@ -323,10 +334,11 @@
323 if(zRenderMode!=0){
324 cgi_printf_header("x-ajax-render-mode: %s\r\n", zRenderMode);
325 }
326 }
327
 
328 /*
329 ** Internal mapping of ajax sub-route names to various metadata.
330 */
331 struct AjaxRoute {
332 const char *zName; /* Name part of the route after "ajax/" */
@@ -334,16 +346,17 @@
334 int bWriteMode; /* True if requires write mode */
335 int bPost; /* True if requires POST (i.e. CSRF
336 ** verification) */
337 };
338 typedef struct AjaxRoute AjaxRoute;
 
339
340 /*
341 ** Comparison function for bsearch() for searching an AjaxRoute
342 ** list for a matching name.
343 */
344 static int cmp_ajax_route_name(const void *a, const void *b){
345 const AjaxRoute * rA = (const AjaxRoute*)a;
346 const AjaxRoute * rB = (const AjaxRoute*)b;
347 return fossil_strcmp(rA->zName, rB->zName);
348 }
349
350
--- src/ajax.c
+++ src/ajax.c
@@ -130,11 +130,12 @@
130 wiki_render_by_mimetype(pContent, zMime);
131 break;
132 default:{
133 const char *zContent = blob_str(pContent);
134 if(AJAX_PREVIEW_LINE_NUMBERS & flags){
135 output_text_with_line_numbers(zContent, blob_size(pContent),
136 zName, "on");
137 }else{
138 const char *zExt = strrchr(zName,'.');
139 if(zExt && zExt[1]){
140 CX("<pre><code class='language-%s'>%h</code></pre>",
141 zExt+1, zContent);
@@ -163,10 +164,20 @@
164 }else{
165 CX("<pre class='udiff'>%b</pre>",&out);
166 }
167 blob_reset(&out);
168 }
169
170 /*
171 ** Uses P(zKey) to fetch a CGI environment variable. If that var is
172 ** NULL or starts with '0' or 'f' then this function returns false,
173 ** else it returns true.
174 */
175 int ajax_p_bool(char const *zKey){
176 const char * zVal = P(zKey);
177 return (!zVal || '0'==*zVal || 'f'==*zVal) ? 0 : 1;
178 }
179
180 /*
181 ** Helper for /ajax routes. Clears the CGI content buffer, sets an
182 ** HTTP error status code, and queues up a JSON response in the form
183 ** of an object:
@@ -323,10 +334,11 @@
334 if(zRenderMode!=0){
335 cgi_printf_header("x-ajax-render-mode: %s\r\n", zRenderMode);
336 }
337 }
338
339 #if INTERFACE
340 /*
341 ** Internal mapping of ajax sub-route names to various metadata.
342 */
343 struct AjaxRoute {
344 const char *zName; /* Name part of the route after "ajax/" */
@@ -334,16 +346,17 @@
346 int bWriteMode; /* True if requires write mode */
347 int bPost; /* True if requires POST (i.e. CSRF
348 ** verification) */
349 };
350 typedef struct AjaxRoute AjaxRoute;
351 #endif /*INTERFACE*/
352
353 /*
354 ** Comparison function for bsearch() for searching an AjaxRoute
355 ** list for a matching name.
356 */
357 int cmp_ajax_route_name(const void *a, const void *b){
358 const AjaxRoute * rA = (const AjaxRoute*)a;
359 const AjaxRoute * rB = (const AjaxRoute*)b;
360 return fossil_strcmp(rA->zName, rB->zName);
361 }
362
363
--- src/allrepo.c
+++ src/allrepo.c
@@ -219,10 +219,11 @@
219219
zCmd = "dbstat --omit-version-info -R";
220220
showLabel = 1;
221221
quiet = 1;
222222
collect_argument(&extra, "brief", "b");
223223
collect_argument(&extra, "db-check", 0);
224
+ collect_argument(&extra, "db-verify", 0);
224225
}else if( strncmp(zCmd, "extras", n)==0 ){
225226
if( showFile ){
226227
zCmd = "extras --chdir";
227228
}else{
228229
zCmd = "extras --header --chdir";
229230
--- src/allrepo.c
+++ src/allrepo.c
@@ -219,10 +219,11 @@
219 zCmd = "dbstat --omit-version-info -R";
220 showLabel = 1;
221 quiet = 1;
222 collect_argument(&extra, "brief", "b");
223 collect_argument(&extra, "db-check", 0);
 
224 }else if( strncmp(zCmd, "extras", n)==0 ){
225 if( showFile ){
226 zCmd = "extras --chdir";
227 }else{
228 zCmd = "extras --header --chdir";
229
--- src/allrepo.c
+++ src/allrepo.c
@@ -219,10 +219,11 @@
219 zCmd = "dbstat --omit-version-info -R";
220 showLabel = 1;
221 quiet = 1;
222 collect_argument(&extra, "brief", "b");
223 collect_argument(&extra, "db-check", 0);
224 collect_argument(&extra, "db-verify", 0);
225 }else if( strncmp(zCmd, "extras", n)==0 ){
226 if( showFile ){
227 zCmd = "extras --chdir";
228 }else{
229 zCmd = "extras --header --chdir";
230
+1 -1
--- src/attach.c
+++ src/attach.c
@@ -617,11 +617,11 @@
617617
const char *z;
618618
content_get(ridSrc, &attach);
619619
blob_to_utf8_no_bom(&attach, 0);
620620
z = blob_str(&attach);
621621
if( zLn ){
622
- output_text_with_line_numbers(z, zLn);
622
+ output_text_with_line_numbers(z, blob_size(&attach), zName, zLn);
623623
}else{
624624
@ <pre>
625625
@ %h(z)
626626
@ </pre>
627627
}
628628
--- src/attach.c
+++ src/attach.c
@@ -617,11 +617,11 @@
617 const char *z;
618 content_get(ridSrc, &attach);
619 blob_to_utf8_no_bom(&attach, 0);
620 z = blob_str(&attach);
621 if( zLn ){
622 output_text_with_line_numbers(z, zLn);
623 }else{
624 @ <pre>
625 @ %h(z)
626 @ </pre>
627 }
628
--- src/attach.c
+++ src/attach.c
@@ -617,11 +617,11 @@
617 const char *z;
618 content_get(ridSrc, &attach);
619 blob_to_utf8_no_bom(&attach, 0);
620 z = blob_str(&attach);
621 if( zLn ){
622 output_text_with_line_numbers(z, blob_size(&attach), zName, zLn);
623 }else{
624 @ <pre>
625 @ %h(z)
626 @ </pre>
627 }
628
+2 -1
--- src/bisect.c
+++ src/bisect.c
@@ -381,11 +381,12 @@
381381
/*
382382
** COMMAND: bisect
383383
**
384384
** Usage: %fossil bisect SUBCOMMAND ...
385385
**
386
-** Run various subcommands useful for searching for bugs.
386
+** Run various subcommands useful for searching back through the change
387
+** history for a particular checkin that causes or fixes a problem.
387388
**
388389
** > fossil bisect bad ?VERSION?
389390
**
390391
** Identify version VERSION as non-working. If VERSION is omitted,
391392
** the current checkout is marked as non-working.
392393
--- src/bisect.c
+++ src/bisect.c
@@ -381,11 +381,12 @@
381 /*
382 ** COMMAND: bisect
383 **
384 ** Usage: %fossil bisect SUBCOMMAND ...
385 **
386 ** Run various subcommands useful for searching for bugs.
 
387 **
388 ** > fossil bisect bad ?VERSION?
389 **
390 ** Identify version VERSION as non-working. If VERSION is omitted,
391 ** the current checkout is marked as non-working.
392
--- src/bisect.c
+++ src/bisect.c
@@ -381,11 +381,12 @@
381 /*
382 ** COMMAND: bisect
383 **
384 ** Usage: %fossil bisect SUBCOMMAND ...
385 **
386 ** Run various subcommands useful for searching back through the change
387 ** history for a particular checkin that causes or fixes a problem.
388 **
389 ** > fossil bisect bad ?VERSION?
390 **
391 ** Identify version VERSION as non-working. If VERSION is omitted,
392 ** the current checkout is marked as non-working.
393
+5
--- src/blob.c
+++ src/blob.c
@@ -487,10 +487,15 @@
487487
**
488488
** For semantic compatibility with blob_append_full(), if newSize is
489489
** >=0x7fff000 (~2GB) then this function will trigger blob_panic(). If
490490
** it didn't, it would be possible to bypass that hard-coded limit via
491491
** this function.
492
+**
493
+** We've had at least one report:
494
+** https://fossil-scm.org/forum/forumpost/b7bbd28db4
495
+** which implies that this is unconditionally failing on mingw 32-bit
496
+** builds.
492497
*/
493498
void blob_reserve(Blob *pBlob, unsigned int newSize){
494499
if(newSize>=0x7fff0000 ){
495500
blob_panic();
496501
}else if(newSize>pBlob->nUsed){
497502
--- src/blob.c
+++ src/blob.c
@@ -487,10 +487,15 @@
487 **
488 ** For semantic compatibility with blob_append_full(), if newSize is
489 ** >=0x7fff000 (~2GB) then this function will trigger blob_panic(). If
490 ** it didn't, it would be possible to bypass that hard-coded limit via
491 ** this function.
 
 
 
 
 
492 */
493 void blob_reserve(Blob *pBlob, unsigned int newSize){
494 if(newSize>=0x7fff0000 ){
495 blob_panic();
496 }else if(newSize>pBlob->nUsed){
497
--- src/blob.c
+++ src/blob.c
@@ -487,10 +487,15 @@
487 **
488 ** For semantic compatibility with blob_append_full(), if newSize is
489 ** >=0x7fff000 (~2GB) then this function will trigger blob_panic(). If
490 ** it didn't, it would be possible to bypass that hard-coded limit via
491 ** this function.
492 **
493 ** We've had at least one report:
494 ** https://fossil-scm.org/forum/forumpost/b7bbd28db4
495 ** which implies that this is unconditionally failing on mingw 32-bit
496 ** builds.
497 */
498 void blob_reserve(Blob *pBlob, unsigned int newSize){
499 if(newSize>=0x7fff0000 ){
500 blob_panic();
501 }else if(newSize>pBlob->nUsed){
502
--- src/branch.c
+++ src/branch.c
@@ -382,16 +382,10 @@
382382
** Either no timezone suffix or "Z" means UTC.
383383
**
384384
** Options valid for all subcommands:
385385
**
386386
** -R|--repository FILE Run commands on repository FILE
387
-**
388
-** Summary:
389
-** fossil branch current
390
-** fossil branch info BRANCH-NAME
391
-** fossil branch [list|ls]
392
-** fossil branch new BRANCH-NAME BASIS
393387
*/
394388
void branch_cmd(void){
395389
int n;
396390
const char *zCmd = "list";
397391
db_find_and_open_repository(0, 0);
398392
--- src/branch.c
+++ src/branch.c
@@ -382,16 +382,10 @@
382 ** Either no timezone suffix or "Z" means UTC.
383 **
384 ** Options valid for all subcommands:
385 **
386 ** -R|--repository FILE Run commands on repository FILE
387 **
388 ** Summary:
389 ** fossil branch current
390 ** fossil branch info BRANCH-NAME
391 ** fossil branch [list|ls]
392 ** fossil branch new BRANCH-NAME BASIS
393 */
394 void branch_cmd(void){
395 int n;
396 const char *zCmd = "list";
397 db_find_and_open_repository(0, 0);
398
--- src/branch.c
+++ src/branch.c
@@ -382,16 +382,10 @@
382 ** Either no timezone suffix or "Z" means UTC.
383 **
384 ** Options valid for all subcommands:
385 **
386 ** -R|--repository FILE Run commands on repository FILE
 
 
 
 
 
 
387 */
388 void branch_cmd(void){
389 int n;
390 const char *zCmd = "list";
391 db_find_and_open_repository(0, 0);
392
+1 -1
--- src/browse.c
+++ src/browse.c
@@ -911,11 +911,11 @@
911911
}
912912
}
913913
}
914914
@ </ul>
915915
@ </ul></div>
916
- style_load_one_js_file("tree.js");
916
+ builtin_request_js("tree.js");
917917
style_footer();
918918
919919
/* We could free memory used by sTree here if we needed to. But
920920
** the process is about to exit, so doing so would not really accomplish
921921
** anything useful. */
922922
--- src/browse.c
+++ src/browse.c
@@ -911,11 +911,11 @@
911 }
912 }
913 }
914 @ </ul>
915 @ </ul></div>
916 style_load_one_js_file("tree.js");
917 style_footer();
918
919 /* We could free memory used by sTree here if we needed to. But
920 ** the process is about to exit, so doing so would not really accomplish
921 ** anything useful. */
922
--- src/browse.c
+++ src/browse.c
@@ -911,11 +911,11 @@
911 }
912 }
913 }
914 @ </ul>
915 @ </ul></div>
916 builtin_request_js("tree.js");
917 style_footer();
918
919 /* We could free memory used by sTree here if we needed to. But
920 ** the process is about to exit, so doing so would not really accomplish
921 ** anything useful. */
922
+459 -10
--- src/builtin.c
+++ src/builtin.c
@@ -28,13 +28,15 @@
2828
** builtin_data.h file. Include that information here:
2929
*/
3030
#include "builtin_data.h"
3131
3232
/*
33
-** Return a pointer to built-in content
33
+** Return the index in the aBuiltinFiles[] array for the file
34
+** whose name is zFilename. Or return -1 if the file is not
35
+** found.
3436
*/
35
-const unsigned char *builtin_file(const char *zFilename, int *piSize){
37
+static int builtin_file_index(const char *zFilename){
3638
int lwr, upr, i, c;
3739
lwr = 0;
3840
upr = count(aBuiltinFiles) - 1;
3941
while( upr>=lwr ){
4042
i = (upr+lwr)/2;
@@ -42,16 +44,28 @@
4244
if( c<0 ){
4345
lwr = i+1;
4446
}else if( c>0 ){
4547
upr = i-1;
4648
}else{
47
- if( piSize ) *piSize = aBuiltinFiles[i].nByte;
48
- return aBuiltinFiles[i].pData;
49
+ return i;
4950
}
5051
}
51
- if( piSize ) *piSize = 0;
52
- return 0;
52
+ return -1;
53
+}
54
+
55
+/*
56
+** Return a pointer to built-in content
57
+*/
58
+const unsigned char *builtin_file(const char *zFilename, int *piSize){
59
+ int i = builtin_file_index(zFilename);
60
+ if( i>=0 ){
61
+ if( piSize ) *piSize = aBuiltinFiles[i].nByte;
62
+ return aBuiltinFiles[i].pData;
63
+ }else{
64
+ if( piSize ) *piSize = 0;
65
+ return 0;
66
+ }
5367
}
5468
const char *builtin_text(const char *zFilename){
5569
return (char*)builtin_file(zFilename, 0);
5670
}
5771
@@ -65,11 +79,11 @@
6579
*/
6680
void test_builtin_list(void){
6781
int i, size = 0;;
6882
for(i=0; i<count(aBuiltinFiles); i++){
6983
const int n = aBuiltinFiles[i].nByte;
70
- fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,n);
84
+ fossil_print("%3d. %-45s %6d\n", i+1, aBuiltinFiles[i].zName,n);
7185
size += n;
7286
}
7387
if(find_option("verbose","v",0)!=0){
7488
fossil_print("%d entries totaling %d bytes\n", i, size);
7589
}
@@ -81,16 +95,18 @@
8195
** Show all built-in text files.
8296
*/
8397
void test_builtin_list_page(void){
8498
int i;
8599
style_header("Built-in Text Files");
86
- @ <ul>
100
+ @ <ol>
87101
for(i=0; i<count(aBuiltinFiles); i++){
88102
const char *z = aBuiltinFiles[i].zName;
89
- @ <li>%z(href("%R/builtin?name=%T&id=%S",z,MANIFEST_UUID))%h(z)</a>
103
+ char *zUrl = href("%R/builtin?name=%T&id=%.8s&mimetype=text/plain",
104
+ z,fossil_exe_id());
105
+ @ <li>%z(zUrl)%h(z)</a>
90106
}
91
- @ </ul>
107
+ @ </ol>
92108
style_footer();
93109
}
94110
95111
/*
96112
** COMMAND: test-builtin-get
@@ -110,5 +126,438 @@
110126
}
111127
blob_init(&x, (const char*)pData, nByte);
112128
blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-");
113129
blob_reset(&x);
114130
}
131
+
132
+/*
133
+** Input zList is a list of numeric identifiers for files in
134
+** aBuiltinFiles[]. Return the concatenation of all of those
135
+** files using mimetype zType, or as application/javascript if
136
+** zType is 0.
137
+*/
138
+static void builtin_deliver_multiple_js_files(
139
+ const char *zList, /* List of numeric identifiers */
140
+ const char *zType /* Override mimetype */
141
+){
142
+ Blob *pOut;
143
+ if( zType==0 ) zType = "application/javascript";
144
+ cgi_set_content_type(zType);
145
+ pOut = cgi_output_blob();
146
+ while( zList[0] ){
147
+ int i = atoi(zList);
148
+ if( i>0 && i<=count(aBuiltinFiles) ){
149
+ blob_appendf(pOut, "/* %s */\n", aBuiltinFiles[i-1].zName);
150
+ blob_append(pOut, (const char*)aBuiltinFiles[i-1].pData,
151
+ aBuiltinFiles[i-1].nByte);
152
+ }
153
+ while( fossil_isdigit(zList[0]) ) zList++;
154
+ if( zList[0]==',' ) zList++;
155
+ }
156
+ return;
157
+}
158
+
159
+/*
160
+** WEBPAGE: builtin
161
+**
162
+** Return one of many built-in content files. Query parameters:
163
+**
164
+** name=FILENAME Return the single file whose name is FILENAME.
165
+** mimetype=TYPE Override the mimetype in the returned file to
166
+** be TYPE. If this query parameter is omitted
167
+** (the usual case) then the mimetype is inferred
168
+** from the suffix on FILENAME
169
+** m=IDLIST IDLIST is a comma-separated list of integers
170
+** that specify multiple javascript files to be
171
+** concatenated and returned all at once.
172
+** id=UNIQUEID Version number of the "builtin" files. Used
173
+** for cache control only.
174
+**
175
+** At least one of the name= or m= query parameters must be present.
176
+**
177
+** If the id= query parameter is present, then Fossil assumes that the
178
+** result is immutable and sets a very large cache retention time (1 year).
179
+*/
180
+void builtin_webpage(void){
181
+ Blob out;
182
+ const char *zName = P("name");
183
+ const char *zTxt = 0;
184
+ const char *zId = P("id");
185
+ const char *zType = P("mimetype");
186
+ int nId;
187
+ if( zName ) zTxt = builtin_text(zName);
188
+ if( zTxt==0 ){
189
+ const char *zM = P("m");
190
+ if( zM ){
191
+ if( zId && (nId = (int)strlen(zId))>=8
192
+ && strncmp(zId,fossil_exe_id(),nId)==0
193
+ ){
194
+ g.isConst = 1;
195
+ }
196
+ etag_check(0,0);
197
+ builtin_deliver_multiple_js_files(zM, zType);
198
+ return;
199
+ }
200
+ cgi_set_status(404, "Not Found");
201
+ @ File "%h(zName)" not found
202
+ return;
203
+ }
204
+ if( zType==0 ){
205
+ if( sqlite3_strglob("*.js", zName)==0 ){
206
+ zType = "application/javascript";
207
+ }else{
208
+ zType = mimetype_from_name(zName);
209
+ }
210
+ }
211
+ cgi_set_content_type(zType);
212
+ if( zId
213
+ && (nId = (int)strlen(zId))>=8
214
+ && strncmp(zId,fossil_exe_id(),nId)==0
215
+ ){
216
+ g.isConst = 1;
217
+ }
218
+ etag_check(0,0);
219
+ blob_init(&out, zTxt, -1);
220
+ cgi_set_content(&out);
221
+}
222
+
223
+/* Variables controlling the JS cache.
224
+*/
225
+static struct {
226
+ int aReq[30]; /* Indexes of all requested built-in JS files */
227
+ int nReq; /* Number of slots in aReq[] currently used */
228
+ int nSent; /* Number of slots in aReq[] fulfilled */
229
+ int eDelivery; /* Delivery mechanism */
230
+} builtin;
231
+
232
+#if INTERFACE
233
+/* Various delivery mechanisms. The 0 option is the default.
234
+*/
235
+#define JS_INLINE 0 /* inline, batched together at end of file */
236
+#define JS_SEPARATE 1 /* Separate HTTP request for each JS file */
237
+#define JS_BUNDLED 2 /* One HTTP request to load all JS files */
238
+ /* concatenated together into a bundle */
239
+#endif /* INTERFACE */
240
+
241
+/*
242
+** The argument is a request to change the javascript delivery mode.
243
+** The argument is a string which is a command-line option or CGI
244
+** parameter. Try to match it against one of the delivery options
245
+** and set things up accordingly. Throw an error if no match unless
246
+** bSilent is true.
247
+*/
248
+void builtin_set_js_delivery_mode(const char *zMode, int bSilent){
249
+ if( zMode==0 ) return;
250
+ if( strcmp(zMode, "inline")==0 ){
251
+ builtin.eDelivery = JS_INLINE;
252
+ }else
253
+ if( strcmp(zMode, "separate")==0 ){
254
+ builtin.eDelivery = JS_SEPARATE;
255
+ }else
256
+ if( strcmp(zMode, "bundled")==0 ){
257
+ builtin.eDelivery = JS_BUNDLED;
258
+ }else if( !bSilent ){
259
+ fossil_fatal("unknown javascript delivery mode \"%s\" - should be"
260
+ " one of: inline separate bundled", zMode);
261
+ }
262
+}
263
+
264
+/*
265
+** The caller wants the Javascript file named by zFilename to be
266
+** included in the generated page. Add the file to the queue of
267
+** requested javascript resources, if it is not there already.
268
+**
269
+** The current implementation queues the file to be included in the
270
+** output later. However, the caller should not depend on that
271
+** behavior. In the future, this routine might decide to insert
272
+** the requested javascript inline, immedaitely, or to insert
273
+** a <script src=..> element to reference the javascript as a
274
+** separate resource. The exact behavior might change in the future
275
+** so pages that use this interface must not rely on any particular
276
+** behavior.
277
+**
278
+** All this routine guarantees is that the named javascript file
279
+** will be requested by the browser at some point. This routine
280
+** does not guarantee when the javascript will be included, and it
281
+** does not guarantee whether the javascript will be added inline or
282
+** delivered as a separate resource.
283
+*/
284
+void builtin_request_js(const char *zFilename){
285
+ int i = builtin_file_index(zFilename);
286
+ int j;
287
+ if( i<0 ){
288
+ fossil_panic("unknown javascript file: \"%s\"", zFilename);
289
+ }
290
+ for(j=0; j<builtin.nReq; j++){
291
+ if( builtin.aReq[j]==i ) return; /* Already queued or sent */
292
+ }
293
+ if( builtin.nReq>=count(builtin.aReq) ){
294
+ fossil_panic("too many javascript files requested");
295
+ }
296
+ builtin.aReq[builtin.nReq++] = i;
297
+}
298
+
299
+/*
300
+** Fulfill all pending requests for javascript files.
301
+**
302
+** The current implementation delivers all javascript in-line. However,
303
+** the caller should not depend on this. Future changes to this routine
304
+** might choose to deliver javascript as separate resources.
305
+*/
306
+void builtin_fulfill_js_requests(void){
307
+ if( builtin.nSent>=builtin.nReq ) return; /* nothing to do */
308
+ switch( builtin.eDelivery ){
309
+ case JS_INLINE: {
310
+ CX("<script nonce='%h'>\n",style_nonce());
311
+ do{
312
+ int i = builtin.aReq[builtin.nSent++];
313
+ CX("/* %s */\n", aBuiltinFiles[i].zName);
314
+ cgi_append_content((const char*)aBuiltinFiles[i].pData,
315
+ aBuiltinFiles[i].nByte);
316
+ }while( builtin.nSent<builtin.nReq );
317
+ CX("</script>\n");
318
+ break;
319
+ }
320
+ case JS_BUNDLED: {
321
+ if( builtin.nSent+1<builtin.nReq ){
322
+ Blob aList;
323
+ blob_init(&aList,0,0);
324
+ while( builtin.nSent<builtin.nReq ){
325
+ blob_appendf(&aList, ",%d", builtin.aReq[builtin.nSent++]+1);
326
+ }
327
+ CX("<script src='%R/builtin?m=%s&id=%.8s'></script>\n",
328
+ blob_str(&aList)+1, fossil_exe_id());
329
+ blob_reset(&aList);
330
+ break;
331
+ }
332
+ /* If there is only one JS file, fall through into the
333
+ ** JS_SEPARATE case below. */
334
+ /*FALLTHROUGH*/
335
+ }
336
+ case JS_SEPARATE: {
337
+ /* Each JS file as a separate resource */
338
+ while( builtin.nSent<builtin.nReq ){
339
+ int i = builtin.aReq[builtin.nSent++];
340
+ CX("<script src='%R/builtin?name=%t&id=%.8s'></script>\n",
341
+ aBuiltinFiles[i].zName, fossil_exe_id());
342
+ }
343
+ break;
344
+ }
345
+ }
346
+}
347
+
348
+/*****************************************************************************
349
+** A virtual table for accessing the information in aBuiltinFiles[].
350
+*/
351
+
352
+/* builtinVtab_vtab is a subclass of sqlite3_vtab which is
353
+** underlying representation of the virtual table
354
+*/
355
+typedef struct builtinVtab_vtab builtinVtab_vtab;
356
+struct builtinVtab_vtab {
357
+ sqlite3_vtab base; /* Base class - must be first */
358
+ /* Add new fields here, as necessary */
359
+};
360
+
361
+/* builtinVtab_cursor is a subclass of sqlite3_vtab_cursor which will
362
+** serve as the underlying representation of a cursor that scans
363
+** over rows of the result
364
+*/
365
+typedef struct builtinVtab_cursor builtinVtab_cursor;
366
+struct builtinVtab_cursor {
367
+ sqlite3_vtab_cursor base; /* Base class - must be first */
368
+ /* Insert new fields here. For this builtinVtab we only keep track
369
+ ** of the rowid */
370
+ sqlite3_int64 iRowid; /* The rowid */
371
+};
372
+
373
+/*
374
+** The builtinVtabConnect() method is invoked to create a new
375
+** builtin virtual table.
376
+**
377
+** Think of this routine as the constructor for builtinVtab_vtab objects.
378
+**
379
+** All this routine needs to do is:
380
+**
381
+** (1) Allocate the builtinVtab_vtab object and initialize all fields.
382
+**
383
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
384
+** result set of queries against the virtual table will look like.
385
+*/
386
+static int builtinVtabConnect(
387
+ sqlite3 *db,
388
+ void *pAux,
389
+ int argc, const char *const*argv,
390
+ sqlite3_vtab **ppVtab,
391
+ char **pzErr
392
+){
393
+ builtinVtab_vtab *pNew;
394
+ int rc;
395
+
396
+ rc = sqlite3_declare_vtab(db,
397
+ "CREATE TABLE x(name,size,data)"
398
+ );
399
+ if( rc==SQLITE_OK ){
400
+ pNew = sqlite3_malloc( sizeof(*pNew) );
401
+ *ppVtab = (sqlite3_vtab*)pNew;
402
+ if( pNew==0 ) return SQLITE_NOMEM;
403
+ memset(pNew, 0, sizeof(*pNew));
404
+ }
405
+ return rc;
406
+}
407
+
408
+/*
409
+** This method is the destructor for builtinVtab_vtab objects.
410
+*/
411
+static int builtinVtabDisconnect(sqlite3_vtab *pVtab){
412
+ builtinVtab_vtab *p = (builtinVtab_vtab*)pVtab;
413
+ sqlite3_free(p);
414
+ return SQLITE_OK;
415
+}
416
+
417
+/*
418
+** Constructor for a new builtinVtab_cursor object.
419
+*/
420
+static int builtinVtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
421
+ builtinVtab_cursor *pCur;
422
+ pCur = sqlite3_malloc( sizeof(*pCur) );
423
+ if( pCur==0 ) return SQLITE_NOMEM;
424
+ memset(pCur, 0, sizeof(*pCur));
425
+ *ppCursor = &pCur->base;
426
+ return SQLITE_OK;
427
+}
428
+
429
+/*
430
+** Destructor for a builtinVtab_cursor.
431
+*/
432
+static int builtinVtabClose(sqlite3_vtab_cursor *cur){
433
+ builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
434
+ sqlite3_free(pCur);
435
+ return SQLITE_OK;
436
+}
437
+
438
+
439
+/*
440
+** Advance a builtinVtab_cursor to its next row of output.
441
+*/
442
+static int builtinVtabNext(sqlite3_vtab_cursor *cur){
443
+ builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
444
+ pCur->iRowid++;
445
+ return SQLITE_OK;
446
+}
447
+
448
+/*
449
+** Return values of columns for the row at which the builtinVtab_cursor
450
+** is currently pointing.
451
+*/
452
+static int builtinVtabColumn(
453
+ sqlite3_vtab_cursor *cur, /* The cursor */
454
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
455
+ int i /* Which column to return */
456
+){
457
+ builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
458
+ const struct BuiltinFileTable *pFile = aBuiltinFiles + pCur->iRowid;
459
+ switch( i ){
460
+ case 0: /* name */
461
+ sqlite3_result_text(ctx, pFile->zName, -1, SQLITE_STATIC);
462
+ break;
463
+ case 1: /* size */
464
+ sqlite3_result_int(ctx, pFile->nByte);
465
+ break;
466
+ case 2: /* data */
467
+ sqlite3_result_blob(ctx, pFile->pData, pFile->nByte, SQLITE_STATIC);
468
+ break;
469
+ }
470
+ return SQLITE_OK;
471
+}
472
+
473
+/*
474
+** Return the rowid for the current row. In this implementation, the
475
+** rowid is the same as the output value.
476
+*/
477
+static int builtinVtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
478
+ builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
479
+ *pRowid = pCur->iRowid;
480
+ return SQLITE_OK;
481
+}
482
+
483
+/*
484
+** Return TRUE if the cursor has been moved off of the last
485
+** row of output.
486
+*/
487
+static int builtinVtabEof(sqlite3_vtab_cursor *cur){
488
+ builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
489
+ return pCur->iRowid>=count(aBuiltinFiles);
490
+}
491
+
492
+/*
493
+** This method is called to "rewind" the builtinVtab_cursor object back
494
+** to the first row of output. This method is always called at least
495
+** once prior to any call to builtinVtabColumn() or builtinVtabRowid() or
496
+** builtinVtabEof().
497
+*/
498
+static int builtinVtabFilter(
499
+ sqlite3_vtab_cursor *pVtabCursor,
500
+ int idxNum, const char *idxStr,
501
+ int argc, sqlite3_value **argv
502
+){
503
+ builtinVtab_cursor *pCur = (builtinVtab_cursor *)pVtabCursor;
504
+ pCur->iRowid = 1;
505
+ return SQLITE_OK;
506
+}
507
+
508
+/*
509
+** SQLite will invoke this method one or more times while planning a query
510
+** that uses the virtual table. This routine needs to create
511
+** a query plan for each invocation and compute an estimated cost for that
512
+** plan.
513
+*/
514
+static int builtinVtabBestIndex(
515
+ sqlite3_vtab *tab,
516
+ sqlite3_index_info *pIdxInfo
517
+){
518
+ pIdxInfo->estimatedCost = (double)count(aBuiltinFiles);
519
+ pIdxInfo->estimatedRows = count(aBuiltinFiles);
520
+ return SQLITE_OK;
521
+}
522
+
523
+/*
524
+** This following structure defines all the methods for the
525
+** virtual table.
526
+*/
527
+static sqlite3_module builtinVtabModule = {
528
+ /* iVersion */ 0,
529
+ /* xCreate */ 0, /* The builtin vtab is eponymous and read-only */
530
+ /* xConnect */ builtinVtabConnect,
531
+ /* xBestIndex */ builtinVtabBestIndex,
532
+ /* xDisconnect */ builtinVtabDisconnect,
533
+ /* xDestroy */ 0,
534
+ /* xOpen */ builtinVtabOpen,
535
+ /* xClose */ builtinVtabClose,
536
+ /* xFilter */ builtinVtabFilter,
537
+ /* xNext */ builtinVtabNext,
538
+ /* xEof */ builtinVtabEof,
539
+ /* xColumn */ builtinVtabColumn,
540
+ /* xRowid */ builtinVtabRowid,
541
+ /* xUpdate */ 0,
542
+ /* xBegin */ 0,
543
+ /* xSync */ 0,
544
+ /* xCommit */ 0,
545
+ /* xRollback */ 0,
546
+ /* xFindMethod */ 0,
547
+ /* xRename */ 0,
548
+ /* xSavepoint */ 0,
549
+ /* xRelease */ 0,
550
+ /* xRollbackTo */ 0,
551
+ /* xShadowName */ 0
552
+};
553
+
554
+
555
+/*
556
+** Register the builtin virtual table
557
+*/
558
+int builtin_vtab_register(sqlite3 *db){
559
+ int rc = sqlite3_create_module(db, "builtin", &builtinVtabModule, 0);
560
+ return rc;
561
+}
562
+/* End of the builtin virtual table
563
+******************************************************************************/
115564
--- src/builtin.c
+++ src/builtin.c
@@ -28,13 +28,15 @@
28 ** builtin_data.h file. Include that information here:
29 */
30 #include "builtin_data.h"
31
32 /*
33 ** Return a pointer to built-in content
 
 
34 */
35 const unsigned char *builtin_file(const char *zFilename, int *piSize){
36 int lwr, upr, i, c;
37 lwr = 0;
38 upr = count(aBuiltinFiles) - 1;
39 while( upr>=lwr ){
40 i = (upr+lwr)/2;
@@ -42,16 +44,28 @@
42 if( c<0 ){
43 lwr = i+1;
44 }else if( c>0 ){
45 upr = i-1;
46 }else{
47 if( piSize ) *piSize = aBuiltinFiles[i].nByte;
48 return aBuiltinFiles[i].pData;
49 }
50 }
51 if( piSize ) *piSize = 0;
52 return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
53 }
54 const char *builtin_text(const char *zFilename){
55 return (char*)builtin_file(zFilename, 0);
56 }
57
@@ -65,11 +79,11 @@
65 */
66 void test_builtin_list(void){
67 int i, size = 0;;
68 for(i=0; i<count(aBuiltinFiles); i++){
69 const int n = aBuiltinFiles[i].nByte;
70 fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,n);
71 size += n;
72 }
73 if(find_option("verbose","v",0)!=0){
74 fossil_print("%d entries totaling %d bytes\n", i, size);
75 }
@@ -81,16 +95,18 @@
81 ** Show all built-in text files.
82 */
83 void test_builtin_list_page(void){
84 int i;
85 style_header("Built-in Text Files");
86 @ <ul>
87 for(i=0; i<count(aBuiltinFiles); i++){
88 const char *z = aBuiltinFiles[i].zName;
89 @ <li>%z(href("%R/builtin?name=%T&id=%S",z,MANIFEST_UUID))%h(z)</a>
 
 
90 }
91 @ </ul>
92 style_footer();
93 }
94
95 /*
96 ** COMMAND: test-builtin-get
@@ -110,5 +126,438 @@
110 }
111 blob_init(&x, (const char*)pData, nByte);
112 blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-");
113 blob_reset(&x);
114 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
--- src/builtin.c
+++ src/builtin.c
@@ -28,13 +28,15 @@
28 ** builtin_data.h file. Include that information here:
29 */
30 #include "builtin_data.h"
31
32 /*
33 ** Return the index in the aBuiltinFiles[] array for the file
34 ** whose name is zFilename. Or return -1 if the file is not
35 ** found.
36 */
37 static int builtin_file_index(const char *zFilename){
38 int lwr, upr, i, c;
39 lwr = 0;
40 upr = count(aBuiltinFiles) - 1;
41 while( upr>=lwr ){
42 i = (upr+lwr)/2;
@@ -42,16 +44,28 @@
44 if( c<0 ){
45 lwr = i+1;
46 }else if( c>0 ){
47 upr = i-1;
48 }else{
49 return i;
 
50 }
51 }
52 return -1;
53 }
54
55 /*
56 ** Return a pointer to built-in content
57 */
58 const unsigned char *builtin_file(const char *zFilename, int *piSize){
59 int i = builtin_file_index(zFilename);
60 if( i>=0 ){
61 if( piSize ) *piSize = aBuiltinFiles[i].nByte;
62 return aBuiltinFiles[i].pData;
63 }else{
64 if( piSize ) *piSize = 0;
65 return 0;
66 }
67 }
68 const char *builtin_text(const char *zFilename){
69 return (char*)builtin_file(zFilename, 0);
70 }
71
@@ -65,11 +79,11 @@
79 */
80 void test_builtin_list(void){
81 int i, size = 0;;
82 for(i=0; i<count(aBuiltinFiles); i++){
83 const int n = aBuiltinFiles[i].nByte;
84 fossil_print("%3d. %-45s %6d\n", i+1, aBuiltinFiles[i].zName,n);
85 size += n;
86 }
87 if(find_option("verbose","v",0)!=0){
88 fossil_print("%d entries totaling %d bytes\n", i, size);
89 }
@@ -81,16 +95,18 @@
95 ** Show all built-in text files.
96 */
97 void test_builtin_list_page(void){
98 int i;
99 style_header("Built-in Text Files");
100 @ <ol>
101 for(i=0; i<count(aBuiltinFiles); i++){
102 const char *z = aBuiltinFiles[i].zName;
103 char *zUrl = href("%R/builtin?name=%T&id=%.8s&mimetype=text/plain",
104 z,fossil_exe_id());
105 @ <li>%z(zUrl)%h(z)</a>
106 }
107 @ </ol>
108 style_footer();
109 }
110
111 /*
112 ** COMMAND: test-builtin-get
@@ -110,5 +126,438 @@
126 }
127 blob_init(&x, (const char*)pData, nByte);
128 blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-");
129 blob_reset(&x);
130 }
131
132 /*
133 ** Input zList is a list of numeric identifiers for files in
134 ** aBuiltinFiles[]. Return the concatenation of all of those
135 ** files using mimetype zType, or as application/javascript if
136 ** zType is 0.
137 */
138 static void builtin_deliver_multiple_js_files(
139 const char *zList, /* List of numeric identifiers */
140 const char *zType /* Override mimetype */
141 ){
142 Blob *pOut;
143 if( zType==0 ) zType = "application/javascript";
144 cgi_set_content_type(zType);
145 pOut = cgi_output_blob();
146 while( zList[0] ){
147 int i = atoi(zList);
148 if( i>0 && i<=count(aBuiltinFiles) ){
149 blob_appendf(pOut, "/* %s */\n", aBuiltinFiles[i-1].zName);
150 blob_append(pOut, (const char*)aBuiltinFiles[i-1].pData,
151 aBuiltinFiles[i-1].nByte);
152 }
153 while( fossil_isdigit(zList[0]) ) zList++;
154 if( zList[0]==',' ) zList++;
155 }
156 return;
157 }
158
159 /*
160 ** WEBPAGE: builtin
161 **
162 ** Return one of many built-in content files. Query parameters:
163 **
164 ** name=FILENAME Return the single file whose name is FILENAME.
165 ** mimetype=TYPE Override the mimetype in the returned file to
166 ** be TYPE. If this query parameter is omitted
167 ** (the usual case) then the mimetype is inferred
168 ** from the suffix on FILENAME
169 ** m=IDLIST IDLIST is a comma-separated list of integers
170 ** that specify multiple javascript files to be
171 ** concatenated and returned all at once.
172 ** id=UNIQUEID Version number of the "builtin" files. Used
173 ** for cache control only.
174 **
175 ** At least one of the name= or m= query parameters must be present.
176 **
177 ** If the id= query parameter is present, then Fossil assumes that the
178 ** result is immutable and sets a very large cache retention time (1 year).
179 */
180 void builtin_webpage(void){
181 Blob out;
182 const char *zName = P("name");
183 const char *zTxt = 0;
184 const char *zId = P("id");
185 const char *zType = P("mimetype");
186 int nId;
187 if( zName ) zTxt = builtin_text(zName);
188 if( zTxt==0 ){
189 const char *zM = P("m");
190 if( zM ){
191 if( zId && (nId = (int)strlen(zId))>=8
192 && strncmp(zId,fossil_exe_id(),nId)==0
193 ){
194 g.isConst = 1;
195 }
196 etag_check(0,0);
197 builtin_deliver_multiple_js_files(zM, zType);
198 return;
199 }
200 cgi_set_status(404, "Not Found");
201 @ File "%h(zName)" not found
202 return;
203 }
204 if( zType==0 ){
205 if( sqlite3_strglob("*.js", zName)==0 ){
206 zType = "application/javascript";
207 }else{
208 zType = mimetype_from_name(zName);
209 }
210 }
211 cgi_set_content_type(zType);
212 if( zId
213 && (nId = (int)strlen(zId))>=8
214 && strncmp(zId,fossil_exe_id(),nId)==0
215 ){
216 g.isConst = 1;
217 }
218 etag_check(0,0);
219 blob_init(&out, zTxt, -1);
220 cgi_set_content(&out);
221 }
222
223 /* Variables controlling the JS cache.
224 */
225 static struct {
226 int aReq[30]; /* Indexes of all requested built-in JS files */
227 int nReq; /* Number of slots in aReq[] currently used */
228 int nSent; /* Number of slots in aReq[] fulfilled */
229 int eDelivery; /* Delivery mechanism */
230 } builtin;
231
232 #if INTERFACE
233 /* Various delivery mechanisms. The 0 option is the default.
234 */
235 #define JS_INLINE 0 /* inline, batched together at end of file */
236 #define JS_SEPARATE 1 /* Separate HTTP request for each JS file */
237 #define JS_BUNDLED 2 /* One HTTP request to load all JS files */
238 /* concatenated together into a bundle */
239 #endif /* INTERFACE */
240
241 /*
242 ** The argument is a request to change the javascript delivery mode.
243 ** The argument is a string which is a command-line option or CGI
244 ** parameter. Try to match it against one of the delivery options
245 ** and set things up accordingly. Throw an error if no match unless
246 ** bSilent is true.
247 */
248 void builtin_set_js_delivery_mode(const char *zMode, int bSilent){
249 if( zMode==0 ) return;
250 if( strcmp(zMode, "inline")==0 ){
251 builtin.eDelivery = JS_INLINE;
252 }else
253 if( strcmp(zMode, "separate")==0 ){
254 builtin.eDelivery = JS_SEPARATE;
255 }else
256 if( strcmp(zMode, "bundled")==0 ){
257 builtin.eDelivery = JS_BUNDLED;
258 }else if( !bSilent ){
259 fossil_fatal("unknown javascript delivery mode \"%s\" - should be"
260 " one of: inline separate bundled", zMode);
261 }
262 }
263
264 /*
265 ** The caller wants the Javascript file named by zFilename to be
266 ** included in the generated page. Add the file to the queue of
267 ** requested javascript resources, if it is not there already.
268 **
269 ** The current implementation queues the file to be included in the
270 ** output later. However, the caller should not depend on that
271 ** behavior. In the future, this routine might decide to insert
272 ** the requested javascript inline, immedaitely, or to insert
273 ** a <script src=..> element to reference the javascript as a
274 ** separate resource. The exact behavior might change in the future
275 ** so pages that use this interface must not rely on any particular
276 ** behavior.
277 **
278 ** All this routine guarantees is that the named javascript file
279 ** will be requested by the browser at some point. This routine
280 ** does not guarantee when the javascript will be included, and it
281 ** does not guarantee whether the javascript will be added inline or
282 ** delivered as a separate resource.
283 */
284 void builtin_request_js(const char *zFilename){
285 int i = builtin_file_index(zFilename);
286 int j;
287 if( i<0 ){
288 fossil_panic("unknown javascript file: \"%s\"", zFilename);
289 }
290 for(j=0; j<builtin.nReq; j++){
291 if( builtin.aReq[j]==i ) return; /* Already queued or sent */
292 }
293 if( builtin.nReq>=count(builtin.aReq) ){
294 fossil_panic("too many javascript files requested");
295 }
296 builtin.aReq[builtin.nReq++] = i;
297 }
298
299 /*
300 ** Fulfill all pending requests for javascript files.
301 **
302 ** The current implementation delivers all javascript in-line. However,
303 ** the caller should not depend on this. Future changes to this routine
304 ** might choose to deliver javascript as separate resources.
305 */
306 void builtin_fulfill_js_requests(void){
307 if( builtin.nSent>=builtin.nReq ) return; /* nothing to do */
308 switch( builtin.eDelivery ){
309 case JS_INLINE: {
310 CX("<script nonce='%h'>\n",style_nonce());
311 do{
312 int i = builtin.aReq[builtin.nSent++];
313 CX("/* %s */\n", aBuiltinFiles[i].zName);
314 cgi_append_content((const char*)aBuiltinFiles[i].pData,
315 aBuiltinFiles[i].nByte);
316 }while( builtin.nSent<builtin.nReq );
317 CX("</script>\n");
318 break;
319 }
320 case JS_BUNDLED: {
321 if( builtin.nSent+1<builtin.nReq ){
322 Blob aList;
323 blob_init(&aList,0,0);
324 while( builtin.nSent<builtin.nReq ){
325 blob_appendf(&aList, ",%d", builtin.aReq[builtin.nSent++]+1);
326 }
327 CX("<script src='%R/builtin?m=%s&id=%.8s'></script>\n",
328 blob_str(&aList)+1, fossil_exe_id());
329 blob_reset(&aList);
330 break;
331 }
332 /* If there is only one JS file, fall through into the
333 ** JS_SEPARATE case below. */
334 /*FALLTHROUGH*/
335 }
336 case JS_SEPARATE: {
337 /* Each JS file as a separate resource */
338 while( builtin.nSent<builtin.nReq ){
339 int i = builtin.aReq[builtin.nSent++];
340 CX("<script src='%R/builtin?name=%t&id=%.8s'></script>\n",
341 aBuiltinFiles[i].zName, fossil_exe_id());
342 }
343 break;
344 }
345 }
346 }
347
348 /*****************************************************************************
349 ** A virtual table for accessing the information in aBuiltinFiles[].
350 */
351
352 /* builtinVtab_vtab is a subclass of sqlite3_vtab which is
353 ** underlying representation of the virtual table
354 */
355 typedef struct builtinVtab_vtab builtinVtab_vtab;
356 struct builtinVtab_vtab {
357 sqlite3_vtab base; /* Base class - must be first */
358 /* Add new fields here, as necessary */
359 };
360
361 /* builtinVtab_cursor is a subclass of sqlite3_vtab_cursor which will
362 ** serve as the underlying representation of a cursor that scans
363 ** over rows of the result
364 */
365 typedef struct builtinVtab_cursor builtinVtab_cursor;
366 struct builtinVtab_cursor {
367 sqlite3_vtab_cursor base; /* Base class - must be first */
368 /* Insert new fields here. For this builtinVtab we only keep track
369 ** of the rowid */
370 sqlite3_int64 iRowid; /* The rowid */
371 };
372
373 /*
374 ** The builtinVtabConnect() method is invoked to create a new
375 ** builtin virtual table.
376 **
377 ** Think of this routine as the constructor for builtinVtab_vtab objects.
378 **
379 ** All this routine needs to do is:
380 **
381 ** (1) Allocate the builtinVtab_vtab object and initialize all fields.
382 **
383 ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
384 ** result set of queries against the virtual table will look like.
385 */
386 static int builtinVtabConnect(
387 sqlite3 *db,
388 void *pAux,
389 int argc, const char *const*argv,
390 sqlite3_vtab **ppVtab,
391 char **pzErr
392 ){
393 builtinVtab_vtab *pNew;
394 int rc;
395
396 rc = sqlite3_declare_vtab(db,
397 "CREATE TABLE x(name,size,data)"
398 );
399 if( rc==SQLITE_OK ){
400 pNew = sqlite3_malloc( sizeof(*pNew) );
401 *ppVtab = (sqlite3_vtab*)pNew;
402 if( pNew==0 ) return SQLITE_NOMEM;
403 memset(pNew, 0, sizeof(*pNew));
404 }
405 return rc;
406 }
407
408 /*
409 ** This method is the destructor for builtinVtab_vtab objects.
410 */
411 static int builtinVtabDisconnect(sqlite3_vtab *pVtab){
412 builtinVtab_vtab *p = (builtinVtab_vtab*)pVtab;
413 sqlite3_free(p);
414 return SQLITE_OK;
415 }
416
417 /*
418 ** Constructor for a new builtinVtab_cursor object.
419 */
420 static int builtinVtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
421 builtinVtab_cursor *pCur;
422 pCur = sqlite3_malloc( sizeof(*pCur) );
423 if( pCur==0 ) return SQLITE_NOMEM;
424 memset(pCur, 0, sizeof(*pCur));
425 *ppCursor = &pCur->base;
426 return SQLITE_OK;
427 }
428
429 /*
430 ** Destructor for a builtinVtab_cursor.
431 */
432 static int builtinVtabClose(sqlite3_vtab_cursor *cur){
433 builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
434 sqlite3_free(pCur);
435 return SQLITE_OK;
436 }
437
438
439 /*
440 ** Advance a builtinVtab_cursor to its next row of output.
441 */
442 static int builtinVtabNext(sqlite3_vtab_cursor *cur){
443 builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
444 pCur->iRowid++;
445 return SQLITE_OK;
446 }
447
448 /*
449 ** Return values of columns for the row at which the builtinVtab_cursor
450 ** is currently pointing.
451 */
452 static int builtinVtabColumn(
453 sqlite3_vtab_cursor *cur, /* The cursor */
454 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
455 int i /* Which column to return */
456 ){
457 builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
458 const struct BuiltinFileTable *pFile = aBuiltinFiles + pCur->iRowid;
459 switch( i ){
460 case 0: /* name */
461 sqlite3_result_text(ctx, pFile->zName, -1, SQLITE_STATIC);
462 break;
463 case 1: /* size */
464 sqlite3_result_int(ctx, pFile->nByte);
465 break;
466 case 2: /* data */
467 sqlite3_result_blob(ctx, pFile->pData, pFile->nByte, SQLITE_STATIC);
468 break;
469 }
470 return SQLITE_OK;
471 }
472
473 /*
474 ** Return the rowid for the current row. In this implementation, the
475 ** rowid is the same as the output value.
476 */
477 static int builtinVtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
478 builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
479 *pRowid = pCur->iRowid;
480 return SQLITE_OK;
481 }
482
483 /*
484 ** Return TRUE if the cursor has been moved off of the last
485 ** row of output.
486 */
487 static int builtinVtabEof(sqlite3_vtab_cursor *cur){
488 builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
489 return pCur->iRowid>=count(aBuiltinFiles);
490 }
491
492 /*
493 ** This method is called to "rewind" the builtinVtab_cursor object back
494 ** to the first row of output. This method is always called at least
495 ** once prior to any call to builtinVtabColumn() or builtinVtabRowid() or
496 ** builtinVtabEof().
497 */
498 static int builtinVtabFilter(
499 sqlite3_vtab_cursor *pVtabCursor,
500 int idxNum, const char *idxStr,
501 int argc, sqlite3_value **argv
502 ){
503 builtinVtab_cursor *pCur = (builtinVtab_cursor *)pVtabCursor;
504 pCur->iRowid = 1;
505 return SQLITE_OK;
506 }
507
508 /*
509 ** SQLite will invoke this method one or more times while planning a query
510 ** that uses the virtual table. This routine needs to create
511 ** a query plan for each invocation and compute an estimated cost for that
512 ** plan.
513 */
514 static int builtinVtabBestIndex(
515 sqlite3_vtab *tab,
516 sqlite3_index_info *pIdxInfo
517 ){
518 pIdxInfo->estimatedCost = (double)count(aBuiltinFiles);
519 pIdxInfo->estimatedRows = count(aBuiltinFiles);
520 return SQLITE_OK;
521 }
522
523 /*
524 ** This following structure defines all the methods for the
525 ** virtual table.
526 */
527 static sqlite3_module builtinVtabModule = {
528 /* iVersion */ 0,
529 /* xCreate */ 0, /* The builtin vtab is eponymous and read-only */
530 /* xConnect */ builtinVtabConnect,
531 /* xBestIndex */ builtinVtabBestIndex,
532 /* xDisconnect */ builtinVtabDisconnect,
533 /* xDestroy */ 0,
534 /* xOpen */ builtinVtabOpen,
535 /* xClose */ builtinVtabClose,
536 /* xFilter */ builtinVtabFilter,
537 /* xNext */ builtinVtabNext,
538 /* xEof */ builtinVtabEof,
539 /* xColumn */ builtinVtabColumn,
540 /* xRowid */ builtinVtabRowid,
541 /* xUpdate */ 0,
542 /* xBegin */ 0,
543 /* xSync */ 0,
544 /* xCommit */ 0,
545 /* xRollback */ 0,
546 /* xFindMethod */ 0,
547 /* xRename */ 0,
548 /* xSavepoint */ 0,
549 /* xRelease */ 0,
550 /* xRollbackTo */ 0,
551 /* xShadowName */ 0
552 };
553
554
555 /*
556 ** Register the builtin virtual table
557 */
558 int builtin_vtab_register(sqlite3 *db){
559 int rc = sqlite3_create_module(db, "builtin", &builtinVtabModule, 0);
560 return rc;
561 }
562 /* End of the builtin virtual table
563 ******************************************************************************/
564
+2 -16
--- src/bundle.c
+++ src/bundle.c
@@ -716,11 +716,11 @@
716716
}
717717
db_end_transaction(0);
718718
}
719719
720720
/*
721
-** COMMAND: bundle
721
+** COMMAND: bundle*
722722
**
723723
** Usage: %fossil bundle SUBCOMMAND ARGS...
724724
**
725725
** > fossil bundle append BUNDLE FILE...
726726
**
@@ -768,25 +768,11 @@
768768
**
769769
** Remove from the repository all files that are used exclusively
770770
** by check-ins in BUNDLE. This has the effect of undoing a
771771
** "fossil bundle import".
772772
**
773
-** SUMMARY:
774
-** fossil bundle append BUNDLE FILE... Add files to BUNDLE
775
-** fossil bundle cat BUNDLE HASH... Extract file from BUNDLE
776
-** fossil bundle export BUNDLE ?OPTIONS? Create a new BUNDLE
777
-** --branch BRANCH --from TAG1 --to TAG2 Check-ins to include
778
-** --checkin TAG Use only check-in TAG
779
-** --standalone Omit dependencies
780
-** fossil bundle extend BUNDLE Update with newer content
781
-** fossil bundle import BUNDLE ?OPTIONS? Import a bundle
782
-** --publish Publish the import
783
-** --force Cross-repo import
784
-** fossil bundle ls BUNDLE List content of a bundle
785
-** fossil bundle purge BUNDLE Undo an import
786
-**
787
-** See also: publish
773
+** See also: [[publish]]
788774
*/
789775
void bundle_cmd(void){
790776
const char *zSubcmd;
791777
int n;
792778
if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?OPTIONS?");
793779
--- src/bundle.c
+++ src/bundle.c
@@ -716,11 +716,11 @@
716 }
717 db_end_transaction(0);
718 }
719
720 /*
721 ** COMMAND: bundle
722 **
723 ** Usage: %fossil bundle SUBCOMMAND ARGS...
724 **
725 ** > fossil bundle append BUNDLE FILE...
726 **
@@ -768,25 +768,11 @@
768 **
769 ** Remove from the repository all files that are used exclusively
770 ** by check-ins in BUNDLE. This has the effect of undoing a
771 ** "fossil bundle import".
772 **
773 ** SUMMARY:
774 ** fossil bundle append BUNDLE FILE... Add files to BUNDLE
775 ** fossil bundle cat BUNDLE HASH... Extract file from BUNDLE
776 ** fossil bundle export BUNDLE ?OPTIONS? Create a new BUNDLE
777 ** --branch BRANCH --from TAG1 --to TAG2 Check-ins to include
778 ** --checkin TAG Use only check-in TAG
779 ** --standalone Omit dependencies
780 ** fossil bundle extend BUNDLE Update with newer content
781 ** fossil bundle import BUNDLE ?OPTIONS? Import a bundle
782 ** --publish Publish the import
783 ** --force Cross-repo import
784 ** fossil bundle ls BUNDLE List content of a bundle
785 ** fossil bundle purge BUNDLE Undo an import
786 **
787 ** See also: publish
788 */
789 void bundle_cmd(void){
790 const char *zSubcmd;
791 int n;
792 if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?OPTIONS?");
793
--- src/bundle.c
+++ src/bundle.c
@@ -716,11 +716,11 @@
716 }
717 db_end_transaction(0);
718 }
719
720 /*
721 ** COMMAND: bundle*
722 **
723 ** Usage: %fossil bundle SUBCOMMAND ARGS...
724 **
725 ** > fossil bundle append BUNDLE FILE...
726 **
@@ -768,25 +768,11 @@
768 **
769 ** Remove from the repository all files that are used exclusively
770 ** by check-ins in BUNDLE. This has the effect of undoing a
771 ** "fossil bundle import".
772 **
773 ** See also: [[publish]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
774 */
775 void bundle_cmd(void){
776 const char *zSubcmd;
777 int n;
778 if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?OPTIONS?");
779
+8 -8
--- src/cgi.c
+++ src/cgi.c
@@ -303,24 +303,24 @@
303303
fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
304304
}else{
305305
assert( rangeEnd==0 );
306306
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
307307
}
308
- if( g.isConst ){
308
+ if( etag_tag()[0]!=0 ){
309
+ fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
310
+ fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
311
+ if( etag_mtime()>0 ){
312
+ fprintf(g.httpOut, "Last-Modified: %s\r\n",
313
+ cgi_rfc822_datestamp(etag_mtime()));
314
+ }
315
+ }else if( g.isConst ){
309316
/* isConst means that the reply is guaranteed to be invariant, even
310317
** after configuration changes and/or Fossil binary recompiles. */
311318
fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
312
- }else if( etag_tag()[0]!=0 ){
313
- fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
314
- fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
315319
}else{
316320
fprintf(g.httpOut, "Cache-control: no-cache\r\n");
317321
}
318
- if( etag_mtime()>0 ){
319
- fprintf(g.httpOut, "Last-Modified: %s\r\n",
320
- cgi_rfc822_datestamp(etag_mtime()));
321
- }
322322
323323
if( blob_size(&extraHeader)>0 ){
324324
fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
325325
}
326326
327327
--- src/cgi.c
+++ src/cgi.c
@@ -303,24 +303,24 @@
303 fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
304 }else{
305 assert( rangeEnd==0 );
306 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
307 }
308 if( g.isConst ){
 
 
 
 
 
 
 
309 /* isConst means that the reply is guaranteed to be invariant, even
310 ** after configuration changes and/or Fossil binary recompiles. */
311 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
312 }else if( etag_tag()[0]!=0 ){
313 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
314 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
315 }else{
316 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
317 }
318 if( etag_mtime()>0 ){
319 fprintf(g.httpOut, "Last-Modified: %s\r\n",
320 cgi_rfc822_datestamp(etag_mtime()));
321 }
322
323 if( blob_size(&extraHeader)>0 ){
324 fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
325 }
326
327
--- src/cgi.c
+++ src/cgi.c
@@ -303,24 +303,24 @@
303 fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
304 }else{
305 assert( rangeEnd==0 );
306 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
307 }
308 if( etag_tag()[0]!=0 ){
309 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
310 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
311 if( etag_mtime()>0 ){
312 fprintf(g.httpOut, "Last-Modified: %s\r\n",
313 cgi_rfc822_datestamp(etag_mtime()));
314 }
315 }else if( g.isConst ){
316 /* isConst means that the reply is guaranteed to be invariant, even
317 ** after configuration changes and/or Fossil binary recompiles. */
318 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
 
 
 
319 }else{
320 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
321 }
 
 
 
 
322
323 if( blob_size(&extraHeader)>0 ){
324 fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
325 }
326
327
+5 -5
--- src/checkin.c
+++ src/checkin.c
@@ -440,11 +440,11 @@
440440
** --extra Display unmanaged files.
441441
** --differ Display modified and extra files.
442442
** --merge Display merge contributors.
443443
** --no-merge Do not display merge contributors.
444444
**
445
-** See also: extras, ls
445
+** See also: [[extras]], [[ls]]
446446
*/
447447
void status_cmd(void){
448448
/* Affirmative and negative flag option tables. */
449449
static const struct {
450450
const char *option; /* Flag name. */
@@ -676,11 +676,11 @@
676676
** -v|--verbose Provide extra information about each file.
677677
** -t Sort output in time order.
678678
** -r VERSION The specific check-in to list.
679679
** -R|--repository FILE Extract info from repository FILE.
680680
**
681
-** See also: changes, extras, status
681
+** See also: [[changes]], [[extras]], [[status]]
682682
*/
683683
void ls_cmd(void){
684684
int vid;
685685
Stmt q;
686686
int verboseFlag;
@@ -830,11 +830,11 @@
830830
** --header Identify the repository if there are extras
831831
** --ignore CSG Ignore files matching patterns from the argument
832832
** --rel-paths Display pathnames relative to the current working
833833
** directory.
834834
**
835
-** See also: changes, clean, status
835
+** See also: [[changes]], [[clean]], [[status]]
836836
*/
837837
void extras_cmd(void){
838838
Blob report = BLOB_INITIALIZER;
839839
const char *zIgnoreFlag = find_option("ignore",0,1);
840840
unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
@@ -954,11 +954,11 @@
954954
** --no-prompt This option disables prompting the user for input
955955
** and assumes an answer of 'No' for every question.
956956
** --temp Remove only Fossil-generated temporary files.
957957
** -v|--verbose Show all files as they are removed.
958958
**
959
-** See also: addremove, extras, status
959
+** See also: [[addremove]], [[extras]], [[status]]
960960
*/
961961
void clean_cmd(void){
962962
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
963963
int emptyDirsFlag, dirsOnlyFlag;
964964
int disableUndo, noPrompt;
@@ -2091,11 +2091,11 @@
20912091
** year-month-day form, it may be truncated, the "T" may be replaced by
20922092
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
20932093
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
20942094
** means UTC.
20952095
**
2096
-** See also: branch, changes, checkout, extras, sync
2096
+** See also: [[branch]], [[changes]], [[update]], [[extras]], [[sync]]
20972097
*/
20982098
void commit_cmd(void){
20992099
int hasChanges; /* True if unsaved changes exist */
21002100
int vid; /* blob-id of parent version */
21012101
int nrid; /* blob-id of a modified file */
21022102
--- src/checkin.c
+++ src/checkin.c
@@ -440,11 +440,11 @@
440 ** --extra Display unmanaged files.
441 ** --differ Display modified and extra files.
442 ** --merge Display merge contributors.
443 ** --no-merge Do not display merge contributors.
444 **
445 ** See also: extras, ls
446 */
447 void status_cmd(void){
448 /* Affirmative and negative flag option tables. */
449 static const struct {
450 const char *option; /* Flag name. */
@@ -676,11 +676,11 @@
676 ** -v|--verbose Provide extra information about each file.
677 ** -t Sort output in time order.
678 ** -r VERSION The specific check-in to list.
679 ** -R|--repository FILE Extract info from repository FILE.
680 **
681 ** See also: changes, extras, status
682 */
683 void ls_cmd(void){
684 int vid;
685 Stmt q;
686 int verboseFlag;
@@ -830,11 +830,11 @@
830 ** --header Identify the repository if there are extras
831 ** --ignore CSG Ignore files matching patterns from the argument
832 ** --rel-paths Display pathnames relative to the current working
833 ** directory.
834 **
835 ** See also: changes, clean, status
836 */
837 void extras_cmd(void){
838 Blob report = BLOB_INITIALIZER;
839 const char *zIgnoreFlag = find_option("ignore",0,1);
840 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
@@ -954,11 +954,11 @@
954 ** --no-prompt This option disables prompting the user for input
955 ** and assumes an answer of 'No' for every question.
956 ** --temp Remove only Fossil-generated temporary files.
957 ** -v|--verbose Show all files as they are removed.
958 **
959 ** See also: addremove, extras, status
960 */
961 void clean_cmd(void){
962 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
963 int emptyDirsFlag, dirsOnlyFlag;
964 int disableUndo, noPrompt;
@@ -2091,11 +2091,11 @@
2091 ** year-month-day form, it may be truncated, the "T" may be replaced by
2092 ** a space, and it may also name a timezone offset from UTC as "-HH:MM"
2093 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
2094 ** means UTC.
2095 **
2096 ** See also: branch, changes, checkout, extras, sync
2097 */
2098 void commit_cmd(void){
2099 int hasChanges; /* True if unsaved changes exist */
2100 int vid; /* blob-id of parent version */
2101 int nrid; /* blob-id of a modified file */
2102
--- src/checkin.c
+++ src/checkin.c
@@ -440,11 +440,11 @@
440 ** --extra Display unmanaged files.
441 ** --differ Display modified and extra files.
442 ** --merge Display merge contributors.
443 ** --no-merge Do not display merge contributors.
444 **
445 ** See also: [[extras]], [[ls]]
446 */
447 void status_cmd(void){
448 /* Affirmative and negative flag option tables. */
449 static const struct {
450 const char *option; /* Flag name. */
@@ -676,11 +676,11 @@
676 ** -v|--verbose Provide extra information about each file.
677 ** -t Sort output in time order.
678 ** -r VERSION The specific check-in to list.
679 ** -R|--repository FILE Extract info from repository FILE.
680 **
681 ** See also: [[changes]], [[extras]], [[status]]
682 */
683 void ls_cmd(void){
684 int vid;
685 Stmt q;
686 int verboseFlag;
@@ -830,11 +830,11 @@
830 ** --header Identify the repository if there are extras
831 ** --ignore CSG Ignore files matching patterns from the argument
832 ** --rel-paths Display pathnames relative to the current working
833 ** directory.
834 **
835 ** See also: [[changes]], [[clean]], [[status]]
836 */
837 void extras_cmd(void){
838 Blob report = BLOB_INITIALIZER;
839 const char *zIgnoreFlag = find_option("ignore",0,1);
840 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
@@ -954,11 +954,11 @@
954 ** --no-prompt This option disables prompting the user for input
955 ** and assumes an answer of 'No' for every question.
956 ** --temp Remove only Fossil-generated temporary files.
957 ** -v|--verbose Show all files as they are removed.
958 **
959 ** See also: [[addremove]], [[extras]], [[status]]
960 */
961 void clean_cmd(void){
962 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
963 int emptyDirsFlag, dirsOnlyFlag;
964 int disableUndo, noPrompt;
@@ -2091,11 +2091,11 @@
2091 ** year-month-day form, it may be truncated, the "T" may be replaced by
2092 ** a space, and it may also name a timezone offset from UTC as "-HH:MM"
2093 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
2094 ** means UTC.
2095 **
2096 ** See also: [[branch]], [[changes]], [[update]], [[extras]], [[sync]]
2097 */
2098 void commit_cmd(void){
2099 int hasChanges; /* True if unsaved changes exist */
2100 int vid; /* blob-id of parent version */
2101 int nrid; /* blob-id of a modified file */
2102
+3 -3
--- src/checkout.c
+++ src/checkout.c
@@ -279,11 +279,11 @@
279279
** --force-missing Force checkout even if content is missing
280280
** --setmtime Set timestamps of all files to match their SCM-side
281281
** times (the timestamp of the last checkin which modified
282282
** them).
283283
**
284
-** See also: update
284
+** See also: [[update]]
285285
*/
286286
void checkout_cmd(void){
287287
int forceFlag; /* Force checkout even if edits exist */
288288
int forceMissingFlag; /* Force checkout even if missing content */
289289
int keepFlag; /* Do not change any files on disk */
@@ -387,18 +387,18 @@
387387
/*
388388
** COMMAND: close*
389389
**
390390
** Usage: %fossil close ?OPTIONS?
391391
**
392
-** The opposite of "open". Close the current database connection.
392
+** The opposite of "[[open]]". Close the current database connection.
393393
** Require a -f or --force flag if there are unsaved changes in the
394394
** current check-out or if there is non-empty stash.
395395
**
396396
** Options:
397397
** --force|-f necessary to close a check out with uncommitted changes
398398
**
399
-** See also: open
399
+** See also: [[open]]
400400
*/
401401
void close_cmd(void){
402402
int forceFlag = find_option("force","f",0)!=0;
403403
db_must_be_within_tree();
404404
405405
--- src/checkout.c
+++ src/checkout.c
@@ -279,11 +279,11 @@
279 ** --force-missing Force checkout even if content is missing
280 ** --setmtime Set timestamps of all files to match their SCM-side
281 ** times (the timestamp of the last checkin which modified
282 ** them).
283 **
284 ** See also: update
285 */
286 void checkout_cmd(void){
287 int forceFlag; /* Force checkout even if edits exist */
288 int forceMissingFlag; /* Force checkout even if missing content */
289 int keepFlag; /* Do not change any files on disk */
@@ -387,18 +387,18 @@
387 /*
388 ** COMMAND: close*
389 **
390 ** Usage: %fossil close ?OPTIONS?
391 **
392 ** The opposite of "open". Close the current database connection.
393 ** Require a -f or --force flag if there are unsaved changes in the
394 ** current check-out or if there is non-empty stash.
395 **
396 ** Options:
397 ** --force|-f necessary to close a check out with uncommitted changes
398 **
399 ** See also: open
400 */
401 void close_cmd(void){
402 int forceFlag = find_option("force","f",0)!=0;
403 db_must_be_within_tree();
404
405
--- src/checkout.c
+++ src/checkout.c
@@ -279,11 +279,11 @@
279 ** --force-missing Force checkout even if content is missing
280 ** --setmtime Set timestamps of all files to match their SCM-side
281 ** times (the timestamp of the last checkin which modified
282 ** them).
283 **
284 ** See also: [[update]]
285 */
286 void checkout_cmd(void){
287 int forceFlag; /* Force checkout even if edits exist */
288 int forceMissingFlag; /* Force checkout even if missing content */
289 int keepFlag; /* Do not change any files on disk */
@@ -387,18 +387,18 @@
387 /*
388 ** COMMAND: close*
389 **
390 ** Usage: %fossil close ?OPTIONS?
391 **
392 ** The opposite of "[[open]]". Close the current database connection.
393 ** Require a -f or --force flag if there are unsaved changes in the
394 ** current check-out or if there is non-empty stash.
395 **
396 ** Options:
397 ** --force|-f necessary to close a check out with uncommitted changes
398 **
399 ** See also: [[open]]
400 */
401 void close_cmd(void){
402 int forceFlag = find_option("force","f",0)!=0;
403 db_must_be_within_tree();
404
405
+9 -7
--- src/clone.c
+++ src/clone.c
@@ -83,13 +83,11 @@
8383
** COMMAND: clone
8484
**
8585
** Usage: %fossil clone ?OPTIONS? URI FILENAME
8686
**
8787
** Make a clone of a repository specified by URI in the local
88
-** file named FILENAME.
89
-**
90
-** URI may be one of the following forms:
88
+** file named FILENAME. URI may be one of the following forms:
9189
** ([...] denotes optional elements):
9290
**
9391
** * HTTP/HTTPS protocol:
9492
**
9593
** http[s]://[userid[:password]@]host[:port][/path]
@@ -100,18 +98,22 @@
10098
**
10199
** * Filesystem:
102100
**
103101
** [file://]path/to/repo.fossil
104102
**
105
-** Note 1: For ssh and filesystem, path must have an extra leading
103
+** Note that in Fossil (in contrast to some other DVCSes) a repository
104
+** is distinct from a checkout. This command create a clone of a repository.
105
+** Use the separate [[open]] command to open a checkout from that repository.
106
+**
107
+** For ssh and filesystem, path must have an extra leading
106108
** '/' to use an absolute path.
107109
**
108
-** Note 2: Use %HH escapes for special characters in the userid and
110
+** Use %HH escapes for special characters in the userid and
109111
** password. For example "%40" in place of "@", "%2f" in place
110112
** of "/", and "%3a" in place of ":".
111113
**
112
-** By default, your current login name is used to create the default
114
+** By default, the current login name is used to create the default
113115
** admin user. This can be overridden using the -A|--admin-user
114116
** parameter.
115117
**
116118
** Options:
117119
** --admin-user|-A USERNAME Make USERNAME the administrator
@@ -123,11 +125,11 @@
123125
** --ssh-command|-c SSH Use SSH as the "ssh" command
124126
** --ssl-identity FILENAME Use the SSL identity if requested by the server
125127
** -u|--unversioned Also sync unversioned content
126128
** -v|--verbose Show more statistics in output
127129
**
128
-** See also: init
130
+** See also: [[init]], [[open]]
129131
*/
130132
void clone_cmd(void){
131133
char *zPassword;
132134
const char *zDefaultUser; /* Optional name of the default user */
133135
const char *zHttpAuth; /* HTTP Authorization user:pass information */
134136
--- src/clone.c
+++ src/clone.c
@@ -83,13 +83,11 @@
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URI FILENAME
86 **
87 ** Make a clone of a repository specified by URI in the local
88 ** file named FILENAME.
89 **
90 ** URI may be one of the following forms:
91 ** ([...] denotes optional elements):
92 **
93 ** * HTTP/HTTPS protocol:
94 **
95 ** http[s]://[userid[:password]@]host[:port][/path]
@@ -100,18 +98,22 @@
100 **
101 ** * Filesystem:
102 **
103 ** [file://]path/to/repo.fossil
104 **
105 ** Note 1: For ssh and filesystem, path must have an extra leading
 
 
 
 
106 ** '/' to use an absolute path.
107 **
108 ** Note 2: Use %HH escapes for special characters in the userid and
109 ** password. For example "%40" in place of "@", "%2f" in place
110 ** of "/", and "%3a" in place of ":".
111 **
112 ** By default, your current login name is used to create the default
113 ** admin user. This can be overridden using the -A|--admin-user
114 ** parameter.
115 **
116 ** Options:
117 ** --admin-user|-A USERNAME Make USERNAME the administrator
@@ -123,11 +125,11 @@
123 ** --ssh-command|-c SSH Use SSH as the "ssh" command
124 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
125 ** -u|--unversioned Also sync unversioned content
126 ** -v|--verbose Show more statistics in output
127 **
128 ** See also: init
129 */
130 void clone_cmd(void){
131 char *zPassword;
132 const char *zDefaultUser; /* Optional name of the default user */
133 const char *zHttpAuth; /* HTTP Authorization user:pass information */
134
--- src/clone.c
+++ src/clone.c
@@ -83,13 +83,11 @@
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URI FILENAME
86 **
87 ** Make a clone of a repository specified by URI in the local
88 ** file named FILENAME. URI may be one of the following forms:
 
 
89 ** ([...] denotes optional elements):
90 **
91 ** * HTTP/HTTPS protocol:
92 **
93 ** http[s]://[userid[:password]@]host[:port][/path]
@@ -100,18 +98,22 @@
98 **
99 ** * Filesystem:
100 **
101 ** [file://]path/to/repo.fossil
102 **
103 ** Note that in Fossil (in contrast to some other DVCSes) a repository
104 ** is distinct from a checkout. This command create a clone of a repository.
105 ** Use the separate [[open]] command to open a checkout from that repository.
106 **
107 ** For ssh and filesystem, path must have an extra leading
108 ** '/' to use an absolute path.
109 **
110 ** Use %HH escapes for special characters in the userid and
111 ** password. For example "%40" in place of "@", "%2f" in place
112 ** of "/", and "%3a" in place of ":".
113 **
114 ** By default, the current login name is used to create the default
115 ** admin user. This can be overridden using the -A|--admin-user
116 ** parameter.
117 **
118 ** Options:
119 ** --admin-user|-A USERNAME Make USERNAME the administrator
@@ -123,11 +125,11 @@
125 ** --ssh-command|-c SSH Use SSH as the "ssh" command
126 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
127 ** -u|--unversioned Also sync unversioned content
128 ** -v|--verbose Show more statistics in output
129 **
130 ** See also: [[init]], [[open]]
131 */
132 void clone_cmd(void){
133 char *zPassword;
134 const char *zDefaultUser; /* Optional name of the default user */
135 const char *zHttpAuth; /* HTTP Authorization user:pass information */
136
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -407,11 +407,10 @@
407407
{ "smtp_send_line", 2, FMT_SAFE },
408408
{ "smtp_server_send", 2, FMT_SAFE },
409409
{ "socket_set_errmsg", 1, FMT_SAFE },
410410
{ "ssl_set_errmsg", 1, FMT_SAFE },
411411
{ "style_header", 1, FMT_HTML },
412
- { "style_js_onload", 1, FMT_HTML },
413412
{ "style_set_current_page", 1, FMT_URL },
414413
{ "style_submenu_element", 2, FMT_URL },
415414
{ "style_submenu_sql", 3, FMT_SQL },
416415
{ "webpage_error", 1, FMT_SAFE },
417416
{ "xhref", 2, FMT_URL },
418417
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -407,11 +407,10 @@
407 { "smtp_send_line", 2, FMT_SAFE },
408 { "smtp_server_send", 2, FMT_SAFE },
409 { "socket_set_errmsg", 1, FMT_SAFE },
410 { "ssl_set_errmsg", 1, FMT_SAFE },
411 { "style_header", 1, FMT_HTML },
412 { "style_js_onload", 1, FMT_HTML },
413 { "style_set_current_page", 1, FMT_URL },
414 { "style_submenu_element", 2, FMT_URL },
415 { "style_submenu_sql", 3, FMT_SQL },
416 { "webpage_error", 1, FMT_SAFE },
417 { "xhref", 2, FMT_URL },
418
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -407,11 +407,10 @@
407 { "smtp_send_line", 2, FMT_SAFE },
408 { "smtp_server_send", 2, FMT_SAFE },
409 { "socket_set_errmsg", 1, FMT_SAFE },
410 { "ssl_set_errmsg", 1, FMT_SAFE },
411 { "style_header", 1, FMT_HTML },
 
412 { "style_set_current_page", 1, FMT_URL },
413 { "style_submenu_element", 2, FMT_URL },
414 { "style_submenu_sql", 3, FMT_SQL },
415 { "webpage_error", 1, FMT_SAFE },
416 { "xhref", 2, FMT_URL },
417
+4 -1
--- src/configure.c
+++ src/configure.c
@@ -94,10 +94,12 @@
9494
{ "js", CONFIGSET_SKIN },
9595
{ "logo-mimetype", CONFIGSET_SKIN },
9696
{ "logo-image", CONFIGSET_SKIN },
9797
{ "background-mimetype", CONFIGSET_SKIN },
9898
{ "background-image", CONFIGSET_SKIN },
99
+ { "icon-mimetype", CONFIGSET_SKIN },
100
+ { "icon-image", CONFIGSET_SKIN },
99101
{ "timeline-block-markup", CONFIGSET_SKIN },
100102
{ "timeline-date-format", CONFIGSET_SKIN },
101103
{ "timeline-default-style", CONFIGSET_SKIN },
102104
{ "timeline-dwelltime", CONFIGSET_SKIN },
103105
{ "timeline-closetime", CONFIGSET_SKIN },
@@ -112,10 +114,11 @@
112114
{ "default-csp", CONFIGSET_SKIN },
113115
{ "sitemap-docidx", CONFIGSET_SKIN },
114116
{ "sitemap-download", CONFIGSET_SKIN },
115117
{ "sitemap-license", CONFIGSET_SKIN },
116118
{ "sitemap-contact", CONFIGSET_SKIN },
119
+ { "safe-html", CONFIGSET_SKIN },
117120
118121
#ifdef FOSSIL_ENABLE_TH1_DOCS
119122
{ "th1-docs", CONFIGSET_TH1 },
120123
#endif
121124
#ifdef FOSSIL_ENABLE_TH1_HOOKS
@@ -744,11 +747,11 @@
744747
** the remote repository at URL.
745748
**
746749
** Options:
747750
** -R|--repository FILE Extract info from repository FILE
748751
**
749
-** See also: settings, unset
752
+** See also: [[settings]], [[unset]]
750753
*/
751754
void configuration_cmd(void){
752755
int n;
753756
const char *zMethod;
754757
db_find_and_open_repository(0, 0);
755758
--- src/configure.c
+++ src/configure.c
@@ -94,10 +94,12 @@
94 { "js", CONFIGSET_SKIN },
95 { "logo-mimetype", CONFIGSET_SKIN },
96 { "logo-image", CONFIGSET_SKIN },
97 { "background-mimetype", CONFIGSET_SKIN },
98 { "background-image", CONFIGSET_SKIN },
 
 
99 { "timeline-block-markup", CONFIGSET_SKIN },
100 { "timeline-date-format", CONFIGSET_SKIN },
101 { "timeline-default-style", CONFIGSET_SKIN },
102 { "timeline-dwelltime", CONFIGSET_SKIN },
103 { "timeline-closetime", CONFIGSET_SKIN },
@@ -112,10 +114,11 @@
112 { "default-csp", CONFIGSET_SKIN },
113 { "sitemap-docidx", CONFIGSET_SKIN },
114 { "sitemap-download", CONFIGSET_SKIN },
115 { "sitemap-license", CONFIGSET_SKIN },
116 { "sitemap-contact", CONFIGSET_SKIN },
 
117
118 #ifdef FOSSIL_ENABLE_TH1_DOCS
119 { "th1-docs", CONFIGSET_TH1 },
120 #endif
121 #ifdef FOSSIL_ENABLE_TH1_HOOKS
@@ -744,11 +747,11 @@
744 ** the remote repository at URL.
745 **
746 ** Options:
747 ** -R|--repository FILE Extract info from repository FILE
748 **
749 ** See also: settings, unset
750 */
751 void configuration_cmd(void){
752 int n;
753 const char *zMethod;
754 db_find_and_open_repository(0, 0);
755
--- src/configure.c
+++ src/configure.c
@@ -94,10 +94,12 @@
94 { "js", CONFIGSET_SKIN },
95 { "logo-mimetype", CONFIGSET_SKIN },
96 { "logo-image", CONFIGSET_SKIN },
97 { "background-mimetype", CONFIGSET_SKIN },
98 { "background-image", CONFIGSET_SKIN },
99 { "icon-mimetype", CONFIGSET_SKIN },
100 { "icon-image", CONFIGSET_SKIN },
101 { "timeline-block-markup", CONFIGSET_SKIN },
102 { "timeline-date-format", CONFIGSET_SKIN },
103 { "timeline-default-style", CONFIGSET_SKIN },
104 { "timeline-dwelltime", CONFIGSET_SKIN },
105 { "timeline-closetime", CONFIGSET_SKIN },
@@ -112,10 +114,11 @@
114 { "default-csp", CONFIGSET_SKIN },
115 { "sitemap-docidx", CONFIGSET_SKIN },
116 { "sitemap-download", CONFIGSET_SKIN },
117 { "sitemap-license", CONFIGSET_SKIN },
118 { "sitemap-contact", CONFIGSET_SKIN },
119 { "safe-html", CONFIGSET_SKIN },
120
121 #ifdef FOSSIL_ENABLE_TH1_DOCS
122 { "th1-docs", CONFIGSET_TH1 },
123 #endif
124 #ifdef FOSSIL_ENABLE_TH1_HOOKS
@@ -744,11 +747,11 @@
747 ** the remote repository at URL.
748 **
749 ** Options:
750 ** -R|--repository FILE Extract info from repository FILE
751 **
752 ** See also: [[settings]], [[unset]]
753 */
754 void configuration_cmd(void){
755 int n;
756 const char *zMethod;
757 db_find_and_open_repository(0, 0);
758
+1 -1
--- src/content.c
+++ src/content.c
@@ -326,11 +326,11 @@
326326
** the named output file.
327327
**
328328
** Options:
329329
** -R|--repository FILE Extract artifacts from repository FILE
330330
**
331
-** See also: finfo
331
+** See also: [[finfo]]
332332
*/
333333
void artifact_cmd(void){
334334
int rid;
335335
Blob content;
336336
const char *zFile;
337337
--- src/content.c
+++ src/content.c
@@ -326,11 +326,11 @@
326 ** the named output file.
327 **
328 ** Options:
329 ** -R|--repository FILE Extract artifacts from repository FILE
330 **
331 ** See also: finfo
332 */
333 void artifact_cmd(void){
334 int rid;
335 Blob content;
336 const char *zFile;
337
--- src/content.c
+++ src/content.c
@@ -326,11 +326,11 @@
326 ** the named output file.
327 **
328 ** Options:
329 ** -R|--repository FILE Extract artifacts from repository FILE
330 **
331 ** See also: [[finfo]]
332 */
333 void artifact_cmd(void){
334 int rid;
335 Blob content;
336 const char *zFile;
337
+131 -19
--- src/db.c
+++ src/db.c
@@ -116,10 +116,11 @@
116116
*/
117117
static struct DbLocalData {
118118
int nBegin; /* Nesting depth of BEGIN */
119119
int doRollback; /* True to force a rollback */
120120
int nCommitHook; /* Number of commit hooks */
121
+ int wrTxn; /* Outer-most TNX is a write */
121122
Stmt *pAllStmt; /* List of all unfinalized statements */
122123
int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
123124
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
124125
struct sCommitHook {
125126
int (*xHook)(void); /* Functions to call at db_end_transaction() */
@@ -195,10 +196,11 @@
195196
sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
196197
db.nPriorChanges = sqlite3_total_changes(g.db);
197198
db.doRollback = 0;
198199
db.zStartFile = zStartFile;
199200
db.iStartLine = iStartLine;
201
+ db.wrTxn = 0;
200202
}
201203
db.nBegin++;
202204
}
203205
/*
204206
** Begin a new transaction for writing.
@@ -209,11 +211,12 @@
209211
sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
210212
db.nPriorChanges = sqlite3_total_changes(g.db);
211213
db.doRollback = 0;
212214
db.zStartFile = zStartFile;
213215
db.iStartLine = iStartLine;
214
- }else{
216
+ db.wrTxn = 1;
217
+ }else if( !db.wrTxn ){
215218
fossil_warning("read txn at %s:%d might cause SQLITE_BUSY "
216219
"for the write txn at %s:%d",
217220
db.zStartFile, db.iStartLine, zStartFile, iStartLine);
218221
}
219222
db.nBegin++;
@@ -1328,11 +1331,11 @@
13281331
);
13291332
if( rc!=SQLITE_OK ){
13301333
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
13311334
}
13321335
db_maybe_set_encryption_key(db, zDbName);
1333
- sqlite3_busy_timeout(db, 5000);
1336
+ sqlite3_busy_timeout(db, 15000);
13341337
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
13351338
sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
13361339
sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
13371340
sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
13381341
sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
@@ -1344,11 +1347,11 @@
13441347
);
13451348
if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
13461349
db_add_aux_functions(db);
13471350
re_add_sql_func(db); /* The REGEXP operator */
13481351
foci_register(db); /* The "files_of_checkin" virtual table */
1349
- sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1352
+ sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc);
13501353
return db;
13511354
}
13521355
13531356
13541357
/*
@@ -1714,16 +1717,20 @@
17141717
**
17151718
** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
17161719
** try again. Once the file is found, the g.zLocalRoot variable is set
17171720
** to the root of the repository tree and this routine returns 1. If
17181721
** no database is found, then this routine return 0.
1722
+**
1723
+** In db_open_local_v2(), if the bRootOnly flag is true, then only
1724
+** look in the CWD for the checkout database. Do not scan upwards in
1725
+** the file hierarchy.
17191726
**
17201727
** This routine always opens the user database regardless of whether or
17211728
** not the repository database is found. If the _FOSSIL_ or .fslckout file
17221729
** is found, it is attached to the open database connection too.
17231730
*/
1724
-int db_open_local(const char *zDbName){
1731
+int db_open_local_v2(const char *zDbName, int bRootOnly){
17251732
int i, n;
17261733
char zPwd[2000];
17271734
static const char *(aDbName[]) = { "_FOSSIL_", ".fslckout", ".fos" };
17281735
17291736
if( g.localOpen ) return 1;
@@ -1747,18 +1754,22 @@
17471754
g.localOpen = 1;
17481755
db_open_repository(zDbName);
17491756
return 1;
17501757
}
17511758
}
1759
+ if( bRootOnly ) break;
17521760
n--;
17531761
while( n>1 && zPwd[n]!='/' ){ n--; }
17541762
while( n>1 && zPwd[n-1]=='/' ){ n--; }
17551763
zPwd[n] = 0;
17561764
}
17571765
17581766
/* A checkout database file could not be found */
17591767
return 0;
1768
+}
1769
+int db_open_local(const char *zDbName){
1770
+ return db_open_local_v2(zDbName, 0);
17601771
}
17611772
17621773
/*
17631774
** Get the full pathname to the repository database file. The
17641775
** local database (the _FOSSIL_ or .fslckout database) must have already
@@ -2388,11 +2399,11 @@
23882399
** year-month-day form, it may be truncated, the "T" may be replaced by
23892400
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
23902401
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
23912402
** means UTC.
23922403
**
2393
-** See also: clone
2404
+** See also: [[clone]]
23942405
*/
23952406
void create_repository_cmd(void){
23962407
char *zPassword;
23972408
const char *zTemplate; /* Repository from which to copy settings */
23982409
const char *zDate; /* Date of the initial check-in */
@@ -3070,57 +3081,158 @@
30703081
}
30713082
30723083
/*
30733084
** COMMAND: open
30743085
**
3075
-** Usage: %fossil open FILENAME ?VERSION? ?OPTIONS?
3086
+** Usage: %fossil open REPOSITORY ?VERSION? ?OPTIONS?
3087
+**
3088
+** Open a new connection to the repository name REPOSITORY. A checkout
3089
+** for the repository is created with its root at the current working
3090
+** directory, or in DIR if the "--workdir DIR" is used. If VERSION is
3091
+** specified then that version is checked out. Otherwise the most recent
3092
+** check-in on the main branch (usually "trunk") is used.
3093
+**
3094
+** REPOSITORY can be the filename for a repository that already exists on the
3095
+** local machine or it can be a URI for a remote repository. If REPOSITORY
3096
+** is a URI in one of the formats recognized by the [[clone]] command, then
3097
+** remote repo is first cloned, then the clone is opened. The clone will be
3098
+** stored in the current directory, or in DIR if the "--repodir DIR" option
3099
+** is used. The name of the clone will be taken from the last term of the URI.
3100
+** For "http:" and "https:" URIs, you can append an extra term to the end of
3101
+** the URI to get any repository name you like. For example:
3102
+**
3103
+** fossil open https://fossil-scm.org/home/new-name
30763104
**
3077
-** Open a connection to the local repository in FILENAME. A checkout
3078
-** for the repository is created with its root at the working directory.
3079
-** If VERSION is specified then that version is checked out. Otherwise
3080
-** the latest version is checked out. No files other than "manifest"
3081
-** and "manifest.uuid" are modified if the --keep option is present.
3105
+** The base URI for cloning is "https://fossil-scm.org/home". The extra
3106
+** "new-name" term means that the cloned repository will be called
3107
+** "new-name.fossil".
30823108
**
30833109
** Options:
30843110
** --empty Initialize checkout as being empty, but still connected
30853111
** with the local repository. If you commit this checkout,
30863112
** it will become a new "initial" commit in the repository.
3113
+** --force Continue with the open even if the working directory is
3114
+** not empty.
3115
+** --force-missing Force opening a repository with missing content
30873116
** --keep Only modify the manifest and manifest.uuid files
30883117
** --nested Allow opening a repository inside an opened checkout
3089
-** --force-missing Force opening a repository with missing content
3118
+** --repodir DIR If REPOSITORY is a URI that will be cloned, store
3119
+** the clone in DIR rather than in "."
30903120
** --setmtime Set timestamps of all files to match their SCM-side
30913121
** times (the timestamp of the last checkin which modified
30923122
** them).
3123
+** --workdir DIR Use DIR as the working directory instead of ".". The DIR
3124
+** directory is created if it does not exist.
30933125
**
3094
-** See also: close
3126
+** See also: [[close]], [[clone]]
30953127
*/
30963128
void cmd_open(void){
30973129
int emptyFlag;
30983130
int keepFlag;
30993131
int forceMissingFlag;
31003132
int allowNested;
31013133
int allowSymlinks;
31023134
int setmtimeFlag; /* --setmtime. Set mtimes on files */
3135
+ int bForce = 0; /* --force. Open even if non-empty dir */
31033136
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3137
+ const char *zWorkDir; /* --workdir value */
3138
+ const char *zRepo = 0; /* Name of the repository file */
3139
+ const char *zRepoDir = 0; /* --repodir value */
3140
+ char *zPwd; /* Initial working directory */
3141
+ int isUri = 0; /* True if REPOSITORY is a URI */
31043142
31053143
url_proxy_options();
31063144
emptyFlag = find_option("empty",0,0)!=0;
31073145
keepFlag = find_option("keep",0,0)!=0;
31083146
forceMissingFlag = find_option("force-missing",0,0)!=0;
31093147
allowNested = find_option("nested",0,0)!=0;
31103148
setmtimeFlag = find_option("setmtime",0,0)!=0;
3149
+ zWorkDir = find_option("workdir",0,1);
3150
+ zRepoDir = find_option("repodir",0,1);
3151
+ bForce = find_option("force",0,0)!=0;
3152
+ zPwd = file_getcwd(0,0);
3153
+
31113154
31123155
/* We should be done with options.. */
31133156
verify_all_options();
31143157
31153158
if( g.argc!=3 && g.argc!=4 ){
31163159
usage("REPOSITORY-FILENAME ?VERSION?");
31173160
}
3118
- if( !allowNested && db_open_local(0) ){
3119
- fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot);
3161
+ zRepo = g.argv[2];
3162
+ if( sqlite3_strglob("http://*", zRepo)==0
3163
+ || sqlite3_strglob("https://*", zRepo)==0
3164
+ || sqlite3_strglob("ssh:*", zRepo)==0
3165
+ || sqlite3_strglob("file:*", zRepo)==0
3166
+ ){
3167
+ isUri = 1;
3168
+ }
3169
+
3170
+ /* If --workdir is specified, change to the requested working directory */
3171
+ if( zWorkDir ){
3172
+ if( !isUri ){
3173
+ zRepo = file_canonical_name_dup(zRepo);
3174
+ }
3175
+ if( zRepoDir ){
3176
+ zRepoDir = file_canonical_name_dup(zRepoDir);
3177
+ }
3178
+ if( file_isdir(zWorkDir, ExtFILE)!=1 ){
3179
+ file_mkfolder(zWorkDir, ExtFILE, 0, 0);
3180
+ if( file_mkdir(zWorkDir, ExtFILE, 0) ){
3181
+ fossil_fatal("cannot create directory %s", zWorkDir);
3182
+ }
3183
+ }
3184
+ if( file_chdir(zWorkDir, 0) ){
3185
+ fossil_fatal("unable to make %s the working directory", zWorkDir);
3186
+ }
3187
+ }
3188
+ if( keepFlag==0 && bForce==0 && file_directory_size(".", 0, 1)>0 ){
3189
+ fossil_fatal("directory %s is not empty\n"
3190
+ "use the --force option to override", file_getcwd(0,0));
3191
+ }
3192
+
3193
+ if( db_open_local_v2(0, allowNested) ){
3194
+ fossil_fatal("there is already an open tree at %s", g.zLocalRoot);
3195
+ }
3196
+
3197
+ /* If REPOSITORY looks like a URI, then try to clone it first */
3198
+ if( isUri ){
3199
+ char *zNewBase; /* Base name of the cloned repository file */
3200
+ const char *zUri; /* URI to clone */
3201
+ int i; /* Loop counter */
3202
+ int rc; /* Result code from fossil_system() */
3203
+ Blob cmd; /* Clone command to be run */
3204
+ char *zCmd; /* String version of the clone command */
3205
+
3206
+ zUri = zRepo;
3207
+ zNewBase = fossil_strdup(file_tail(zUri));
3208
+ for(i=(int)strlen(zNewBase)-1; i>1 && zNewBase[i]!='.'; i--){}
3209
+ if( zNewBase[i]=='.' ) zNewBase[i] = 0;
3210
+ if( zRepoDir==0 ) zRepoDir = zPwd;
3211
+ zRepo = mprintf("%s/%s.fossil", zRepoDir, zNewBase);
3212
+ fossil_free(zNewBase);
3213
+ blob_init(&cmd, 0, 0);
3214
+ blob_append_escaped_arg(&cmd, g.nameOfExe);
3215
+ blob_append(&cmd, " clone", -1);
3216
+ blob_append_escaped_arg(&cmd, zUri);
3217
+ blob_append_escaped_arg(&cmd, zRepo);
3218
+ zCmd = blob_str(&cmd);
3219
+ fossil_print("%s\n", zCmd);
3220
+ if( zWorkDir ) file_chdir(zPwd, 0);
3221
+ rc = fossil_system(zCmd);
3222
+ if( rc ){
3223
+ fossil_fatal("clone of %s failed", zUri);
3224
+ }
3225
+ blob_reset(&cmd);
3226
+ if( zWorkDir ) file_chdir(zWorkDir, 0);
3227
+ }else if( zRepoDir ){
3228
+ fossil_fatal("the --repodir option only makes sense if the REPOSITORY "
3229
+ "argument is a URI that begins with http:, https:, ssh:, "
3230
+ "or file:");
31203231
}
3121
- db_open_repository(g.argv[2]);
3232
+
3233
+ db_open_repository(zRepo);
31223234
31233235
/* Figure out which revision to open. */
31243236
if( !emptyFlag ){
31253237
if( g.argc==4 ){
31263238
g.zOpenRevision = g.argv[3];
@@ -3169,12 +3281,12 @@
31693281
** point, this will probably be the setting value from the
31703282
** repository or global configuration databases. */
31713283
g.allowSymlinks = db_get_boolean("allow-symlinks",
31723284
db_allow_symlinks_by_default());
31733285
}
3174
- db_lset("repository", g.argv[2]);
3175
- db_record_repository_filename(g.argv[2]);
3286
+ db_lset("repository", zRepo);
3287
+ db_record_repository_filename(zRepo);
31763288
db_set_checkout(0);
31773289
azNewArgv[0] = g.argv[0];
31783290
g.argv = azNewArgv;
31793291
if( !emptyFlag ){
31803292
g.argc = 3;
@@ -3887,11 +3999,11 @@
38873999
** --global set or unset the given property globally instead of
38884000
** setting or unsetting it for the open repository only.
38894001
**
38904002
** --exact only consider exact name matches.
38914003
**
3892
-** See also: configuration
4004
+** See also: [[configuration]]
38934005
*/
38944006
void setting_cmd(void){
38954007
int i;
38964008
int globalFlag = find_option("global","g",0)!=0;
38974009
int exactFlag = find_option("exact",0,0)!=0;
38984010
--- src/db.c
+++ src/db.c
@@ -116,10 +116,11 @@
116 */
117 static struct DbLocalData {
118 int nBegin; /* Nesting depth of BEGIN */
119 int doRollback; /* True to force a rollback */
120 int nCommitHook; /* Number of commit hooks */
 
121 Stmt *pAllStmt; /* List of all unfinalized statements */
122 int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
123 int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
124 struct sCommitHook {
125 int (*xHook)(void); /* Functions to call at db_end_transaction() */
@@ -195,10 +196,11 @@
195 sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
196 db.nPriorChanges = sqlite3_total_changes(g.db);
197 db.doRollback = 0;
198 db.zStartFile = zStartFile;
199 db.iStartLine = iStartLine;
 
200 }
201 db.nBegin++;
202 }
203 /*
204 ** Begin a new transaction for writing.
@@ -209,11 +211,12 @@
209 sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
210 db.nPriorChanges = sqlite3_total_changes(g.db);
211 db.doRollback = 0;
212 db.zStartFile = zStartFile;
213 db.iStartLine = iStartLine;
214 }else{
 
215 fossil_warning("read txn at %s:%d might cause SQLITE_BUSY "
216 "for the write txn at %s:%d",
217 db.zStartFile, db.iStartLine, zStartFile, iStartLine);
218 }
219 db.nBegin++;
@@ -1328,11 +1331,11 @@
1328 );
1329 if( rc!=SQLITE_OK ){
1330 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
1331 }
1332 db_maybe_set_encryption_key(db, zDbName);
1333 sqlite3_busy_timeout(db, 5000);
1334 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
1335 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
1336 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
1337 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
1338 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
@@ -1344,11 +1347,11 @@
1344 );
1345 if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
1346 db_add_aux_functions(db);
1347 re_add_sql_func(db); /* The REGEXP operator */
1348 foci_register(db); /* The "files_of_checkin" virtual table */
1349 sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1350 return db;
1351 }
1352
1353
1354 /*
@@ -1714,16 +1717,20 @@
1714 **
1715 ** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
1716 ** try again. Once the file is found, the g.zLocalRoot variable is set
1717 ** to the root of the repository tree and this routine returns 1. If
1718 ** no database is found, then this routine return 0.
 
 
 
 
1719 **
1720 ** This routine always opens the user database regardless of whether or
1721 ** not the repository database is found. If the _FOSSIL_ or .fslckout file
1722 ** is found, it is attached to the open database connection too.
1723 */
1724 int db_open_local(const char *zDbName){
1725 int i, n;
1726 char zPwd[2000];
1727 static const char *(aDbName[]) = { "_FOSSIL_", ".fslckout", ".fos" };
1728
1729 if( g.localOpen ) return 1;
@@ -1747,18 +1754,22 @@
1747 g.localOpen = 1;
1748 db_open_repository(zDbName);
1749 return 1;
1750 }
1751 }
 
1752 n--;
1753 while( n>1 && zPwd[n]!='/' ){ n--; }
1754 while( n>1 && zPwd[n-1]=='/' ){ n--; }
1755 zPwd[n] = 0;
1756 }
1757
1758 /* A checkout database file could not be found */
1759 return 0;
 
 
 
1760 }
1761
1762 /*
1763 ** Get the full pathname to the repository database file. The
1764 ** local database (the _FOSSIL_ or .fslckout database) must have already
@@ -2388,11 +2399,11 @@
2388 ** year-month-day form, it may be truncated, the "T" may be replaced by
2389 ** a space, and it may also name a timezone offset from UTC as "-HH:MM"
2390 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
2391 ** means UTC.
2392 **
2393 ** See also: clone
2394 */
2395 void create_repository_cmd(void){
2396 char *zPassword;
2397 const char *zTemplate; /* Repository from which to copy settings */
2398 const char *zDate; /* Date of the initial check-in */
@@ -3070,57 +3081,158 @@
3070 }
3071
3072 /*
3073 ** COMMAND: open
3074 **
3075 ** Usage: %fossil open FILENAME ?VERSION? ?OPTIONS?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3076 **
3077 ** Open a connection to the local repository in FILENAME. A checkout
3078 ** for the repository is created with its root at the working directory.
3079 ** If VERSION is specified then that version is checked out. Otherwise
3080 ** the latest version is checked out. No files other than "manifest"
3081 ** and "manifest.uuid" are modified if the --keep option is present.
3082 **
3083 ** Options:
3084 ** --empty Initialize checkout as being empty, but still connected
3085 ** with the local repository. If you commit this checkout,
3086 ** it will become a new "initial" commit in the repository.
 
 
 
3087 ** --keep Only modify the manifest and manifest.uuid files
3088 ** --nested Allow opening a repository inside an opened checkout
3089 ** --force-missing Force opening a repository with missing content
 
3090 ** --setmtime Set timestamps of all files to match their SCM-side
3091 ** times (the timestamp of the last checkin which modified
3092 ** them).
 
 
3093 **
3094 ** See also: close
3095 */
3096 void cmd_open(void){
3097 int emptyFlag;
3098 int keepFlag;
3099 int forceMissingFlag;
3100 int allowNested;
3101 int allowSymlinks;
3102 int setmtimeFlag; /* --setmtime. Set mtimes on files */
 
3103 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
 
 
 
 
 
3104
3105 url_proxy_options();
3106 emptyFlag = find_option("empty",0,0)!=0;
3107 keepFlag = find_option("keep",0,0)!=0;
3108 forceMissingFlag = find_option("force-missing",0,0)!=0;
3109 allowNested = find_option("nested",0,0)!=0;
3110 setmtimeFlag = find_option("setmtime",0,0)!=0;
 
 
 
 
 
3111
3112 /* We should be done with options.. */
3113 verify_all_options();
3114
3115 if( g.argc!=3 && g.argc!=4 ){
3116 usage("REPOSITORY-FILENAME ?VERSION?");
3117 }
3118 if( !allowNested && db_open_local(0) ){
3119 fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3120 }
3121 db_open_repository(g.argv[2]);
 
3122
3123 /* Figure out which revision to open. */
3124 if( !emptyFlag ){
3125 if( g.argc==4 ){
3126 g.zOpenRevision = g.argv[3];
@@ -3169,12 +3281,12 @@
3169 ** point, this will probably be the setting value from the
3170 ** repository or global configuration databases. */
3171 g.allowSymlinks = db_get_boolean("allow-symlinks",
3172 db_allow_symlinks_by_default());
3173 }
3174 db_lset("repository", g.argv[2]);
3175 db_record_repository_filename(g.argv[2]);
3176 db_set_checkout(0);
3177 azNewArgv[0] = g.argv[0];
3178 g.argv = azNewArgv;
3179 if( !emptyFlag ){
3180 g.argc = 3;
@@ -3887,11 +3999,11 @@
3887 ** --global set or unset the given property globally instead of
3888 ** setting or unsetting it for the open repository only.
3889 **
3890 ** --exact only consider exact name matches.
3891 **
3892 ** See also: configuration
3893 */
3894 void setting_cmd(void){
3895 int i;
3896 int globalFlag = find_option("global","g",0)!=0;
3897 int exactFlag = find_option("exact",0,0)!=0;
3898
--- src/db.c
+++ src/db.c
@@ -116,10 +116,11 @@
116 */
117 static struct DbLocalData {
118 int nBegin; /* Nesting depth of BEGIN */
119 int doRollback; /* True to force a rollback */
120 int nCommitHook; /* Number of commit hooks */
121 int wrTxn; /* Outer-most TNX is a write */
122 Stmt *pAllStmt; /* List of all unfinalized statements */
123 int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
124 int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
125 struct sCommitHook {
126 int (*xHook)(void); /* Functions to call at db_end_transaction() */
@@ -195,10 +196,11 @@
196 sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
197 db.nPriorChanges = sqlite3_total_changes(g.db);
198 db.doRollback = 0;
199 db.zStartFile = zStartFile;
200 db.iStartLine = iStartLine;
201 db.wrTxn = 0;
202 }
203 db.nBegin++;
204 }
205 /*
206 ** Begin a new transaction for writing.
@@ -209,11 +211,12 @@
211 sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
212 db.nPriorChanges = sqlite3_total_changes(g.db);
213 db.doRollback = 0;
214 db.zStartFile = zStartFile;
215 db.iStartLine = iStartLine;
216 db.wrTxn = 1;
217 }else if( !db.wrTxn ){
218 fossil_warning("read txn at %s:%d might cause SQLITE_BUSY "
219 "for the write txn at %s:%d",
220 db.zStartFile, db.iStartLine, zStartFile, iStartLine);
221 }
222 db.nBegin++;
@@ -1328,11 +1331,11 @@
1331 );
1332 if( rc!=SQLITE_OK ){
1333 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
1334 }
1335 db_maybe_set_encryption_key(db, zDbName);
1336 sqlite3_busy_timeout(db, 15000);
1337 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
1338 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
1339 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
1340 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
1341 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
@@ -1344,11 +1347,11 @@
1347 );
1348 if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, db_sql_trace, 0);
1349 db_add_aux_functions(db);
1350 re_add_sql_func(db); /* The REGEXP operator */
1351 foci_register(db); /* The "files_of_checkin" virtual table */
1352 sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 0, &rc);
1353 return db;
1354 }
1355
1356
1357 /*
@@ -1714,16 +1717,20 @@
1717 **
1718 ** If no valid _FOSSIL_ or .fslckout file is found, we move up one level and
1719 ** try again. Once the file is found, the g.zLocalRoot variable is set
1720 ** to the root of the repository tree and this routine returns 1. If
1721 ** no database is found, then this routine return 0.
1722 **
1723 ** In db_open_local_v2(), if the bRootOnly flag is true, then only
1724 ** look in the CWD for the checkout database. Do not scan upwards in
1725 ** the file hierarchy.
1726 **
1727 ** This routine always opens the user database regardless of whether or
1728 ** not the repository database is found. If the _FOSSIL_ or .fslckout file
1729 ** is found, it is attached to the open database connection too.
1730 */
1731 int db_open_local_v2(const char *zDbName, int bRootOnly){
1732 int i, n;
1733 char zPwd[2000];
1734 static const char *(aDbName[]) = { "_FOSSIL_", ".fslckout", ".fos" };
1735
1736 if( g.localOpen ) return 1;
@@ -1747,18 +1754,22 @@
1754 g.localOpen = 1;
1755 db_open_repository(zDbName);
1756 return 1;
1757 }
1758 }
1759 if( bRootOnly ) break;
1760 n--;
1761 while( n>1 && zPwd[n]!='/' ){ n--; }
1762 while( n>1 && zPwd[n-1]=='/' ){ n--; }
1763 zPwd[n] = 0;
1764 }
1765
1766 /* A checkout database file could not be found */
1767 return 0;
1768 }
1769 int db_open_local(const char *zDbName){
1770 return db_open_local_v2(zDbName, 0);
1771 }
1772
1773 /*
1774 ** Get the full pathname to the repository database file. The
1775 ** local database (the _FOSSIL_ or .fslckout database) must have already
@@ -2388,11 +2399,11 @@
2399 ** year-month-day form, it may be truncated, the "T" may be replaced by
2400 ** a space, and it may also name a timezone offset from UTC as "-HH:MM"
2401 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
2402 ** means UTC.
2403 **
2404 ** See also: [[clone]]
2405 */
2406 void create_repository_cmd(void){
2407 char *zPassword;
2408 const char *zTemplate; /* Repository from which to copy settings */
2409 const char *zDate; /* Date of the initial check-in */
@@ -3070,57 +3081,158 @@
3081 }
3082
3083 /*
3084 ** COMMAND: open
3085 **
3086 ** Usage: %fossil open REPOSITORY ?VERSION? ?OPTIONS?
3087 **
3088 ** Open a new connection to the repository name REPOSITORY. A checkout
3089 ** for the repository is created with its root at the current working
3090 ** directory, or in DIR if the "--workdir DIR" is used. If VERSION is
3091 ** specified then that version is checked out. Otherwise the most recent
3092 ** check-in on the main branch (usually "trunk") is used.
3093 **
3094 ** REPOSITORY can be the filename for a repository that already exists on the
3095 ** local machine or it can be a URI for a remote repository. If REPOSITORY
3096 ** is a URI in one of the formats recognized by the [[clone]] command, then
3097 ** remote repo is first cloned, then the clone is opened. The clone will be
3098 ** stored in the current directory, or in DIR if the "--repodir DIR" option
3099 ** is used. The name of the clone will be taken from the last term of the URI.
3100 ** For "http:" and "https:" URIs, you can append an extra term to the end of
3101 ** the URI to get any repository name you like. For example:
3102 **
3103 ** fossil open https://fossil-scm.org/home/new-name
3104 **
3105 ** The base URI for cloning is "https://fossil-scm.org/home". The extra
3106 ** "new-name" term means that the cloned repository will be called
3107 ** "new-name.fossil".
 
 
3108 **
3109 ** Options:
3110 ** --empty Initialize checkout as being empty, but still connected
3111 ** with the local repository. If you commit this checkout,
3112 ** it will become a new "initial" commit in the repository.
3113 ** --force Continue with the open even if the working directory is
3114 ** not empty.
3115 ** --force-missing Force opening a repository with missing content
3116 ** --keep Only modify the manifest and manifest.uuid files
3117 ** --nested Allow opening a repository inside an opened checkout
3118 ** --repodir DIR If REPOSITORY is a URI that will be cloned, store
3119 ** the clone in DIR rather than in "."
3120 ** --setmtime Set timestamps of all files to match their SCM-side
3121 ** times (the timestamp of the last checkin which modified
3122 ** them).
3123 ** --workdir DIR Use DIR as the working directory instead of ".". The DIR
3124 ** directory is created if it does not exist.
3125 **
3126 ** See also: [[close]], [[clone]]
3127 */
3128 void cmd_open(void){
3129 int emptyFlag;
3130 int keepFlag;
3131 int forceMissingFlag;
3132 int allowNested;
3133 int allowSymlinks;
3134 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3135 int bForce = 0; /* --force. Open even if non-empty dir */
3136 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3137 const char *zWorkDir; /* --workdir value */
3138 const char *zRepo = 0; /* Name of the repository file */
3139 const char *zRepoDir = 0; /* --repodir value */
3140 char *zPwd; /* Initial working directory */
3141 int isUri = 0; /* True if REPOSITORY is a URI */
3142
3143 url_proxy_options();
3144 emptyFlag = find_option("empty",0,0)!=0;
3145 keepFlag = find_option("keep",0,0)!=0;
3146 forceMissingFlag = find_option("force-missing",0,0)!=0;
3147 allowNested = find_option("nested",0,0)!=0;
3148 setmtimeFlag = find_option("setmtime",0,0)!=0;
3149 zWorkDir = find_option("workdir",0,1);
3150 zRepoDir = find_option("repodir",0,1);
3151 bForce = find_option("force",0,0)!=0;
3152 zPwd = file_getcwd(0,0);
3153
3154
3155 /* We should be done with options.. */
3156 verify_all_options();
3157
3158 if( g.argc!=3 && g.argc!=4 ){
3159 usage("REPOSITORY-FILENAME ?VERSION?");
3160 }
3161 zRepo = g.argv[2];
3162 if( sqlite3_strglob("http://*", zRepo)==0
3163 || sqlite3_strglob("https://*", zRepo)==0
3164 || sqlite3_strglob("ssh:*", zRepo)==0
3165 || sqlite3_strglob("file:*", zRepo)==0
3166 ){
3167 isUri = 1;
3168 }
3169
3170 /* If --workdir is specified, change to the requested working directory */
3171 if( zWorkDir ){
3172 if( !isUri ){
3173 zRepo = file_canonical_name_dup(zRepo);
3174 }
3175 if( zRepoDir ){
3176 zRepoDir = file_canonical_name_dup(zRepoDir);
3177 }
3178 if( file_isdir(zWorkDir, ExtFILE)!=1 ){
3179 file_mkfolder(zWorkDir, ExtFILE, 0, 0);
3180 if( file_mkdir(zWorkDir, ExtFILE, 0) ){
3181 fossil_fatal("cannot create directory %s", zWorkDir);
3182 }
3183 }
3184 if( file_chdir(zWorkDir, 0) ){
3185 fossil_fatal("unable to make %s the working directory", zWorkDir);
3186 }
3187 }
3188 if( keepFlag==0 && bForce==0 && file_directory_size(".", 0, 1)>0 ){
3189 fossil_fatal("directory %s is not empty\n"
3190 "use the --force option to override", file_getcwd(0,0));
3191 }
3192
3193 if( db_open_local_v2(0, allowNested) ){
3194 fossil_fatal("there is already an open tree at %s", g.zLocalRoot);
3195 }
3196
3197 /* If REPOSITORY looks like a URI, then try to clone it first */
3198 if( isUri ){
3199 char *zNewBase; /* Base name of the cloned repository file */
3200 const char *zUri; /* URI to clone */
3201 int i; /* Loop counter */
3202 int rc; /* Result code from fossil_system() */
3203 Blob cmd; /* Clone command to be run */
3204 char *zCmd; /* String version of the clone command */
3205
3206 zUri = zRepo;
3207 zNewBase = fossil_strdup(file_tail(zUri));
3208 for(i=(int)strlen(zNewBase)-1; i>1 && zNewBase[i]!='.'; i--){}
3209 if( zNewBase[i]=='.' ) zNewBase[i] = 0;
3210 if( zRepoDir==0 ) zRepoDir = zPwd;
3211 zRepo = mprintf("%s/%s.fossil", zRepoDir, zNewBase);
3212 fossil_free(zNewBase);
3213 blob_init(&cmd, 0, 0);
3214 blob_append_escaped_arg(&cmd, g.nameOfExe);
3215 blob_append(&cmd, " clone", -1);
3216 blob_append_escaped_arg(&cmd, zUri);
3217 blob_append_escaped_arg(&cmd, zRepo);
3218 zCmd = blob_str(&cmd);
3219 fossil_print("%s\n", zCmd);
3220 if( zWorkDir ) file_chdir(zPwd, 0);
3221 rc = fossil_system(zCmd);
3222 if( rc ){
3223 fossil_fatal("clone of %s failed", zUri);
3224 }
3225 blob_reset(&cmd);
3226 if( zWorkDir ) file_chdir(zWorkDir, 0);
3227 }else if( zRepoDir ){
3228 fossil_fatal("the --repodir option only makes sense if the REPOSITORY "
3229 "argument is a URI that begins with http:, https:, ssh:, "
3230 "or file:");
3231 }
3232
3233 db_open_repository(zRepo);
3234
3235 /* Figure out which revision to open. */
3236 if( !emptyFlag ){
3237 if( g.argc==4 ){
3238 g.zOpenRevision = g.argv[3];
@@ -3169,12 +3281,12 @@
3281 ** point, this will probably be the setting value from the
3282 ** repository or global configuration databases. */
3283 g.allowSymlinks = db_get_boolean("allow-symlinks",
3284 db_allow_symlinks_by_default());
3285 }
3286 db_lset("repository", zRepo);
3287 db_record_repository_filename(zRepo);
3288 db_set_checkout(0);
3289 azNewArgv[0] = g.argv[0];
3290 g.argv = azNewArgv;
3291 if( !emptyFlag ){
3292 g.argc = 3;
@@ -3887,11 +3999,11 @@
3999 ** --global set or unset the given property globally instead of
4000 ** setting or unsetting it for the open repository only.
4001 **
4002 ** --exact only consider exact name matches.
4003 **
4004 ** See also: [[configuration]]
4005 */
4006 void setting_cmd(void){
4007 int i;
4008 int globalFlag = find_option("global","g",0)!=0;
4009 int exactFlag = find_option("exact",0,0)!=0;
4010
+375 -21
--- src/default.css
+++ src/default.css
@@ -440,16 +440,10 @@
440440
content:"'";
441441
}
442442
span.usertype:after {
443443
content:"'";
444444
}
445
-div.selectedText {
446
- font-weight: bold;
447
- color: blue;
448
- background-color: #d5d5ff;
449
- border: 1px blue solid;
450
-}
451445
p.missingPriv {
452446
color: blue;
453447
}
454448
span.wikiruleHead {
455449
font-weight: bold;
@@ -774,44 +768,93 @@
774768
div.forumTime > div > form,
775769
div.forumHierRoot > div > form {
776770
margin: 0.5em 0;
777771
}
778772
.forum-post-collapser {
773
+ /* Common style for the bottom-of-post and right-of-post
774
+ expand/collapse widgets. */
779775
font-size: 0.8em;
780
- margin-top: 0.2em;
781776
padding: 0;
777
+ border: 1px solid rgba(0, 0, 0, 0.2);
778
+ border-radius: 0 0 0.5em 0.5em;
779
+ background-color: rgba(0, 0, 0, 0.05);
780
+ opacity: 0.8;
781
+ cursor: pointer;
782
+}
783
+.forum-post-collapser.bottom {
784
+ margin: 0 0 0.4em 0;
782785
height: 1.75em;
783786
line-height: 1.75em;
784787
/* ^^^ Those sizes are finely tuned for the current selection of
785788
arrow characters. If those change, these should, too. Remember that
786789
FF/Chrome simply do not agree on alignment with most values :/. */
787
- border-width: 1px;
788
- border-style: solid;
789
- border-radius: 0.25em;
790
- opacity: 0.8;
791
- cursor: pointer;
792790
display: flex;
793791
flex-direction: row;
794792
justify-content: space-between;
795793
}
796
-.forum-post-collapser > span {
794
+.forum-post-collapser.bottom > span {
797795
margin: 0 1em 0 1em;
798796
vertical-align: middle;
799797
}
800
-.forum-post-collapser.expanded > span::before {
801
- content: "⇡⇡⇡" /*reminder: FF/Chrome cannot agree on alignment of ⮝*/;
802
-}
803
-.forum-post-collapser:not(.expanded) > span::before {
798
+.forum-post-collapser.bottom > span::before {
804799
content: "⇣⇣⇣";
805800
}
801
+.forum-post-collapser.bottom.expanded > span::before {
802
+ content: "⇡⇡⇡" /*reminder: FF/Chrome cannot agree on alignment of ⮝*/;
803
+}
806804
div.forumPostBody{
807805
max-height: 50em;
808806
overflow: auto;
807
+}
808
+div.forumPostBody.with-expander {
809
+ display: flex;
810
+ flex-direction: row;
811
+ overflow: auto;
812
+}
813
+div.forumPostBody.with-expander:not(.expanded) > :first-child {
814
+ overflow-y: hidden;
815
+}
816
+div.forumPostBody.with-expander > *:first-child {
817
+ /* Main content DIV/PRE */
818
+ overflow: auto;
819
+ flex: 10 1 auto;
820
+}
821
+div.forumPostBody.with-expander.expanded > *:first-child {
822
+ margin-bottom: 0.5em /* try to suppress scroll bar */;
823
+}
824
+div.forumPostBody.with-expander .forum-post-collapser.right {
825
+ /* "Tap zone" for expansion of the post, sits to the right of the
826
+ post's content. */
827
+ flex: 1 10 auto;
828
+ min-width: 1.25em;
829
+ max-width: 1.25em;
830
+ margin: 0 0 0 0.2em;
831
+ overflow: hidden;
832
+ display: flex;
833
+ flex-direction: column;
834
+ justify-content: space-around;
835
+ align-items: center;
836
+ border-radius: 0.1em;
837
+ cursor: pointer;
838
+ border-bottom: 0;
839
+ border-radius: 0 0.5em 0 0;
840
+}
841
+div.forumPostBody.with-expander .forum-post-collapser.right > span:before {
842
+ content: "⇣";
843
+}
844
+div.forumPostBody.with-expander.expanded .forum-post-collapser.right > span:before {
845
+ content: "⇡";
809846
}
810847
div.forumPostBody.expanded {
811848
max-height: initial;
812849
}
850
+div.forumPostBody.shrunken {
851
+ /* When an expandable post is un-expanded, it is shrunkend down
852
+ to this size instead of its original size. */
853
+ max-height: 8em;
854
+}
855
+
813856
div.forumSel {
814857
background-color: #cef;
815858
}
816859
div.forumObs {
817860
color: #bbb;
@@ -904,14 +947,19 @@
904947
color: darkred;
905948
background: yellow;
906949
opacity: 0.7;
907950
}
908951
.hidden {
909
- position: absolute;
910
- opacity: 0;
911
- pointer-events: none;
912
- display: none;
952
+ /* The framework-wide way of hiding elements is to assign them this
953
+ CSS class. To make them visible again, remove it. The !important
954
+ qualifiers are unfortunate but sometimes necessary when hidden
955
+ element has other classes which specify visibility-related
956
+ options. */
957
+ position: absolute !important;
958
+ opacity: 0 !important;
959
+ pointer-events: none !important;
960
+ display: none !important;
913961
}
914962
input {
915963
max-width: 95%;
916964
}
917965
textarea {
@@ -919,5 +967,311 @@
919967
}
920968
img {
921969
max-width: 100%;
922970
height: auto;
923971
}
972
+hr {
973
+ /* Needed to keep /dir README.txt from floating right in some skins */
974
+ clear: both;
975
+}
976
+
977
+/**
978
+ .tab-xxx: styles for fossil.tabs.js.
979
+*/
980
+.tab-container {
981
+ width: 100%;
982
+ display: flex;
983
+ flex-direction: column;
984
+ align-items: stretch;
985
+}
986
+.tab-container > #fossil-status-bar {
987
+ margin-top: 0;
988
+}
989
+.tab-container > .tabs {
990
+ padding: 0.25em;
991
+ margin: 0;
992
+ display: flex;
993
+ flex-direction: column;
994
+ border-width: 1px;
995
+ border-style: outset;
996
+ border-color: inherit;
997
+}
998
+.tab-container > .tabs > .tab-panel {
999
+ align-self: stretch;
1000
+ flex: 10 1 auto;
1001
+ display: block;
1002
+ border: 0;
1003
+ padding: 0;
1004
+ margin: 0;
1005
+}
1006
+.tab-container > .tab-bar {
1007
+ display: flex;
1008
+ flex-direction: row;
1009
+ flex: 1 10 auto;
1010
+ align-self: stretch;
1011
+ flex-wrap: wrap;
1012
+}
1013
+.tab-container > .tab-bar > .tab-button {
1014
+ display: inline-block;
1015
+ border-radius: 0.25em 0.25em 0 0;
1016
+ margin: 0 0.1em;
1017
+ padding: 0.25em 0.75em;
1018
+ align-self: baseline;
1019
+ border-color: inherit;
1020
+ border-width: 1px;
1021
+ border-bottom: none;
1022
+ border-top-style: inset;
1023
+ border-left-style: inset;
1024
+ border-right-style: inset;
1025
+ cursor: pointer;
1026
+ opacity: 0.6;
1027
+}
1028
+.tab-container > .tab-bar > .tab-button.selected {
1029
+ text-decoration: underline;
1030
+ opacity: 1.0;
1031
+ border-top-style: outset;
1032
+ border-left-style: outset;
1033
+ border-right-style: outset;
1034
+}
1035
+
1036
+/**
1037
+ The flex-xxx classes can be used to create basic flexbox layouts
1038
+ through the application of classes to the containing/contained
1039
+ objects.
1040
+*/
1041
+.flex-container {
1042
+ display: flex;
1043
+}
1044
+.flex-container.flex-row {
1045
+ flex-direction: row;
1046
+ flex-wrap: wrap;
1047
+ justify-content: center;
1048
+ align-items: center;
1049
+}
1050
+.flex-container .flex-grow {
1051
+ flex-grow: 10;
1052
+ flex-shrink: 0;
1053
+}
1054
+.flex-container .flex-shrink {
1055
+ flex-grow: 0;
1056
+ flex-shrink: 10;
1057
+}
1058
+.flex-container.flex-row.stretch {
1059
+ flex-wrap: wrap;
1060
+ align-items: baseline;
1061
+ justify-content: stretch;
1062
+ margin: 0;
1063
+}
1064
+.flex-container.flex-column {
1065
+ flex-direction: column;
1066
+ flex-wrap: wrap;
1067
+ justify-content: center;
1068
+ align-items: center;
1069
+}
1070
+.flex-container.flex-column.stretch {
1071
+ align-items: stretch;
1072
+ margin: 0;
1073
+}
1074
+.flex-container.child-gap-small > * {
1075
+ margin: 0.25em;
1076
+}
1077
+#fossil-status-bar {
1078
+ display: block;
1079
+ font-family: monospace;
1080
+ border-width: 1px;
1081
+ border-style: inset;
1082
+ border-color: inherit;
1083
+ min-height: 1.5em;
1084
+ font-size: 1.2em;
1085
+ padding: 0.2em;
1086
+ margin: 0.25em 0;
1087
+ flex: 0 0 auto;
1088
+}
1089
+.font-size-100 {
1090
+ font-size: 100%;
1091
+}
1092
+.font-size-125 {
1093
+ font-size: 125%;
1094
+}
1095
+.font-size-150 {
1096
+ font-size: 150%;
1097
+}
1098
+.font-size-175 {
1099
+ font-size: 175%;
1100
+}
1101
+.font-size-200 {
1102
+ font-size: 200%;
1103
+}
1104
+
1105
+/**
1106
+ .input-with-label is intended to be a wrapper element which
1107
+ contain both a LABEL tag and an INPUT or SELECT control.
1108
+ The wrapper is "necessary", as opposed to placing the INPUT
1109
+ in the LABEL, so that we can include multiple INPUT
1110
+ elements (e.g. a set of radio buttons).
1111
+*/
1112
+.input-with-label {
1113
+ border: 1px inset #808080;
1114
+ border-radius: 0.25em;
1115
+ padding: 0.25em 0.4em;
1116
+ margin: 0 0.5em;
1117
+ display: inline-block;
1118
+ cursor: default;
1119
+}
1120
+.input-with-label > * {
1121
+ vertical-align: middle;
1122
+}
1123
+.input-with-label > label {
1124
+ display: inline; /* some skins set label display to block! */
1125
+}
1126
+.input-with-label > input {
1127
+ margin: 0;
1128
+}
1129
+.input-with-label > button {
1130
+ margin: 0;
1131
+}
1132
+.input-with-label > select {
1133
+ margin: 0;
1134
+}
1135
+.input-with-label > input[type=text] {
1136
+ margin: 0;
1137
+}
1138
+.input-with-label > textarea {
1139
+ margin: 0;
1140
+}
1141
+.input-with-label > input[type=checkbox] {
1142
+ vertical-align: sub;
1143
+}
1144
+.input-with-label > input[type=radio] {
1145
+ vertical-align: sub;
1146
+}
1147
+.input-with-label > label {
1148
+ font-weight: initial;
1149
+ margin: 0 0.25em 0 0.25em;
1150
+ vertical-align: middle;
1151
+}
1152
+
1153
+table.numbered-lines {
1154
+ width: 100%;
1155
+ table-layout: fixed /* required to keep ultra-wide code from exceeding
1156
+ window width, and instead force a scrollbar
1157
+ on them. */;
1158
+}
1159
+table.numbered-lines > tbody > tr {
1160
+ font-family: monospace;
1161
+ font-size: 1.2em;
1162
+ line-height: 1.35;
1163
+ white-space: pre;
1164
+}
1165
+table.numbered-lines > tbody > tr > td {
1166
+ font-family: inherit;
1167
+ font-size: inherit;
1168
+ line-height: inherit;
1169
+ white-space: inherit;
1170
+ margin: 0;
1171
+ vertical-align: top;
1172
+ padding: 0.25em 0 0 0 /*prevents slight overlap at top */;
1173
+}
1174
+table.numbered-lines td.line-numbers {
1175
+ width: 4.5em;
1176
+}
1177
+table.numbered-lines td.line-numbers > span:first-of-type {
1178
+ margin-top: 0.25em/*must match top PADDING of
1179
+ td.file-content > pre > code*/;
1180
+}
1181
+table.numbered-lines td.line-numbers > span {
1182
+ display: block;
1183
+ margin: 0;
1184
+ padding: 0;
1185
+ line-height: inherit;
1186
+ font-size: inherit;
1187
+ font-family: inherit;
1188
+ cursor: pointer;
1189
+ white-space: pre;
1190
+ margin-right: 2px/*keep selection from nudging the right column */;
1191
+ text-align: right;
1192
+}
1193
+table.numbered-lines td.line-numbers > span:hover {
1194
+ background-color: rgba(112, 112, 112, 0.25);
1195
+}
1196
+table.numbered-lines td.file-content {
1197
+ padding-left: 0.25em;
1198
+}
1199
+table.numbered-lines td.file-content > pre,
1200
+table.numbered-lines td.file-content > pre > code {
1201
+ margin: 0;
1202
+ padding: 0;
1203
+ line-height: inherit;
1204
+ font-size: inherit;
1205
+ font-family: inherit;
1206
+ white-space: pre;
1207
+ display: block/*necessary for certain skins!*/;
1208
+}
1209
+table.numbered-lines td.file-content > pre {
1210
+}
1211
+table.numbered-lines td.file-content > pre > code {
1212
+ overflow: auto;
1213
+ padding-left: 0.5em;
1214
+ padding-right: 0.5em;
1215
+ padding-top: 0.25em/*any top padding here must match the top MARGIN of
1216
+ td.line-numbers's first span child or the
1217
+ lines/code will get misaligned. */;
1218
+ padding-bottom: 0.25em/*prevents a slight overlap at bottom from
1219
+ triggering a scroller*/;
1220
+}
1221
+table.numbered-lines td.file-content > pre > code > * {
1222
+ /* Defense against syntax highlighters indirectly messing up these
1223
+ properties... */
1224
+ line-height: inherit;
1225
+ font-size: inherit;
1226
+ font-family: inherit;
1227
+}
1228
+table.numbered-lines td.line-numbers span.selected-line/*replacement*/ {
1229
+ font-weight: bold;
1230
+ color: blue;
1231
+ background-color: #d5d5ff;
1232
+ border: 1px blue solid;
1233
+ border-top-width: 0;
1234
+ border-bottom-width: 0;
1235
+ padding: 0;
1236
+ margin: 0;
1237
+}
1238
+table.numbered-lines td.line-numbers span.selected-line.start {
1239
+ border-top-width: 1px;
1240
+ margin-top: -1px/*restore alignment*/;
1241
+}
1242
+table.numbered-lines td.line-numbers span.selected-line.end {
1243
+ border-bottom-width: 1px;
1244
+ margin-top: -1px/*restore alignment*/;
1245
+}
1246
+table.numbered-lines td.line-numbers span.selected-line.start.end {
1247
+ margin-top: -2px/*restore alignment*/;
1248
+}
1249
+
1250
+.fossil-tooltip {
1251
+ text-align: center;
1252
+ padding: 0.2em 1em;
1253
+ border: 1px solid black;
1254
+ border-radius: 0.25em;
1255
+ position: absolute;
1256
+ display: inline-block;
1257
+ z-index: 100;
1258
+ box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.75);
1259
+ background-color: inherit;
1260
+ font-size: 80%;
1261
+}
1262
+
1263
+.fossil-toast {/* "toast"-style popup message */
1264
+ padding: 0.25em 0.5em;
1265
+ margin: 0;
1266
+ border-radius: 0.25em;
1267
+ font-size: 1em;
1268
+ opacity: 0.8;
1269
+ border-size: 1px;
1270
+ border-style: dotted;
1271
+ border-color: rgb( 127, 127, 127, 0.5 );
1272
+}
1273
+
1274
+blockquote.file-content {
1275
+ /* file content block in the /file page */
1276
+ margin: 0 1em;
1277
+}
9241278
--- src/default.css
+++ src/default.css
@@ -440,16 +440,10 @@
440 content:"'";
441 }
442 span.usertype:after {
443 content:"'";
444 }
445 div.selectedText {
446 font-weight: bold;
447 color: blue;
448 background-color: #d5d5ff;
449 border: 1px blue solid;
450 }
451 p.missingPriv {
452 color: blue;
453 }
454 span.wikiruleHead {
455 font-weight: bold;
@@ -774,44 +768,93 @@
774 div.forumTime > div > form,
775 div.forumHierRoot > div > form {
776 margin: 0.5em 0;
777 }
778 .forum-post-collapser {
 
 
779 font-size: 0.8em;
780 margin-top: 0.2em;
781 padding: 0;
 
 
 
 
 
 
 
 
782 height: 1.75em;
783 line-height: 1.75em;
784 /* ^^^ Those sizes are finely tuned for the current selection of
785 arrow characters. If those change, these should, too. Remember that
786 FF/Chrome simply do not agree on alignment with most values :/. */
787 border-width: 1px;
788 border-style: solid;
789 border-radius: 0.25em;
790 opacity: 0.8;
791 cursor: pointer;
792 display: flex;
793 flex-direction: row;
794 justify-content: space-between;
795 }
796 .forum-post-collapser > span {
797 margin: 0 1em 0 1em;
798 vertical-align: middle;
799 }
800 .forum-post-collapser.expanded > span::before {
801 content: "⇡⇡⇡" /*reminder: FF/Chrome cannot agree on alignment of ⮝*/;
802 }
803 .forum-post-collapser:not(.expanded) > span::before {
804 content: "⇣⇣⇣";
805 }
 
 
 
806 div.forumPostBody{
807 max-height: 50em;
808 overflow: auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
809 }
810 div.forumPostBody.expanded {
811 max-height: initial;
812 }
 
 
 
 
 
 
813 div.forumSel {
814 background-color: #cef;
815 }
816 div.forumObs {
817 color: #bbb;
@@ -904,14 +947,19 @@
904 color: darkred;
905 background: yellow;
906 opacity: 0.7;
907 }
908 .hidden {
909 position: absolute;
910 opacity: 0;
911 pointer-events: none;
912 display: none;
 
 
 
 
 
913 }
914 input {
915 max-width: 95%;
916 }
917 textarea {
@@ -919,5 +967,311 @@
919 }
920 img {
921 max-width: 100%;
922 height: auto;
923 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
924
--- src/default.css
+++ src/default.css
@@ -440,16 +440,10 @@
440 content:"'";
441 }
442 span.usertype:after {
443 content:"'";
444 }
 
 
 
 
 
 
445 p.missingPriv {
446 color: blue;
447 }
448 span.wikiruleHead {
449 font-weight: bold;
@@ -774,44 +768,93 @@
768 div.forumTime > div > form,
769 div.forumHierRoot > div > form {
770 margin: 0.5em 0;
771 }
772 .forum-post-collapser {
773 /* Common style for the bottom-of-post and right-of-post
774 expand/collapse widgets. */
775 font-size: 0.8em;
 
776 padding: 0;
777 border: 1px solid rgba(0, 0, 0, 0.2);
778 border-radius: 0 0 0.5em 0.5em;
779 background-color: rgba(0, 0, 0, 0.05);
780 opacity: 0.8;
781 cursor: pointer;
782 }
783 .forum-post-collapser.bottom {
784 margin: 0 0 0.4em 0;
785 height: 1.75em;
786 line-height: 1.75em;
787 /* ^^^ Those sizes are finely tuned for the current selection of
788 arrow characters. If those change, these should, too. Remember that
789 FF/Chrome simply do not agree on alignment with most values :/. */
 
 
 
 
 
790 display: flex;
791 flex-direction: row;
792 justify-content: space-between;
793 }
794 .forum-post-collapser.bottom > span {
795 margin: 0 1em 0 1em;
796 vertical-align: middle;
797 }
798 .forum-post-collapser.bottom > span::before {
 
 
 
799 content: "⇣⇣⇣";
800 }
801 .forum-post-collapser.bottom.expanded > span::before {
802 content: "⇡⇡⇡" /*reminder: FF/Chrome cannot agree on alignment of ⮝*/;
803 }
804 div.forumPostBody{
805 max-height: 50em;
806 overflow: auto;
807 }
808 div.forumPostBody.with-expander {
809 display: flex;
810 flex-direction: row;
811 overflow: auto;
812 }
813 div.forumPostBody.with-expander:not(.expanded) > :first-child {
814 overflow-y: hidden;
815 }
816 div.forumPostBody.with-expander > *:first-child {
817 /* Main content DIV/PRE */
818 overflow: auto;
819 flex: 10 1 auto;
820 }
821 div.forumPostBody.with-expander.expanded > *:first-child {
822 margin-bottom: 0.5em /* try to suppress scroll bar */;
823 }
824 div.forumPostBody.with-expander .forum-post-collapser.right {
825 /* "Tap zone" for expansion of the post, sits to the right of the
826 post's content. */
827 flex: 1 10 auto;
828 min-width: 1.25em;
829 max-width: 1.25em;
830 margin: 0 0 0 0.2em;
831 overflow: hidden;
832 display: flex;
833 flex-direction: column;
834 justify-content: space-around;
835 align-items: center;
836 border-radius: 0.1em;
837 cursor: pointer;
838 border-bottom: 0;
839 border-radius: 0 0.5em 0 0;
840 }
841 div.forumPostBody.with-expander .forum-post-collapser.right > span:before {
842 content: "⇣";
843 }
844 div.forumPostBody.with-expander.expanded .forum-post-collapser.right > span:before {
845 content: "⇡";
846 }
847 div.forumPostBody.expanded {
848 max-height: initial;
849 }
850 div.forumPostBody.shrunken {
851 /* When an expandable post is un-expanded, it is shrunkend down
852 to this size instead of its original size. */
853 max-height: 8em;
854 }
855
856 div.forumSel {
857 background-color: #cef;
858 }
859 div.forumObs {
860 color: #bbb;
@@ -904,14 +947,19 @@
947 color: darkred;
948 background: yellow;
949 opacity: 0.7;
950 }
951 .hidden {
952 /* The framework-wide way of hiding elements is to assign them this
953 CSS class. To make them visible again, remove it. The !important
954 qualifiers are unfortunate but sometimes necessary when hidden
955 element has other classes which specify visibility-related
956 options. */
957 position: absolute !important;
958 opacity: 0 !important;
959 pointer-events: none !important;
960 display: none !important;
961 }
962 input {
963 max-width: 95%;
964 }
965 textarea {
@@ -919,5 +967,311 @@
967 }
968 img {
969 max-width: 100%;
970 height: auto;
971 }
972 hr {
973 /* Needed to keep /dir README.txt from floating right in some skins */
974 clear: both;
975 }
976
977 /**
978 .tab-xxx: styles for fossil.tabs.js.
979 */
980 .tab-container {
981 width: 100%;
982 display: flex;
983 flex-direction: column;
984 align-items: stretch;
985 }
986 .tab-container > #fossil-status-bar {
987 margin-top: 0;
988 }
989 .tab-container > .tabs {
990 padding: 0.25em;
991 margin: 0;
992 display: flex;
993 flex-direction: column;
994 border-width: 1px;
995 border-style: outset;
996 border-color: inherit;
997 }
998 .tab-container > .tabs > .tab-panel {
999 align-self: stretch;
1000 flex: 10 1 auto;
1001 display: block;
1002 border: 0;
1003 padding: 0;
1004 margin: 0;
1005 }
1006 .tab-container > .tab-bar {
1007 display: flex;
1008 flex-direction: row;
1009 flex: 1 10 auto;
1010 align-self: stretch;
1011 flex-wrap: wrap;
1012 }
1013 .tab-container > .tab-bar > .tab-button {
1014 display: inline-block;
1015 border-radius: 0.25em 0.25em 0 0;
1016 margin: 0 0.1em;
1017 padding: 0.25em 0.75em;
1018 align-self: baseline;
1019 border-color: inherit;
1020 border-width: 1px;
1021 border-bottom: none;
1022 border-top-style: inset;
1023 border-left-style: inset;
1024 border-right-style: inset;
1025 cursor: pointer;
1026 opacity: 0.6;
1027 }
1028 .tab-container > .tab-bar > .tab-button.selected {
1029 text-decoration: underline;
1030 opacity: 1.0;
1031 border-top-style: outset;
1032 border-left-style: outset;
1033 border-right-style: outset;
1034 }
1035
1036 /**
1037 The flex-xxx classes can be used to create basic flexbox layouts
1038 through the application of classes to the containing/contained
1039 objects.
1040 */
1041 .flex-container {
1042 display: flex;
1043 }
1044 .flex-container.flex-row {
1045 flex-direction: row;
1046 flex-wrap: wrap;
1047 justify-content: center;
1048 align-items: center;
1049 }
1050 .flex-container .flex-grow {
1051 flex-grow: 10;
1052 flex-shrink: 0;
1053 }
1054 .flex-container .flex-shrink {
1055 flex-grow: 0;
1056 flex-shrink: 10;
1057 }
1058 .flex-container.flex-row.stretch {
1059 flex-wrap: wrap;
1060 align-items: baseline;
1061 justify-content: stretch;
1062 margin: 0;
1063 }
1064 .flex-container.flex-column {
1065 flex-direction: column;
1066 flex-wrap: wrap;
1067 justify-content: center;
1068 align-items: center;
1069 }
1070 .flex-container.flex-column.stretch {
1071 align-items: stretch;
1072 margin: 0;
1073 }
1074 .flex-container.child-gap-small > * {
1075 margin: 0.25em;
1076 }
1077 #fossil-status-bar {
1078 display: block;
1079 font-family: monospace;
1080 border-width: 1px;
1081 border-style: inset;
1082 border-color: inherit;
1083 min-height: 1.5em;
1084 font-size: 1.2em;
1085 padding: 0.2em;
1086 margin: 0.25em 0;
1087 flex: 0 0 auto;
1088 }
1089 .font-size-100 {
1090 font-size: 100%;
1091 }
1092 .font-size-125 {
1093 font-size: 125%;
1094 }
1095 .font-size-150 {
1096 font-size: 150%;
1097 }
1098 .font-size-175 {
1099 font-size: 175%;
1100 }
1101 .font-size-200 {
1102 font-size: 200%;
1103 }
1104
1105 /**
1106 .input-with-label is intended to be a wrapper element which
1107 contain both a LABEL tag and an INPUT or SELECT control.
1108 The wrapper is "necessary", as opposed to placing the INPUT
1109 in the LABEL, so that we can include multiple INPUT
1110 elements (e.g. a set of radio buttons).
1111 */
1112 .input-with-label {
1113 border: 1px inset #808080;
1114 border-radius: 0.25em;
1115 padding: 0.25em 0.4em;
1116 margin: 0 0.5em;
1117 display: inline-block;
1118 cursor: default;
1119 }
1120 .input-with-label > * {
1121 vertical-align: middle;
1122 }
1123 .input-with-label > label {
1124 display: inline; /* some skins set label display to block! */
1125 }
1126 .input-with-label > input {
1127 margin: 0;
1128 }
1129 .input-with-label > button {
1130 margin: 0;
1131 }
1132 .input-with-label > select {
1133 margin: 0;
1134 }
1135 .input-with-label > input[type=text] {
1136 margin: 0;
1137 }
1138 .input-with-label > textarea {
1139 margin: 0;
1140 }
1141 .input-with-label > input[type=checkbox] {
1142 vertical-align: sub;
1143 }
1144 .input-with-label > input[type=radio] {
1145 vertical-align: sub;
1146 }
1147 .input-with-label > label {
1148 font-weight: initial;
1149 margin: 0 0.25em 0 0.25em;
1150 vertical-align: middle;
1151 }
1152
1153 table.numbered-lines {
1154 width: 100%;
1155 table-layout: fixed /* required to keep ultra-wide code from exceeding
1156 window width, and instead force a scrollbar
1157 on them. */;
1158 }
1159 table.numbered-lines > tbody > tr {
1160 font-family: monospace;
1161 font-size: 1.2em;
1162 line-height: 1.35;
1163 white-space: pre;
1164 }
1165 table.numbered-lines > tbody > tr > td {
1166 font-family: inherit;
1167 font-size: inherit;
1168 line-height: inherit;
1169 white-space: inherit;
1170 margin: 0;
1171 vertical-align: top;
1172 padding: 0.25em 0 0 0 /*prevents slight overlap at top */;
1173 }
1174 table.numbered-lines td.line-numbers {
1175 width: 4.5em;
1176 }
1177 table.numbered-lines td.line-numbers > span:first-of-type {
1178 margin-top: 0.25em/*must match top PADDING of
1179 td.file-content > pre > code*/;
1180 }
1181 table.numbered-lines td.line-numbers > span {
1182 display: block;
1183 margin: 0;
1184 padding: 0;
1185 line-height: inherit;
1186 font-size: inherit;
1187 font-family: inherit;
1188 cursor: pointer;
1189 white-space: pre;
1190 margin-right: 2px/*keep selection from nudging the right column */;
1191 text-align: right;
1192 }
1193 table.numbered-lines td.line-numbers > span:hover {
1194 background-color: rgba(112, 112, 112, 0.25);
1195 }
1196 table.numbered-lines td.file-content {
1197 padding-left: 0.25em;
1198 }
1199 table.numbered-lines td.file-content > pre,
1200 table.numbered-lines td.file-content > pre > code {
1201 margin: 0;
1202 padding: 0;
1203 line-height: inherit;
1204 font-size: inherit;
1205 font-family: inherit;
1206 white-space: pre;
1207 display: block/*necessary for certain skins!*/;
1208 }
1209 table.numbered-lines td.file-content > pre {
1210 }
1211 table.numbered-lines td.file-content > pre > code {
1212 overflow: auto;
1213 padding-left: 0.5em;
1214 padding-right: 0.5em;
1215 padding-top: 0.25em/*any top padding here must match the top MARGIN of
1216 td.line-numbers's first span child or the
1217 lines/code will get misaligned. */;
1218 padding-bottom: 0.25em/*prevents a slight overlap at bottom from
1219 triggering a scroller*/;
1220 }
1221 table.numbered-lines td.file-content > pre > code > * {
1222 /* Defense against syntax highlighters indirectly messing up these
1223 properties... */
1224 line-height: inherit;
1225 font-size: inherit;
1226 font-family: inherit;
1227 }
1228 table.numbered-lines td.line-numbers span.selected-line/*replacement*/ {
1229 font-weight: bold;
1230 color: blue;
1231 background-color: #d5d5ff;
1232 border: 1px blue solid;
1233 border-top-width: 0;
1234 border-bottom-width: 0;
1235 padding: 0;
1236 margin: 0;
1237 }
1238 table.numbered-lines td.line-numbers span.selected-line.start {
1239 border-top-width: 1px;
1240 margin-top: -1px/*restore alignment*/;
1241 }
1242 table.numbered-lines td.line-numbers span.selected-line.end {
1243 border-bottom-width: 1px;
1244 margin-top: -1px/*restore alignment*/;
1245 }
1246 table.numbered-lines td.line-numbers span.selected-line.start.end {
1247 margin-top: -2px/*restore alignment*/;
1248 }
1249
1250 .fossil-tooltip {
1251 text-align: center;
1252 padding: 0.2em 1em;
1253 border: 1px solid black;
1254 border-radius: 0.25em;
1255 position: absolute;
1256 display: inline-block;
1257 z-index: 100;
1258 box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.75);
1259 background-color: inherit;
1260 font-size: 80%;
1261 }
1262
1263 .fossil-toast {/* "toast"-style popup message */
1264 padding: 0.25em 0.5em;
1265 margin: 0;
1266 border-radius: 0.25em;
1267 font-size: 1em;
1268 opacity: 0.8;
1269 border-size: 1px;
1270 border-style: dotted;
1271 border-color: rgb( 127, 127, 127, 0.5 );
1272 }
1273
1274 blockquote.file-content {
1275 /* file content block in the /file page */
1276 margin: 0 1em;
1277 }
1278
--- src/descendants.c
+++ src/descendants.c
@@ -348,11 +348,11 @@
348348
** -R|--repository FILE Extract info from repository FILE
349349
** -W|--width <num> Width of lines (default is to auto-detect).
350350
** Must be >20 or 0 (= no limit, resulting in a
351351
** single line per entry).
352352
**
353
-** See also: finfo, info, leaves
353
+** See also: [[finfo]], [[info]], [[leaves]]
354354
*/
355355
void descendants_cmd(void){
356356
Stmt q;
357357
int base, width;
358358
const char *zWidth;
@@ -408,11 +408,11 @@
408408
** --recompute recompute the "leaf" table in the repository DB
409409
** -W|--width <num> Width of lines (default is to auto-detect). Must be
410410
** >39 or 0 (= no limit, resulting in a single line per
411411
** entry).
412412
**
413
-** See also: descendants, finfo, info, branch
413
+** See also: [[descendants]], [[finfo]], [[info]], [[branch]]
414414
*/
415415
void leaves_cmd(void){
416416
Stmt q;
417417
Blob sql;
418418
int showAll = find_option("all", "a", 0)!=0;
419419
--- src/descendants.c
+++ src/descendants.c
@@ -348,11 +348,11 @@
348 ** -R|--repository FILE Extract info from repository FILE
349 ** -W|--width <num> Width of lines (default is to auto-detect).
350 ** Must be >20 or 0 (= no limit, resulting in a
351 ** single line per entry).
352 **
353 ** See also: finfo, info, leaves
354 */
355 void descendants_cmd(void){
356 Stmt q;
357 int base, width;
358 const char *zWidth;
@@ -408,11 +408,11 @@
408 ** --recompute recompute the "leaf" table in the repository DB
409 ** -W|--width <num> Width of lines (default is to auto-detect). Must be
410 ** >39 or 0 (= no limit, resulting in a single line per
411 ** entry).
412 **
413 ** See also: descendants, finfo, info, branch
414 */
415 void leaves_cmd(void){
416 Stmt q;
417 Blob sql;
418 int showAll = find_option("all", "a", 0)!=0;
419
--- src/descendants.c
+++ src/descendants.c
@@ -348,11 +348,11 @@
348 ** -R|--repository FILE Extract info from repository FILE
349 ** -W|--width <num> Width of lines (default is to auto-detect).
350 ** Must be >20 or 0 (= no limit, resulting in a
351 ** single line per entry).
352 **
353 ** See also: [[finfo]], [[info]], [[leaves]]
354 */
355 void descendants_cmd(void){
356 Stmt q;
357 int base, width;
358 const char *zWidth;
@@ -408,11 +408,11 @@
408 ** --recompute recompute the "leaf" table in the repository DB
409 ** -W|--width <num> Width of lines (default is to auto-detect). Must be
410 ** >39 or 0 (= no limit, resulting in a single line per
411 ** entry).
412 **
413 ** See also: [[descendants]], [[finfo]], [[info]], [[branch]]
414 */
415 void leaves_cmd(void){
416 Stmt q;
417 Blob sql;
418 int showAll = find_option("all", "a", 0)!=0;
419
+3 -3
--- src/diff.c
+++ src/diff.c
@@ -125,11 +125,11 @@
125125
** in the count even if it lacks the \n terminator. If an empty string
126126
** is specified, the number of lines is zero. For the purposes of this
127127
** function, a string is considered empty if it contains no characters
128128
** -OR- it contains only NUL characters.
129129
*/
130
-static int count_lines(
130
+int count_lines(
131131
const char *z,
132132
int n,
133133
int *pnLine
134134
){
135135
int nLine;
@@ -2562,11 +2562,11 @@
25622562
}
25632563
25642564
/*
25652565
** COMMAND: annotate
25662566
** COMMAND: blame
2567
-** COMMAND: praise
2567
+** COMMAND: praise*
25682568
**
25692569
** Usage: %fossil annotate|blame|praise ?OPTIONS? FILENAME
25702570
**
25712571
** Output the text of a file with markings to show when each line of the file
25722572
** was last modified. The version currently checked out is shown by default.
@@ -2596,11 +2596,11 @@
25962596
** root of the repository. Set to "trunk" or
25972597
** similar for a reverse annotation.
25982598
** -w|--ignore-all-space Ignore white space when comparing lines
25992599
** -Z|--ignore-trailing-space Ignore whitespace at line end
26002600
**
2601
-** See also: info, finfo, timeline
2601
+** See also: [[info]], [[finfo]], [[timeline]]
26022602
*/
26032603
void annotate_cmd(void){
26042604
const char *zRevision; /* Revision name, or NULL for current check-in */
26052605
Annotator ann; /* The annotation of the file */
26062606
int i; /* Loop counter */
26072607
--- src/diff.c
+++ src/diff.c
@@ -125,11 +125,11 @@
125 ** in the count even if it lacks the \n terminator. If an empty string
126 ** is specified, the number of lines is zero. For the purposes of this
127 ** function, a string is considered empty if it contains no characters
128 ** -OR- it contains only NUL characters.
129 */
130 static int count_lines(
131 const char *z,
132 int n,
133 int *pnLine
134 ){
135 int nLine;
@@ -2562,11 +2562,11 @@
2562 }
2563
2564 /*
2565 ** COMMAND: annotate
2566 ** COMMAND: blame
2567 ** COMMAND: praise
2568 **
2569 ** Usage: %fossil annotate|blame|praise ?OPTIONS? FILENAME
2570 **
2571 ** Output the text of a file with markings to show when each line of the file
2572 ** was last modified. The version currently checked out is shown by default.
@@ -2596,11 +2596,11 @@
2596 ** root of the repository. Set to "trunk" or
2597 ** similar for a reverse annotation.
2598 ** -w|--ignore-all-space Ignore white space when comparing lines
2599 ** -Z|--ignore-trailing-space Ignore whitespace at line end
2600 **
2601 ** See also: info, finfo, timeline
2602 */
2603 void annotate_cmd(void){
2604 const char *zRevision; /* Revision name, or NULL for current check-in */
2605 Annotator ann; /* The annotation of the file */
2606 int i; /* Loop counter */
2607
--- src/diff.c
+++ src/diff.c
@@ -125,11 +125,11 @@
125 ** in the count even if it lacks the \n terminator. If an empty string
126 ** is specified, the number of lines is zero. For the purposes of this
127 ** function, a string is considered empty if it contains no characters
128 ** -OR- it contains only NUL characters.
129 */
130 int count_lines(
131 const char *z,
132 int n,
133 int *pnLine
134 ){
135 int nLine;
@@ -2562,11 +2562,11 @@
2562 }
2563
2564 /*
2565 ** COMMAND: annotate
2566 ** COMMAND: blame
2567 ** COMMAND: praise*
2568 **
2569 ** Usage: %fossil annotate|blame|praise ?OPTIONS? FILENAME
2570 **
2571 ** Output the text of a file with markings to show when each line of the file
2572 ** was last modified. The version currently checked out is shown by default.
@@ -2596,11 +2596,11 @@
2596 ** root of the repository. Set to "trunk" or
2597 ** similar for a reverse annotation.
2598 ** -w|--ignore-all-space Ignore white space when comparing lines
2599 ** -Z|--ignore-trailing-space Ignore whitespace at line end
2600 **
2601 ** See also: [[info]], [[finfo]], [[timeline]]
2602 */
2603 void annotate_cmd(void){
2604 const char *zRevision; /* Revision name, or NULL for current check-in */
2605 Annotator ann; /* The annotation of the file */
2606 int i; /* Loop counter */
2607
+80 -8
--- src/dispatch.c
+++ src/dispatch.c
@@ -263,10 +263,48 @@
263263
if( zEnd[0] ) blob_append(pOut, zEnd, -1);
264264
i = j;
265265
}
266266
}
267267
}
268
+
269
+/*
270
+** Input string zIn starts with '['. If the content is a hyperlink of the
271
+** form [[...]] then return the index of the closing ']'. Otherwise return 0.
272
+*/
273
+static int help_is_link(const char *z, int n){
274
+ int i;
275
+ char c;
276
+ if( n<5 ) return 0;
277
+ if( z[1]!='[' ) return 0;
278
+ for(i=3; i<n && (c = z[i])!=0; i++){
279
+ if( c==']' && z[i-1]==']' ) return i;
280
+ }
281
+ return 0;
282
+}
283
+
284
+/*
285
+** Append text to pOut, adding hyperlink markup for [...].
286
+*/
287
+static void appendLinked(Blob *pOut, const char *z, int n){
288
+ int i = 0;
289
+ int j;
290
+ while( i<n ){
291
+ if( z[i]=='[' && (j = help_is_link(z+i, n-i))>0 ){
292
+ if( i ) blob_append(pOut, z, i);
293
+ z += i+2;
294
+ n -= i+2;
295
+ blob_appendf(pOut, "<a href='%R/help?cmd=%.*s'>%.*s</a>",
296
+ j-3, z, j-3, z);
297
+ z += j-1;
298
+ n -= j-1;
299
+ i = 0;
300
+ }else{
301
+ i++;
302
+ }
303
+ }
304
+ blob_append(pOut, z, i);
305
+}
268306
269307
/*
270308
** Attempt to reformat plain-text help into HTML for display on a webpage.
271309
**
272310
** The HTML output is appended to Blob pHtml, which should already be
@@ -305,17 +343,22 @@
305343
azEnd[0] = "";
306344
while( zHelp[0] ){
307345
i = 0;
308346
while( (c = zHelp[i])!=0
309347
&& c!='\n'
348
+ && c!='<'
310349
&& (c!='%' || strncmp(zHelp+i,"%fossil",7)!=0)
311350
){ i++; }
312351
if( c=='%' ){
313352
if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
314353
zHelp += i + 1;
315
- i = 0;
316354
wantBR = 1;
355
+ continue;
356
+ }else if( c=='<' ){
357
+ if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
358
+ blob_append(pHtml, "&amp;", 5);
359
+ zHelp += i + 1;
317360
continue;
318361
}
319362
if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
320363
isDT = 1;
321364
for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
@@ -394,11 +437,12 @@
394437
}else if( wantBR ){
395438
appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);
396439
blob_append(pHtml, "<br>\n", 5);
397440
wantBR = 0;
398441
}else{
399
- blob_appendf(pHtml, "%#h\n", i-nIndent, zHelp+nIndent);
442
+ appendLinked(pHtml, zHelp+nIndent, i-nIndent);
443
+ blob_append_char(pHtml, '\n');
400444
}
401445
zHelp += i+1;
402446
i = 0;
403447
if( c==0 ) break;
404448
}
@@ -409,11 +453,11 @@
409453
410454
/*
411455
** Format help text for TTY display.
412456
*/
413457
static void help_to_text(const char *zHelp, Blob *pText){
414
- int i;
458
+ int i, x;
415459
char c;
416460
for(i=0; (c = zHelp[i])!=0; i++){
417461
if( c=='%' && strncmp(zHelp+i,"%fossil",7)==0 ){
418462
if( i>0 ) blob_append(pText, zHelp, i);
419463
blob_append(pText, "fossil", 6);
@@ -426,10 +470,18 @@
426470
blob_append(pText, " ", 1);
427471
zHelp += i+2;
428472
i = -1;
429473
continue;
430474
}
475
+ if( c=='[' && (x = help_is_link(zHelp+i, 100000))!=0 ){
476
+ if( i>0 ) blob_append(pText, zHelp, i);
477
+ zHelp += i+2;
478
+ blob_append(pText, zHelp, x-3);
479
+ zHelp += x-1;
480
+ i = -1;
481
+ continue;
482
+ }
431483
}
432484
if( i>0 ){
433485
blob_append(pText, zHelp, i);
434486
}
435487
}
@@ -447,15 +499,17 @@
447499
** -e|--everything Show all commands and pages.
448500
** -t|--test Include test- commands
449501
** -w|--www Show WWW pages.
450502
** -s|--settings Show settings.
451503
** -h|--html Transform output to HTML.
504
+** -r|--raw No output formatting.
452505
*/
453506
void test_all_help_cmd(void){
454507
int i;
455508
int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
456509
int useHtml = find_option("html","h",0)!=0;
510
+ int rawOut = find_option("raw","r",0)!=0;
457511
458512
if( find_option("www","w",0) ){
459513
mask = CMDFLAG_WEBPAGE;
460514
}
461515
if( find_option("everything","e",0) ){
@@ -488,10 +542,13 @@
488542
blob_init(&html, 0, 0);
489543
help_to_html(aCommand[i].zHelp, &html);
490544
fossil_print("<h1>%h</h1>\n", aCommand[i].zName);
491545
fossil_print("%s\n<hr>\n", blob_str(&html));
492546
blob_reset(&html);
547
+ }else if( rawOut ){
548
+ fossil_print("# %s\n", aCommand[i].zName);
549
+ fossil_print("%s\n\n", aCommand[i].zHelp);
493550
}else{
494551
Blob txt;
495552
blob_init(&txt, 0, 0);
496553
help_to_text(aCommand[i].zHelp, &txt);
497554
fossil_print("# %s\n", aCommand[i].zName);
@@ -665,11 +722,11 @@
665722
const CmdOrPage *pCmd = 0;
666723
667724
style_header("Help: %s", zCmd);
668725
669726
style_submenu_element("Command-List", "%s/help", g.zTop);
670
- rc = dispatch_name_search(zCmd, CMDFLAG_ANY, &pCmd);
727
+ rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
671728
if( *zCmd=='/' ){
672729
/* Some of the webpages require query parameters in order to work.
673730
** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
674731
@ <h1>The "%h(zCmd)" page:</h1>
675732
}else if( rc==0 && (pCmd->eCmdFlags & CMDFLAG_SETTING)!=0 ){
@@ -913,11 +970,11 @@
913970
** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
914971
** topics is returned.
915972
**
916973
** The following options can be used when TOPIC is omitted:
917974
**
918
-** -a|--all List both command and auxiliary commands
975
+** -a|--all List both common and auxiliary commands
919976
** -o|--options List command-line options common to all commands
920977
** -s|--setting List setting names
921978
** -t|--test List unsupported "test" commands
922979
** -x|--aux List only auxiliary commands
923980
** -w|--www List all web pages
@@ -936,12 +993,13 @@
936993
Blob txt;
937994
if( g.argc<3 ){
938995
z = g.argv[0];
939996
fossil_print(
940997
"Usage: %s help TOPIC\n"
941
- "Common commands: (use \"%s help help\" for more options)\n",
942
- z, z);
998
+ "Try \"%s help help\" or \"%s help -a\" for more options\n"
999
+ "Frequently used commands:\n",
1000
+ z, z, z);
9431001
command_list(0, CMDFLAG_1ST_TIER);
9441002
version_cmd();
9451003
return;
9461004
}
9471005
if( find_option("options","o",0) ){
@@ -1076,11 +1134,11 @@
10761134
){
10771135
helptextVtab_vtab *pNew;
10781136
int rc;
10791137
10801138
rc = sqlite3_declare_vtab(db,
1081
- "CREATE TABLE x(name,type,flags,helptext)"
1139
+ "CREATE TABLE x(name,type,flags,helptext,formatted,html)"
10821140
);
10831141
if( rc==SQLITE_OK ){
10841142
pNew = sqlite3_malloc( sizeof(*pNew) );
10851143
*ppVtab = (sqlite3_vtab*)pNew;
10861144
if( pNew==0 ) return SQLITE_NOMEM;
@@ -1160,10 +1218,24 @@
11601218
sqlite3_result_int(ctx, pPage->eCmdFlags);
11611219
break;
11621220
case 3: /* helptext */
11631221
sqlite3_result_text(ctx, pPage->zHelp, -1, SQLITE_STATIC);
11641222
break;
1223
+ case 4: { /* formatted */
1224
+ Blob txt;
1225
+ blob_init(&txt, 0, 0);
1226
+ help_to_text(pPage->zHelp, &txt);
1227
+ sqlite3_result_text(ctx, blob_str(&txt), -1, fossil_free);
1228
+ break;
1229
+ }
1230
+ case 5: { /* formatted */
1231
+ Blob txt;
1232
+ blob_init(&txt, 0, 0);
1233
+ help_to_html(pPage->zHelp, &txt);
1234
+ sqlite3_result_text(ctx, blob_str(&txt), -1, fossil_free);
1235
+ break;
1236
+ }
11651237
}
11661238
return SQLITE_OK;
11671239
}
11681240
11691241
/*
11701242
--- src/dispatch.c
+++ src/dispatch.c
@@ -263,10 +263,48 @@
263 if( zEnd[0] ) blob_append(pOut, zEnd, -1);
264 i = j;
265 }
266 }
267 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
269 /*
270 ** Attempt to reformat plain-text help into HTML for display on a webpage.
271 **
272 ** The HTML output is appended to Blob pHtml, which should already be
@@ -305,17 +343,22 @@
305 azEnd[0] = "";
306 while( zHelp[0] ){
307 i = 0;
308 while( (c = zHelp[i])!=0
309 && c!='\n'
 
310 && (c!='%' || strncmp(zHelp+i,"%fossil",7)!=0)
311 ){ i++; }
312 if( c=='%' ){
313 if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
314 zHelp += i + 1;
315 i = 0;
316 wantBR = 1;
 
 
 
 
 
317 continue;
318 }
319 if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
320 isDT = 1;
321 for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
@@ -394,11 +437,12 @@
394 }else if( wantBR ){
395 appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);
396 blob_append(pHtml, "<br>\n", 5);
397 wantBR = 0;
398 }else{
399 blob_appendf(pHtml, "%#h\n", i-nIndent, zHelp+nIndent);
 
400 }
401 zHelp += i+1;
402 i = 0;
403 if( c==0 ) break;
404 }
@@ -409,11 +453,11 @@
409
410 /*
411 ** Format help text for TTY display.
412 */
413 static void help_to_text(const char *zHelp, Blob *pText){
414 int i;
415 char c;
416 for(i=0; (c = zHelp[i])!=0; i++){
417 if( c=='%' && strncmp(zHelp+i,"%fossil",7)==0 ){
418 if( i>0 ) blob_append(pText, zHelp, i);
419 blob_append(pText, "fossil", 6);
@@ -426,10 +470,18 @@
426 blob_append(pText, " ", 1);
427 zHelp += i+2;
428 i = -1;
429 continue;
430 }
 
 
 
 
 
 
 
 
431 }
432 if( i>0 ){
433 blob_append(pText, zHelp, i);
434 }
435 }
@@ -447,15 +499,17 @@
447 ** -e|--everything Show all commands and pages.
448 ** -t|--test Include test- commands
449 ** -w|--www Show WWW pages.
450 ** -s|--settings Show settings.
451 ** -h|--html Transform output to HTML.
 
452 */
453 void test_all_help_cmd(void){
454 int i;
455 int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
456 int useHtml = find_option("html","h",0)!=0;
 
457
458 if( find_option("www","w",0) ){
459 mask = CMDFLAG_WEBPAGE;
460 }
461 if( find_option("everything","e",0) ){
@@ -488,10 +542,13 @@
488 blob_init(&html, 0, 0);
489 help_to_html(aCommand[i].zHelp, &html);
490 fossil_print("<h1>%h</h1>\n", aCommand[i].zName);
491 fossil_print("%s\n<hr>\n", blob_str(&html));
492 blob_reset(&html);
 
 
 
493 }else{
494 Blob txt;
495 blob_init(&txt, 0, 0);
496 help_to_text(aCommand[i].zHelp, &txt);
497 fossil_print("# %s\n", aCommand[i].zName);
@@ -665,11 +722,11 @@
665 const CmdOrPage *pCmd = 0;
666
667 style_header("Help: %s", zCmd);
668
669 style_submenu_element("Command-List", "%s/help", g.zTop);
670 rc = dispatch_name_search(zCmd, CMDFLAG_ANY, &pCmd);
671 if( *zCmd=='/' ){
672 /* Some of the webpages require query parameters in order to work.
673 ** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
674 @ <h1>The "%h(zCmd)" page:</h1>
675 }else if( rc==0 && (pCmd->eCmdFlags & CMDFLAG_SETTING)!=0 ){
@@ -913,11 +970,11 @@
913 ** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
914 ** topics is returned.
915 **
916 ** The following options can be used when TOPIC is omitted:
917 **
918 ** -a|--all List both command and auxiliary commands
919 ** -o|--options List command-line options common to all commands
920 ** -s|--setting List setting names
921 ** -t|--test List unsupported "test" commands
922 ** -x|--aux List only auxiliary commands
923 ** -w|--www List all web pages
@@ -936,12 +993,13 @@
936 Blob txt;
937 if( g.argc<3 ){
938 z = g.argv[0];
939 fossil_print(
940 "Usage: %s help TOPIC\n"
941 "Common commands: (use \"%s help help\" for more options)\n",
942 z, z);
 
943 command_list(0, CMDFLAG_1ST_TIER);
944 version_cmd();
945 return;
946 }
947 if( find_option("options","o",0) ){
@@ -1076,11 +1134,11 @@
1076 ){
1077 helptextVtab_vtab *pNew;
1078 int rc;
1079
1080 rc = sqlite3_declare_vtab(db,
1081 "CREATE TABLE x(name,type,flags,helptext)"
1082 );
1083 if( rc==SQLITE_OK ){
1084 pNew = sqlite3_malloc( sizeof(*pNew) );
1085 *ppVtab = (sqlite3_vtab*)pNew;
1086 if( pNew==0 ) return SQLITE_NOMEM;
@@ -1160,10 +1218,24 @@
1160 sqlite3_result_int(ctx, pPage->eCmdFlags);
1161 break;
1162 case 3: /* helptext */
1163 sqlite3_result_text(ctx, pPage->zHelp, -1, SQLITE_STATIC);
1164 break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1165 }
1166 return SQLITE_OK;
1167 }
1168
1169 /*
1170
--- src/dispatch.c
+++ src/dispatch.c
@@ -263,10 +263,48 @@
263 if( zEnd[0] ) blob_append(pOut, zEnd, -1);
264 i = j;
265 }
266 }
267 }
268
269 /*
270 ** Input string zIn starts with '['. If the content is a hyperlink of the
271 ** form [[...]] then return the index of the closing ']'. Otherwise return 0.
272 */
273 static int help_is_link(const char *z, int n){
274 int i;
275 char c;
276 if( n<5 ) return 0;
277 if( z[1]!='[' ) return 0;
278 for(i=3; i<n && (c = z[i])!=0; i++){
279 if( c==']' && z[i-1]==']' ) return i;
280 }
281 return 0;
282 }
283
284 /*
285 ** Append text to pOut, adding hyperlink markup for [...].
286 */
287 static void appendLinked(Blob *pOut, const char *z, int n){
288 int i = 0;
289 int j;
290 while( i<n ){
291 if( z[i]=='[' && (j = help_is_link(z+i, n-i))>0 ){
292 if( i ) blob_append(pOut, z, i);
293 z += i+2;
294 n -= i+2;
295 blob_appendf(pOut, "<a href='%R/help?cmd=%.*s'>%.*s</a>",
296 j-3, z, j-3, z);
297 z += j-1;
298 n -= j-1;
299 i = 0;
300 }else{
301 i++;
302 }
303 }
304 blob_append(pOut, z, i);
305 }
306
307 /*
308 ** Attempt to reformat plain-text help into HTML for display on a webpage.
309 **
310 ** The HTML output is appended to Blob pHtml, which should already be
@@ -305,17 +343,22 @@
343 azEnd[0] = "";
344 while( zHelp[0] ){
345 i = 0;
346 while( (c = zHelp[i])!=0
347 && c!='\n'
348 && c!='<'
349 && (c!='%' || strncmp(zHelp+i,"%fossil",7)!=0)
350 ){ i++; }
351 if( c=='%' ){
352 if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
353 zHelp += i + 1;
 
354 wantBR = 1;
355 continue;
356 }else if( c=='<' ){
357 if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
358 blob_append(pHtml, "&amp;", 5);
359 zHelp += i + 1;
360 continue;
361 }
362 if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
363 isDT = 1;
364 for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
@@ -394,11 +437,12 @@
437 }else if( wantBR ){
438 appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);
439 blob_append(pHtml, "<br>\n", 5);
440 wantBR = 0;
441 }else{
442 appendLinked(pHtml, zHelp+nIndent, i-nIndent);
443 blob_append_char(pHtml, '\n');
444 }
445 zHelp += i+1;
446 i = 0;
447 if( c==0 ) break;
448 }
@@ -409,11 +453,11 @@
453
454 /*
455 ** Format help text for TTY display.
456 */
457 static void help_to_text(const char *zHelp, Blob *pText){
458 int i, x;
459 char c;
460 for(i=0; (c = zHelp[i])!=0; i++){
461 if( c=='%' && strncmp(zHelp+i,"%fossil",7)==0 ){
462 if( i>0 ) blob_append(pText, zHelp, i);
463 blob_append(pText, "fossil", 6);
@@ -426,10 +470,18 @@
470 blob_append(pText, " ", 1);
471 zHelp += i+2;
472 i = -1;
473 continue;
474 }
475 if( c=='[' && (x = help_is_link(zHelp+i, 100000))!=0 ){
476 if( i>0 ) blob_append(pText, zHelp, i);
477 zHelp += i+2;
478 blob_append(pText, zHelp, x-3);
479 zHelp += x-1;
480 i = -1;
481 continue;
482 }
483 }
484 if( i>0 ){
485 blob_append(pText, zHelp, i);
486 }
487 }
@@ -447,15 +499,17 @@
499 ** -e|--everything Show all commands and pages.
500 ** -t|--test Include test- commands
501 ** -w|--www Show WWW pages.
502 ** -s|--settings Show settings.
503 ** -h|--html Transform output to HTML.
504 ** -r|--raw No output formatting.
505 */
506 void test_all_help_cmd(void){
507 int i;
508 int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
509 int useHtml = find_option("html","h",0)!=0;
510 int rawOut = find_option("raw","r",0)!=0;
511
512 if( find_option("www","w",0) ){
513 mask = CMDFLAG_WEBPAGE;
514 }
515 if( find_option("everything","e",0) ){
@@ -488,10 +542,13 @@
542 blob_init(&html, 0, 0);
543 help_to_html(aCommand[i].zHelp, &html);
544 fossil_print("<h1>%h</h1>\n", aCommand[i].zName);
545 fossil_print("%s\n<hr>\n", blob_str(&html));
546 blob_reset(&html);
547 }else if( rawOut ){
548 fossil_print("# %s\n", aCommand[i].zName);
549 fossil_print("%s\n\n", aCommand[i].zHelp);
550 }else{
551 Blob txt;
552 blob_init(&txt, 0, 0);
553 help_to_text(aCommand[i].zHelp, &txt);
554 fossil_print("# %s\n", aCommand[i].zName);
@@ -665,11 +722,11 @@
722 const CmdOrPage *pCmd = 0;
723
724 style_header("Help: %s", zCmd);
725
726 style_submenu_element("Command-List", "%s/help", g.zTop);
727 rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
728 if( *zCmd=='/' ){
729 /* Some of the webpages require query parameters in order to work.
730 ** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
731 @ <h1>The "%h(zCmd)" page:</h1>
732 }else if( rc==0 && (pCmd->eCmdFlags & CMDFLAG_SETTING)!=0 ){
@@ -913,11 +970,11 @@
970 ** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
971 ** topics is returned.
972 **
973 ** The following options can be used when TOPIC is omitted:
974 **
975 ** -a|--all List both common and auxiliary commands
976 ** -o|--options List command-line options common to all commands
977 ** -s|--setting List setting names
978 ** -t|--test List unsupported "test" commands
979 ** -x|--aux List only auxiliary commands
980 ** -w|--www List all web pages
@@ -936,12 +993,13 @@
993 Blob txt;
994 if( g.argc<3 ){
995 z = g.argv[0];
996 fossil_print(
997 "Usage: %s help TOPIC\n"
998 "Try \"%s help help\" or \"%s help -a\" for more options\n"
999 "Frequently used commands:\n",
1000 z, z, z);
1001 command_list(0, CMDFLAG_1ST_TIER);
1002 version_cmd();
1003 return;
1004 }
1005 if( find_option("options","o",0) ){
@@ -1076,11 +1134,11 @@
1134 ){
1135 helptextVtab_vtab *pNew;
1136 int rc;
1137
1138 rc = sqlite3_declare_vtab(db,
1139 "CREATE TABLE x(name,type,flags,helptext,formatted,html)"
1140 );
1141 if( rc==SQLITE_OK ){
1142 pNew = sqlite3_malloc( sizeof(*pNew) );
1143 *ppVtab = (sqlite3_vtab*)pNew;
1144 if( pNew==0 ) return SQLITE_NOMEM;
@@ -1160,10 +1218,24 @@
1218 sqlite3_result_int(ctx, pPage->eCmdFlags);
1219 break;
1220 case 3: /* helptext */
1221 sqlite3_result_text(ctx, pPage->zHelp, -1, SQLITE_STATIC);
1222 break;
1223 case 4: { /* formatted */
1224 Blob txt;
1225 blob_init(&txt, 0, 0);
1226 help_to_text(pPage->zHelp, &txt);
1227 sqlite3_result_text(ctx, blob_str(&txt), -1, fossil_free);
1228 break;
1229 }
1230 case 5: { /* formatted */
1231 Blob txt;
1232 blob_init(&txt, 0, 0);
1233 help_to_html(pPage->zHelp, &txt);
1234 sqlite3_result_text(ctx, blob_str(&txt), -1, fossil_free);
1235 break;
1236 }
1237 }
1238 return SQLITE_OK;
1239 }
1240
1241 /*
1242
+16 -11
--- src/doc.c
+++ src/doc.c
@@ -147,11 +147,11 @@
147147
{ "jad", 3, "text/vnd.sun.j2me.app-descriptor" },
148148
{ "jar", 3, "application/java-archive" },
149149
{ "jpe", 3, "image/jpeg" },
150150
{ "jpeg", 4, "image/jpeg" },
151151
{ "jpg", 3, "image/jpeg" },
152
- { "js", 2, "application/x-javascript" },
152
+ { "js", 2, "application/javascript" },
153153
{ "kar", 3, "audio/midi" },
154154
{ "latex", 5, "application/x-latex" },
155155
{ "lha", 3, "application/octet-stream" },
156156
{ "lsp", 3, "application/x-lisp" },
157157
{ "lzh", 3, "application/octet-stream" },
@@ -1132,29 +1132,34 @@
11321132
11331133
11341134
/*
11351135
** WEBPAGE: favicon.ico
11361136
**
1137
-** Return the default favicon.ico image. The returned image is for the
1138
-** Fossil lizard icon.
1137
+** Return the configured "favicon.ico" image. If no "favicon.ico" image
1138
+** is defined, the returned image is for the Fossil lizard icon.
11391139
**
1140
-** The intended use case here is to supply a favicon for the "fossil ui"
1140
+** The intended use case here is to supply an icon for the "fossil ui"
11411141
** command. For a permanent website, the recommended process is for
1142
-** the admin to set up a project-specific favicon and reference that
1143
-** icon in the HTML header using a line like:
1142
+** the admin to set up a project-specific icon and reference that icon
1143
+** in the HTML header using a line like:
11441144
**
11451145
** <link rel="icon" href="URL-FOR-YOUR-ICON" type="MIMETYPE"/>
11461146
**
11471147
*/
11481148
void favicon_page(void){
1149
- Blob favicon;
1149
+ Blob icon;
1150
+ char *zMime;
11501151
11511152
etag_check(ETAG_CONFIG, 0);
1152
- blob_zero(&favicon);
1153
- blob_init(&favicon, (char*)aLogo, sizeof(aLogo));
1154
- cgi_set_content_type("image/gif");
1155
- cgi_set_content(&favicon);
1153
+ zMime = db_get("icon-mimetype", "image/gif");
1154
+ blob_zero(&icon);
1155
+ db_blob(&icon, "SELECT value FROM config WHERE name='icon-image'");
1156
+ if( blob_size(&icon)==0 ){
1157
+ blob_init(&icon, (char*)aLogo, sizeof(aLogo));
1158
+ }
1159
+ cgi_set_content_type(zMime);
1160
+ cgi_set_content(&icon);
11561161
}
11571162
11581163
/*
11591164
** WEBPAGE: docsrch
11601165
**
11611166
--- src/doc.c
+++ src/doc.c
@@ -147,11 +147,11 @@
147 { "jad", 3, "text/vnd.sun.j2me.app-descriptor" },
148 { "jar", 3, "application/java-archive" },
149 { "jpe", 3, "image/jpeg" },
150 { "jpeg", 4, "image/jpeg" },
151 { "jpg", 3, "image/jpeg" },
152 { "js", 2, "application/x-javascript" },
153 { "kar", 3, "audio/midi" },
154 { "latex", 5, "application/x-latex" },
155 { "lha", 3, "application/octet-stream" },
156 { "lsp", 3, "application/x-lisp" },
157 { "lzh", 3, "application/octet-stream" },
@@ -1132,29 +1132,34 @@
1132
1133
1134 /*
1135 ** WEBPAGE: favicon.ico
1136 **
1137 ** Return the default favicon.ico image. The returned image is for the
1138 ** Fossil lizard icon.
1139 **
1140 ** The intended use case here is to supply a favicon for the "fossil ui"
1141 ** command. For a permanent website, the recommended process is for
1142 ** the admin to set up a project-specific favicon and reference that
1143 ** icon in the HTML header using a line like:
1144 **
1145 ** <link rel="icon" href="URL-FOR-YOUR-ICON" type="MIMETYPE"/>
1146 **
1147 */
1148 void favicon_page(void){
1149 Blob favicon;
 
1150
1151 etag_check(ETAG_CONFIG, 0);
1152 blob_zero(&favicon);
1153 blob_init(&favicon, (char*)aLogo, sizeof(aLogo));
1154 cgi_set_content_type("image/gif");
1155 cgi_set_content(&favicon);
 
 
 
 
1156 }
1157
1158 /*
1159 ** WEBPAGE: docsrch
1160 **
1161
--- src/doc.c
+++ src/doc.c
@@ -147,11 +147,11 @@
147 { "jad", 3, "text/vnd.sun.j2me.app-descriptor" },
148 { "jar", 3, "application/java-archive" },
149 { "jpe", 3, "image/jpeg" },
150 { "jpeg", 4, "image/jpeg" },
151 { "jpg", 3, "image/jpeg" },
152 { "js", 2, "application/javascript" },
153 { "kar", 3, "audio/midi" },
154 { "latex", 5, "application/x-latex" },
155 { "lha", 3, "application/octet-stream" },
156 { "lsp", 3, "application/x-lisp" },
157 { "lzh", 3, "application/octet-stream" },
@@ -1132,29 +1132,34 @@
1132
1133
1134 /*
1135 ** WEBPAGE: favicon.ico
1136 **
1137 ** Return the configured "favicon.ico" image. If no "favicon.ico" image
1138 ** is defined, the returned image is for the Fossil lizard icon.
1139 **
1140 ** The intended use case here is to supply an icon for the "fossil ui"
1141 ** command. For a permanent website, the recommended process is for
1142 ** the admin to set up a project-specific icon and reference that icon
1143 ** in the HTML header using a line like:
1144 **
1145 ** <link rel="icon" href="URL-FOR-YOUR-ICON" type="MIMETYPE"/>
1146 **
1147 */
1148 void favicon_page(void){
1149 Blob icon;
1150 char *zMime;
1151
1152 etag_check(ETAG_CONFIG, 0);
1153 zMime = db_get("icon-mimetype", "image/gif");
1154 blob_zero(&icon);
1155 db_blob(&icon, "SELECT value FROM config WHERE name='icon-image'");
1156 if( blob_size(&icon)==0 ){
1157 blob_init(&icon, (char*)aLogo, sizeof(aLogo));
1158 }
1159 cgi_set_content_type(zMime);
1160 cgi_set_content(&icon);
1161 }
1162
1163 /*
1164 ** WEBPAGE: docsrch
1165 **
1166
+4 -1
--- src/etag.c
+++ src/etag.c
@@ -97,11 +97,14 @@
9797
const char *zIfNoneMatch;
9898
char zBuf[50];
9999
assert( zETag[0]==0 ); /* Only call this routine once! */
100100
101101
if( etagCancelled ) return;
102
- iMaxAge = 86400;
102
+
103
+ /* By default, ETagged URLs never expire since the ETag will change
104
+ * when the content changes. Approximate this policy as 10 years. */
105
+ iMaxAge = 10 * 365 * 24 * 60 * 60;
103106
md5sum_init();
104107
105108
/* Always include the executable ID as part of the hash */
106109
md5sum_step_text("exe-id: ", -1);
107110
md5sum_step_text(fossil_exe_id(), -1);
108111
--- src/etag.c
+++ src/etag.c
@@ -97,11 +97,14 @@
97 const char *zIfNoneMatch;
98 char zBuf[50];
99 assert( zETag[0]==0 ); /* Only call this routine once! */
100
101 if( etagCancelled ) return;
102 iMaxAge = 86400;
 
 
 
103 md5sum_init();
104
105 /* Always include the executable ID as part of the hash */
106 md5sum_step_text("exe-id: ", -1);
107 md5sum_step_text(fossil_exe_id(), -1);
108
--- src/etag.c
+++ src/etag.c
@@ -97,11 +97,14 @@
97 const char *zIfNoneMatch;
98 char zBuf[50];
99 assert( zETag[0]==0 ); /* Only call this routine once! */
100
101 if( etagCancelled ) return;
102
103 /* By default, ETagged URLs never expire since the ETag will change
104 * when the content changes. Approximate this policy as 10 years. */
105 iMaxAge = 10 * 365 * 24 * 60 * 60;
106 md5sum_init();
107
108 /* Always include the executable ID as part of the hash */
109 md5sum_step_text("exe-id: ", -1);
110 md5sum_step_text(fossil_exe_id(), -1);
111
+1 -1
--- src/export.c
+++ src/export.c
@@ -1642,11 +1642,11 @@
16421642
k = db_int(0, "SELECT count(*) FROm mmark WHERE NOT isfile");
16431643
fossil_print("Exported: %d check-ins and %d file blobs\n", k, n);
16441644
}
16451645
16461646
/*
1647
-** COMMAND: git
1647
+** COMMAND: git*
16481648
**
16491649
** Usage: %fossil git SUBCOMMAND
16501650
**
16511651
** Do incremental import or export operations between Fossil and Git.
16521652
** Subcommands:
16531653
--- src/export.c
+++ src/export.c
@@ -1642,11 +1642,11 @@
1642 k = db_int(0, "SELECT count(*) FROm mmark WHERE NOT isfile");
1643 fossil_print("Exported: %d check-ins and %d file blobs\n", k, n);
1644 }
1645
1646 /*
1647 ** COMMAND: git
1648 **
1649 ** Usage: %fossil git SUBCOMMAND
1650 **
1651 ** Do incremental import or export operations between Fossil and Git.
1652 ** Subcommands:
1653
--- src/export.c
+++ src/export.c
@@ -1642,11 +1642,11 @@
1642 k = db_int(0, "SELECT count(*) FROm mmark WHERE NOT isfile");
1643 fossil_print("Exported: %d check-ins and %d file blobs\n", k, n);
1644 }
1645
1646 /*
1647 ** COMMAND: git*
1648 **
1649 ** Usage: %fossil git SUBCOMMAND
1650 **
1651 ** Do incremental import or export operations between Fossil and Git.
1652 ** Subcommands:
1653
+26
--- src/file.c
+++ src/file.c
@@ -1105,10 +1105,12 @@
11051105
** Remove redundant / characters
11061106
** Remove all /./ path elements.
11071107
** Convert /A/../ to just /
11081108
** If the slash parameter is non-zero, the trailing slash, if any,
11091109
** is retained.
1110
+**
1111
+** See also: file_canonical_name_dup()
11101112
*/
11111113
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
11121114
blob_zero(pOut);
11131115
if( file_is_absolute_path(zOrigName) ){
11141116
blob_appendf(pOut, "%/", zOrigName);
@@ -1140,10 +1142,25 @@
11401142
}
11411143
#endif
11421144
blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
11431145
blob_size(pOut), slash));
11441146
}
1147
+
1148
+/*
1149
+** Compute the canonical name of a file. Store that name in
1150
+** memory obtained from fossil_malloc() and return a pointer to the
1151
+** name.
1152
+**
1153
+** See also: file_canonical_name()
1154
+*/
1155
+char *file_canonical_name_dup(const char *zOrigName){
1156
+ Blob x;
1157
+ if( zOrigName==0 ) return 0;
1158
+ blob_init(&x, 0, 0);
1159
+ file_canonical_name(zOrigName, &x, 0);
1160
+ return blob_str(&x);
1161
+}
11451162
11461163
/*
11471164
** The input is the name of an executable, such as one might
11481165
** type on a command-line. This routine resolves that name into
11491166
** a full pathname. The result is obtained from fossil_malloc()
@@ -2380,5 +2397,14 @@
23802397
changeCount);
23812398
}else{
23822399
fossil_print("Touched %d file(s)\n", changeCount);
23832400
}
23842401
}
2402
+
2403
+/*
2404
+** If zFileName is not NULL and contains a '.', this returns a pointer
2405
+** to the position after the final '.', else it returns NULL.
2406
+*/
2407
+const char * file_extension(const char *zFileName){
2408
+ const char * zExt = strrchr(zFileName, '.');
2409
+ return zExt ? &zExt[1] : 0;
2410
+}
23852411
--- src/file.c
+++ src/file.c
@@ -1105,10 +1105,12 @@
1105 ** Remove redundant / characters
1106 ** Remove all /./ path elements.
1107 ** Convert /A/../ to just /
1108 ** If the slash parameter is non-zero, the trailing slash, if any,
1109 ** is retained.
 
 
1110 */
1111 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
1112 blob_zero(pOut);
1113 if( file_is_absolute_path(zOrigName) ){
1114 blob_appendf(pOut, "%/", zOrigName);
@@ -1140,10 +1142,25 @@
1140 }
1141 #endif
1142 blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
1143 blob_size(pOut), slash));
1144 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1145
1146 /*
1147 ** The input is the name of an executable, such as one might
1148 ** type on a command-line. This routine resolves that name into
1149 ** a full pathname. The result is obtained from fossil_malloc()
@@ -2380,5 +2397,14 @@
2380 changeCount);
2381 }else{
2382 fossil_print("Touched %d file(s)\n", changeCount);
2383 }
2384 }
 
 
 
 
 
 
 
 
 
2385
--- src/file.c
+++ src/file.c
@@ -1105,10 +1105,12 @@
1105 ** Remove redundant / characters
1106 ** Remove all /./ path elements.
1107 ** Convert /A/../ to just /
1108 ** If the slash parameter is non-zero, the trailing slash, if any,
1109 ** is retained.
1110 **
1111 ** See also: file_canonical_name_dup()
1112 */
1113 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
1114 blob_zero(pOut);
1115 if( file_is_absolute_path(zOrigName) ){
1116 blob_appendf(pOut, "%/", zOrigName);
@@ -1140,10 +1142,25 @@
1142 }
1143 #endif
1144 blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
1145 blob_size(pOut), slash));
1146 }
1147
1148 /*
1149 ** Compute the canonical name of a file. Store that name in
1150 ** memory obtained from fossil_malloc() and return a pointer to the
1151 ** name.
1152 **
1153 ** See also: file_canonical_name()
1154 */
1155 char *file_canonical_name_dup(const char *zOrigName){
1156 Blob x;
1157 if( zOrigName==0 ) return 0;
1158 blob_init(&x, 0, 0);
1159 file_canonical_name(zOrigName, &x, 0);
1160 return blob_str(&x);
1161 }
1162
1163 /*
1164 ** The input is the name of an executable, such as one might
1165 ** type on a command-line. This routine resolves that name into
1166 ** a full pathname. The result is obtained from fossil_malloc()
@@ -2380,5 +2397,14 @@
2397 changeCount);
2398 }else{
2399 fossil_print("Touched %d file(s)\n", changeCount);
2400 }
2401 }
2402
2403 /*
2404 ** If zFileName is not NULL and contains a '.', this returns a pointer
2405 ** to the position after the final '.', else it returns NULL.
2406 */
2407 const char * file_extension(const char *zFileName){
2408 const char * zExt = strrchr(zFileName, '.');
2409 return zExt ? &zExt[1] : 0;
2410 }
2411
+221 -144
--- src/fileedit.c
+++ src/fileedit.c
@@ -364,14 +364,10 @@
364364
blob_appendf(pOut, "B %s\n",
365365
pCI->pParent->zBaseline
366366
? pCI->pParent->zBaseline
367367
: pCI->zParentUuid);
368368
}
369
- blob_reserve(pOut, 1024 *
370
- (asDelta ? 2 : pCI->pParent->nFile/11+1
371
- /* In the fossil core repo, each 12-ish F-cards (on
372
- ** average) take up roughly 1kb */));
373369
if(blob_size(&pCI->comment)!=0){
374370
blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment));
375371
}else{
376372
blob_append(pOut, "C (no\\scomment)\n", 16);
377373
}
@@ -965,11 +961,12 @@
965961
** populates:
966962
**
967963
** - *zRevUuid = the fully-expanded value of zRev (owned by the
968964
** caller). zRevUuid may be NULL.
969965
**
970
-** - *vid = the RID of zRevUuid. May not be NULL.
966
+** - *pVid = the RID of zRevUuid. pVid May be NULL. If the vid
967
+** cannot be resolved or is ambiguous, pVid is not assigned.
971968
**
972969
** - *frid = the RID of zFilename's blob content. May not be NULL
973970
** unless zFilename is also NULL. If BOTH of zFilename and frid are
974971
** NULL then no confirmation is done on the filename argument - only
975972
** zRev is checked.
@@ -979,38 +976,41 @@
979976
** returns false, it queues up an error response and the caller must
980977
** return immediately.
981978
*/
982979
static int fileedit_ajax_setup_filerev(const char * zRev,
983980
char ** zRevUuid,
984
- int * vid,
981
+ int * pVid,
985982
const char * zFilename,
986983
int * frid){
987984
char * zFileUuid = 0; /* file content UUID */
988985
const int checkFile = zFilename!=0 || frid!=0;
986
+ int vid = 0;
989987
990988
if(checkFile && !fileedit_ajax_check_filename(zFilename)){
991989
return 0;
992990
}
993
- *vid = symbolic_name_to_rid(zRev, "ci");
994
- if(0==*vid){
991
+ vid = symbolic_name_to_rid(zRev, "ci");
992
+ if(0==vid){
995993
ajax_route_error(404,"Cannot resolve name as a checkin: %s",
996994
zRev);
997995
return 0;
998
- }else if(*vid<0){
996
+ }else if(vid<0){
999997
ajax_route_error(400,"Checkin name is ambiguous: %s",
1000998
zRev);
1001999
return 0;
1000
+ }else if(pVid!=0){
1001
+ *pVid = vid;
10021002
}
10031003
if(checkFile){
1004
- zFileUuid = fileedit_file_uuid(zFilename, *vid, 0);
1004
+ zFileUuid = fileedit_file_uuid(zFilename, vid, 0);
10051005
if(zFileUuid==0){
10061006
ajax_route_error(404, "Checkin does not contain file.");
10071007
return 0;
10081008
}
10091009
}
10101010
if(zRevUuid!=0){
1011
- *zRevUuid = rid_to_uuid(*vid);
1011
+ *zRevUuid = rid_to_uuid(vid);
10121012
}
10131013
if(checkFile){
10141014
assert(zFileUuid!=0);
10151015
if(frid!=0){
10161016
*frid = fast_uuid_to_rid(zFileUuid);
@@ -1290,10 +1290,92 @@
12901290
end_fail:
12911291
#undef fail
12921292
fossil_free(zFileUuid);
12931293
return rc ? rc : 500;
12941294
}
1295
+
1296
+/*
1297
+** Renders a list of all open leaves in JSON form:
1298
+**
1299
+** [
1300
+** {checkin: UUID, branch: branchName, timestamp: string}
1301
+** ]
1302
+**
1303
+** The entries are ordered newest first.
1304
+**
1305
+** If zFirstUuid is not NULL then *zFirstUuid is set to a copy of the
1306
+** full UUID of the first (most recent) leaf, which must be freed by
1307
+** the caller. It is set to 0 if there are no leaves.
1308
+*/
1309
+static void fileedit_render_leaves_list(char ** zFirstUuid){
1310
+ Blob sql = empty_blob;
1311
+ Stmt q = empty_Stmt;
1312
+ int i = 0;
1313
+
1314
+ if(zFirstUuid){
1315
+ *zFirstUuid = 0;
1316
+ }
1317
+ blob_append(&sql, timeline_query_for_tty(), -1);
1318
+ blob_append_sql(&sql, " AND blob.rid IN (SElECT rid FROM leaf "
1319
+ "WHERE NOT EXISTS("
1320
+ "SELECT 1 from tagxref WHERE tagid=%d AND "
1321
+ "tagtype>0 AND rid=leaf.rid"
1322
+ ")) "
1323
+ "ORDER BY mtime DESC", TAG_CLOSED);
1324
+ db_prepare_blob(&q, &sql);
1325
+ CX("[");
1326
+ while( SQLITE_ROW==db_step(&q) ){
1327
+ const char * zUuid = db_column_text(&q, 1);
1328
+ if(i++){
1329
+ CX(",");
1330
+ }else if(zFirstUuid){
1331
+ *zFirstUuid = fossil_strdup(zUuid);
1332
+ }
1333
+ CX("{");
1334
+ CX("\"checkin\":%!j,", zUuid);
1335
+ CX("\"branch\":%!j,", db_column_text(&q, 7));
1336
+ CX("\"timestamp\":%!j", db_column_text(&q, 2));
1337
+ CX("}");
1338
+ }
1339
+ CX("]");
1340
+ db_finalize(&q);
1341
+}
1342
+
1343
+/*
1344
+** For the given fully resolved UUID, renders a JSON object containing
1345
+** the fileeedit-editable files in that checkin:
1346
+**
1347
+** {
1348
+** checkin: UUID,
1349
+** editableFiles: [ filename1, ... filenameN ]
1350
+** }
1351
+**
1352
+** They are sorted by name using filename_collation().
1353
+*/
1354
+static void fileedit_render_checkin_files(const char * zFullUuid){
1355
+ Blob sql = empty_blob;
1356
+ Stmt q = empty_Stmt;
1357
+ int i = 0;
1358
+
1359
+ CX("{\"checkin\":%!j,"
1360
+ "\"editableFiles\":[", zFullUuid);
1361
+ blob_append_sql(&sql, "SELECT filename FROM files_of_checkin(%Q) "
1362
+ "ORDER BY filename %s",
1363
+ zFullUuid, filename_collation());
1364
+ db_prepare_blob(&q, &sql);
1365
+ while( SQLITE_ROW==db_step(&q) ){
1366
+ const char * zFilename = db_column_text(&q, 0);
1367
+ if(fileedit_is_editable(zFilename)){
1368
+ if(i++){
1369
+ CX(",");
1370
+ }
1371
+ CX("%!j", zFilename);
1372
+ }
1373
+ }
1374
+ db_finalize(&q);
1375
+ CX("]}");
1376
+}
12951377
12961378
/*
12971379
** AJAX route /fileedit?ajax=filelist
12981380
**
12991381
** Fetches a JSON-format list of leaves and/or filenames for use in
@@ -1318,66 +1400,27 @@
13181400
** }
13191401
**
13201402
** On error it produces a JSON response as documented for
13211403
** ajax_route_error().
13221404
*/
1323
-static void fileedit_ajax_filelist(void){
1405
+static void fileedit_ajax_filelist(){
13241406
const char * zCi = PD("checkin",P("ci"));
1325
- Blob sql = empty_blob;
1326
- Stmt q = empty_Stmt;
1327
- int i = 0;
13281407
13291408
if(!ajax_route_bootstrap(1,0)){
13301409
return;
13311410
}
13321411
cgi_set_content_type("application/json");
13331412
if(zCi!=0){
13341413
char * zCiFull = 0;
1335
- int vid = 0;
1336
- if(0==fileedit_ajax_setup_filerev(zCi, &zCiFull, &vid, 0, 0)){
1414
+ if(0==fileedit_ajax_setup_filerev(zCi, &zCiFull, 0, 0, 0)){
13371415
/* Error already reported */
13381416
return;
13391417
}
1340
- CX("{\"checkin\":%!j,"
1341
- "\"editableFiles\":[", zCiFull);
1342
- blob_append_sql(&sql, "SELECT filename FROM files_of_checkin(%Q) "
1343
- "ORDER BY filename %s",
1344
- zCiFull, filename_collation());
1345
- db_prepare_blob(&q, &sql);
1346
- while( SQLITE_ROW==db_step(&q) ){
1347
- const char * zFilename = db_column_text(&q, 0);
1348
- if(fileedit_is_editable(zFilename)){
1349
- if(i++){
1350
- CX(",");
1351
- }
1352
- CX("%!j", zFilename);
1353
- }
1354
- }
1355
- db_finalize(&q);
1356
- CX("]}");
1418
+ fileedit_render_checkin_files(zCiFull);
1419
+ fossil_free(zCiFull);
13571420
}else if(P("leaves")!=0){
1358
- blob_append(&sql, timeline_query_for_tty(), -1);
1359
- blob_append_sql(&sql, " AND blob.rid IN (SElECT rid FROM leaf "
1360
- "WHERE NOT EXISTS("
1361
- "SELECT 1 from tagxref WHERE tagid=%d AND "
1362
- "tagtype>0 AND rid=leaf.rid"
1363
- ")) "
1364
- "ORDER BY mtime DESC", TAG_CLOSED);
1365
- db_prepare_blob(&q, &sql);
1366
- CX("[");
1367
- while( SQLITE_ROW==db_step(&q) ){
1368
- if(i++){
1369
- CX(",");
1370
- }
1371
- CX("{");
1372
- CX("\"checkin\":%!j,", db_column_text(&q, 1));
1373
- CX("\"branch\":%!j,", db_column_text(&q, 7));
1374
- CX("\"timestamp\":%!j", db_column_text(&q, 2));
1375
- CX("}");
1376
- }
1377
- CX("]");
1378
- db_finalize(&q);
1421
+ fileedit_render_leaves_list(0);
13791422
}else{
13801423
ajax_route_error(500, "Unhandled URL argument.");
13811424
}
13821425
}
13831426
@@ -1484,52 +1527,60 @@
14841527
}
14851528
14861529
/*
14871530
** WEBPAGE: fileedit
14881531
**
1489
-** Enables the online editing and committing of individual text files.
1490
-** Requires that the user have Write permissions.
1532
+** Enables the online editing and committing of text files. Requires
1533
+** that the user have Write permissions and that a user with setup
1534
+** permissions has set the fileedit-glob setting to a list of glob
1535
+** patterns matching files which may be edited (e.g. "*.wiki,*.md").
1536
+** Note that fileedit-glob, by design, is a local-only setting.
1537
+** It does not sync across repository clones, and must be explicitly
1538
+** set on any repositories where this page should be activated.
14911539
**
14921540
** Optional query parameters:
14931541
**
14941542
** filename=FILENAME Repo-relative path to the file.
14951543
** checkin=VERSION Checkin version, using any unambiguous
1496
-** supported symbolic version name.
1497
-**
1498
-** Internal-use parameters:
1499
-**
1500
-** name=string The name of a page-specific AJAX operation.
1501
-**
1502
-** Noting that fossil internally stores all URL path components after
1503
-** the first as the "name" value. Thus /fileedit?name=blah is
1504
-** equivalent to /fileedit/blah. The latter is the preferred
1505
-** form. This means, however, that no fileedit ajax routes may make
1506
-** use of the name parameter.
1507
-**
1508
-** Which additional parameters are used by each distinct ajax value is
1509
-** an internal implementation detail and may change with any given
1510
-** build of this code. An unknown "name" value triggers an error, as
1511
-** documented for ajax_route_error().
1544
+** symbolic version name.
1545
+**
1546
+** If passed a filename but no checkin then it will attempt to
1547
+** load that file from the most recent leaf checkin.
1548
+**
1549
+** Once the page is loaded, files may be selected from any open leaf
1550
+** version. The only way to edit files from non-leaf checkins is to
1551
+** pass both the filename and checkin as URL parameters to the page.
1552
+** Users with the proper permissions will be presented with "Edit"
1553
+** links in various file-specific contexts for files which match the
1554
+** fileedit-glob, regardless of whether they refer to leaf versions or
1555
+** not.
15121556
*/
15131557
void fileedit_page(void){
1514
- const char * zFilename = 0; /* filename. We'll accept 'name'
1515
- because that param is handled
1516
- specially by the core. */
1517
- const char * zRev = 0; /* checkin version */
15181558
const char * zFileMime = 0; /* File mime type guess */
15191559
CheckinMiniInfo cimi; /* Checkin state */
15201560
int previewRenderMode = AJAX_RENDER_GUESS; /* preview mode */
15211561
Blob err = empty_blob; /* Error report */
1522
- Blob endScript = empty_blob; /* Script code to run at the
1523
- end. This content will be
1524
- combined into a single JS
1525
- function call, thus each
1526
- entry must end with a
1527
- semicolon. */
15281562
const char *zAjax = P("name"); /* Name of AJAX route for
15291563
sub-dispatching. */
15301564
1565
+ /*
1566
+ ** Internal-use URL parameters:
1567
+ **
1568
+ ** name=string The name of a page-specific AJAX operation.
1569
+ **
1570
+ ** Noting that fossil internally stores all URL path components
1571
+ ** after the first as the "name" value. Thus /fileedit?name=blah is
1572
+ ** equivalent to /fileedit/blah. The latter is the preferred
1573
+ ** form. This means, however, that no fileedit ajax routes may make
1574
+ ** use of the name parameter.
1575
+ **
1576
+ ** Which additional parameters are used by each distinct ajax route
1577
+ ** is an internal implementation detail and may change with any
1578
+ ** given build of this code. An unknown "name" value triggers an
1579
+ ** error, as documented for ajax_route_error().
1580
+ */
1581
+
15311582
/* Allow no access to this page without check-in privilege */
15321583
login_check_credentials();
15331584
if( !g.perm.Write ){
15341585
if(zAjax!=0){
15351586
ajax_route_error(403, "Write permissions required.");
@@ -1590,14 +1641,11 @@
15901641
** transaction cleanly.
15911642
*/
15921643
{
15931644
int isMissingArg = 0;
15941645
if(fileedit_setup_cimi_from_p(&cimi, &err, &isMissingArg)==0){
1595
- zFilename = cimi.zFilename;
1596
- zRev = cimi.zParentUuid;
1597
- assert(zRev);
1598
- assert(zFilename);
1646
+ assert(cimi.zFilename);
15991647
zFileMime = mimetype_from_name(cimi.zFilename);
16001648
}else if(isMissingArg!=0){
16011649
/* Squelch these startup warnings - they're non-fatal now but
16021650
** used to be fatal. */
16031651
blob_reset(&err);
@@ -1626,34 +1674,39 @@
16261674
/* Status bar */
16271675
CX("<div id='fossil-status-bar' "
16281676
"title='Status message area. Double-click to clear them.'>"
16291677
"Status messages will go here.</div>\n"
16301678
/* will be moved into the tab container via JS */);
1679
+
1680
+ CX("<div id='fileedit-edit-status'>"
1681
+ "<span class='name'>(no file loaded)</span>"
1682
+ "<span class='links'></span>"
1683
+ "</div>");
16311684
16321685
/* Main tab container... */
16331686
CX("<div id='fileedit-tabs' class='tab-container'></div>");
1687
+
1688
+ /* The .hidden class on the following tab elements is to help lessen
1689
+ the FOUC effect of the tabs before JS re-assembles them. */
16341690
16351691
/***** File/version info tab *****/
16361692
{
16371693
CX("<div id='fileedit-tab-fileselect' "
16381694
"data-tab-parent='fileedit-tabs' "
1639
- "data-tab-label='File Info &amp; Selection'"
1695
+ "data-tab-label='File Selection' "
1696
+ "class='hidden'"
16401697
">");
1641
- CX("<fieldset id='file-version-details'>"
1642
- "<legend>File/Version</legend>"
1643
- "<div>No file loaded.</div>"
1644
- "</fieldset>");
1645
- CX("<h1>Select a file to edit:</h1>");
16461698
CX("<div id='fileedit-file-selector'></div>");
16471699
CX("</div>"/*#fileedit-tab-fileselect*/);
16481700
}
16491701
16501702
/******* Content tab *******/
16511703
{
16521704
CX("<div id='fileedit-tab-content' "
16531705
"data-tab-parent='fileedit-tabs' "
1654
- "data-tab-label='File Content'"
1706
+ "data-tab-label='File Content' "
1707
+ "class='hidden'"
16551708
">");
16561709
CX("<div class='flex-container flex-row child-gap-small'>");
16571710
CX("<button class='fileedit-content-reload confirmer' "
16581711
"title='Reload the file from the server, discarding "
16591712
"any local edits. To help avoid accidental loss of "
@@ -1668,22 +1721,22 @@
16681721
"150%", 150, "175%", 175,
16691722
"200%", 200, NULL);
16701723
CX("</div>");
16711724
CX("<div class='flex-container flex-column stretch'>");
16721725
CX("<textarea name='content' id='fileedit-content-editor' "
1673
- "class='fileedit' "
1674
- "rows='20' cols='80'>");
1726
+ "class='fileedit' rows='25'>");
16751727
CX("</textarea>");
16761728
CX("</div>"/*textarea wrapper*/);
16771729
CX("</div>"/*#tab-file-content*/);
16781730
}
16791731
16801732
/****** Preview tab ******/
16811733
{
16821734
CX("<div id='fileedit-tab-preview' "
16831735
"data-tab-parent='fileedit-tabs' "
1684
- "data-tab-label='Preview'"
1736
+ "data-tab-label='Preview' "
1737
+ "class='hidden'"
16851738
">");
16861739
CX("<div class='fileedit-options flex-container flex-row'>");
16871740
CX("<button id='btn-preview-refresh' "
16881741
"data-f-preview-from='fileContent' "
16891742
/* ^^^ fossil.page[methodName]() OR text source elem ID,
@@ -1741,14 +1794,16 @@
17411794
17421795
/****** Diff tab ******/
17431796
{
17441797
CX("<div id='fileedit-tab-diff' "
17451798
"data-tab-parent='fileedit-tabs' "
1746
- "data-tab-label='Diff'"
1799
+ "data-tab-label='Diff' "
1800
+ "class='hidden'"
17471801
">");
17481802
1749
- CX("<div class='fileedit-options flex-container flex-row' "
1803
+ CX("<div class='fileedit-options flex-container "
1804
+ "flex-row child-gap-small' "
17501805
"id='fileedit-tab-diff-buttons'>");
17511806
CX("<button class='sbs'>Side-by-side</button>"
17521807
"<button class='unified'>Unified</button>");
17531808
if(0){
17541809
/* For the time being let's just ignore all whitespace
@@ -1773,11 +1828,12 @@
17731828
}
17741829
17751830
/****** Commit ******/
17761831
CX("<div id='fileedit-tab-commit' "
17771832
"data-tab-parent='fileedit-tabs' "
1778
- "data-tab-label='Commit'"
1833
+ "data-tab-label='Commit' "
1834
+ "class='hidden'"
17791835
">");
17801836
{
17811837
/******* Commit flags/options *******/
17821838
CX("<div class='fileedit-options flex-container flex-row'>");
17831839
style_labeled_checkbox("cb-dry-run",
@@ -1894,11 +1950,12 @@
18941950
CX("</div>"/*#fileedit-tab-commit*/);
18951951
18961952
/****** Help/Tips ******/
18971953
CX("<div id='fileedit-tab-help' "
18981954
"data-tab-parent='fileedit-tabs' "
1899
- "data-tab-label='Help'"
1955
+ "data-tab-label='Help' "
1956
+ "class='hidden'"
19001957
">");
19011958
{
19021959
CX("<h1>Help &amp; Tips</h1>");
19031960
CX("<ul>");
19041961
CX("<li><strong>Only files matching the <code>fileedit-glob</code> "
@@ -1922,61 +1979,81 @@
19221979
"file/check-in combination are discarded.</li>");
19231980
CX("</ul>");
19241981
}
19251982
CX("</div>"/*#fileedit-tab-help*/);
19261983
1927
- {
1928
- /* Dynamically populate the editor, display any error in the err
1929
- ** blob, and/or switch to tab #0, where the file selector
1930
- ** lives... */
1931
- blob_appendf(&endScript,
1932
- "fossil.onPageLoad(");
1933
- if(zRev && zFilename){
1934
- assert(0==blob_size(&err));
1935
- blob_appendf(&endScript,
1936
- "()=>fossil.page.loadFile(%!j,%!j)",
1937
- zFilename, cimi.zParentUuid);
1938
- }else{
1939
- blob_appendf(&endScript,"function(){\n");
1940
- if(blob_size(&err)>0){
1941
- blob_appendf(&endScript,
1942
- "fossil.error(%!j);\n",
1943
- blob_str(&err));
1944
- }
1945
- blob_appendf(&endScript,
1946
- "fossil.page.tabs.switchToTab(0);\n");
1947
- blob_appendf(&endScript,"}");
1948
- }
1949
- blob_appendf(&endScript,");\n");
1950
- }
1951
-
1952
- blob_reset(&err);
1953
- CheckinMiniInfo_cleanup(&cimi);
1954
- style_emit_script_fossil_bootstrap(0);
1955
- append_diff_javascript(1);
1956
- style_emit_script_fetch(0);
1957
- style_emit_script_tabs(0)/*also emits fossil.dom*/;
1958
- style_emit_script_confirmer(0);
1959
- style_emit_script_builtin(0, "fossil.storage.js");
1960
-
1984
+ builtin_request_js("sbsdiff.js");
1985
+ style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1986
+ "storage", 0);
1987
+ builtin_fulfill_js_requests();
19611988
/*
19621989
** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
19631990
** used for dynamically toggling certain UI components on and off.
1964
- ** Must come before fossil.page.fileedit.js.
1991
+ ** Must come after window.fossil has been intialized and before
1992
+ ** fossil.page.fileedit.js. Potential TODO: move this into the
1993
+ ** window.fossil bootstrapping so that we don't have to "fulfill"
1994
+ ** the JS multiple times.
19651995
*/
19661996
ajax_emit_js_preview_modes(1);
1967
-
1968
- style_emit_script_builtin(0, "fossil.page.fileedit.js");
1969
- if(blob_size(&endScript)>0){
1997
+ builtin_request_js("fossil.page.fileedit.js");
1998
+ builtin_fulfill_js_requests();
1999
+ {
2000
+ /* Dynamically populate the editor, display any error in the err
2001
+ ** blob, and/or switch to tab #0, where the file selector
2002
+ ** lives. The extra C scopes here correspond to JS-level scopes,
2003
+ ** to improve grokability. */
19702004
style_emit_script_tag(0,0);
19712005
CX("\n(function(){\n");
1972
- CX("try{\n%b}\n"
1973
- "catch(e){"
2006
+ CX("try{\n");
2007
+ {
2008
+ char * zFirstLeafUuid = 0;
2009
+ CX("fossil.config['fileedit-glob'] = ");
2010
+ glob_render_json_to_cgi(fileedit_glob());
2011
+ CX(";\n");
2012
+ if(blob_size(&err)>0){
2013
+ CX("fossil.error(%!j);\n", blob_str(&err));
2014
+ }
2015
+ /* Populate the page with the current leaves and, if available,
2016
+ the selected checkin's file list, to save 1 or 2 XHR requests
2017
+ at startup. That makes this page uncacheable, but compressed
2018
+ delivery of this page is currently less than 6k. */
2019
+ CX("fossil.page.initialLeaves = ");
2020
+ fileedit_render_leaves_list(cimi.zParentUuid ? 0 : &zFirstLeafUuid);
2021
+ CX(";\n");
2022
+ if(zFirstLeafUuid){
2023
+ assert(!cimi.zParentUuid);
2024
+ cimi.zParentUuid = zFirstLeafUuid;
2025
+ zFirstLeafUuid = 0;
2026
+ }
2027
+ if(cimi.zParentUuid){
2028
+ CX("fossil.page.initialFiles = ");
2029
+ fileedit_render_checkin_files(cimi.zParentUuid);
2030
+ CX(";\n");
2031
+ }
2032
+ CX("fossil.onPageLoad(function(){\n");
2033
+ {
2034
+ if(blob_size(&err)>0){
2035
+ CX("fossil.error(%!j);\n",
2036
+ blob_str(&err));
2037
+ CX("fossil.page.tabs.switchToTab(0);\n");
2038
+ }
2039
+ if(cimi.zParentUuid && cimi.zFilename){
2040
+ CX("fossil.page.loadFile(%!j,%!j);\n",
2041
+ cimi.zFilename, cimi.zParentUuid)
2042
+ /* Reminder we cannot embed the JSON-format
2043
+ content of the file here because if it contains
2044
+ a SCRIPT tag then it will break the whole page. */;
2045
+ }
2046
+ }
2047
+ CX("});\n")/*fossil.onPageLoad()*/;
2048
+ }
2049
+ CX("}catch(e){"
19742050
"fossil.error(e); console.error('Exception:',e);"
1975
- "}\n",
1976
- &endScript);
1977
- CX("})();");
2051
+ "}\n");
2052
+ CX("})();")/*anonymous function*/;
19782053
style_emit_script_tag(1,0);
19792054
}
2055
+ blob_reset(&err);
2056
+ CheckinMiniInfo_cleanup(&cimi);
19802057
db_end_transaction(0);
19812058
style_footer();
19822059
}
19832060
--- src/fileedit.c
+++ src/fileedit.c
@@ -364,14 +364,10 @@
364 blob_appendf(pOut, "B %s\n",
365 pCI->pParent->zBaseline
366 ? pCI->pParent->zBaseline
367 : pCI->zParentUuid);
368 }
369 blob_reserve(pOut, 1024 *
370 (asDelta ? 2 : pCI->pParent->nFile/11+1
371 /* In the fossil core repo, each 12-ish F-cards (on
372 ** average) take up roughly 1kb */));
373 if(blob_size(&pCI->comment)!=0){
374 blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment));
375 }else{
376 blob_append(pOut, "C (no\\scomment)\n", 16);
377 }
@@ -965,11 +961,12 @@
965 ** populates:
966 **
967 ** - *zRevUuid = the fully-expanded value of zRev (owned by the
968 ** caller). zRevUuid may be NULL.
969 **
970 ** - *vid = the RID of zRevUuid. May not be NULL.
 
971 **
972 ** - *frid = the RID of zFilename's blob content. May not be NULL
973 ** unless zFilename is also NULL. If BOTH of zFilename and frid are
974 ** NULL then no confirmation is done on the filename argument - only
975 ** zRev is checked.
@@ -979,38 +976,41 @@
979 ** returns false, it queues up an error response and the caller must
980 ** return immediately.
981 */
982 static int fileedit_ajax_setup_filerev(const char * zRev,
983 char ** zRevUuid,
984 int * vid,
985 const char * zFilename,
986 int * frid){
987 char * zFileUuid = 0; /* file content UUID */
988 const int checkFile = zFilename!=0 || frid!=0;
 
989
990 if(checkFile && !fileedit_ajax_check_filename(zFilename)){
991 return 0;
992 }
993 *vid = symbolic_name_to_rid(zRev, "ci");
994 if(0==*vid){
995 ajax_route_error(404,"Cannot resolve name as a checkin: %s",
996 zRev);
997 return 0;
998 }else if(*vid<0){
999 ajax_route_error(400,"Checkin name is ambiguous: %s",
1000 zRev);
1001 return 0;
 
 
1002 }
1003 if(checkFile){
1004 zFileUuid = fileedit_file_uuid(zFilename, *vid, 0);
1005 if(zFileUuid==0){
1006 ajax_route_error(404, "Checkin does not contain file.");
1007 return 0;
1008 }
1009 }
1010 if(zRevUuid!=0){
1011 *zRevUuid = rid_to_uuid(*vid);
1012 }
1013 if(checkFile){
1014 assert(zFileUuid!=0);
1015 if(frid!=0){
1016 *frid = fast_uuid_to_rid(zFileUuid);
@@ -1290,10 +1290,92 @@
1290 end_fail:
1291 #undef fail
1292 fossil_free(zFileUuid);
1293 return rc ? rc : 500;
1294 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1295
1296 /*
1297 ** AJAX route /fileedit?ajax=filelist
1298 **
1299 ** Fetches a JSON-format list of leaves and/or filenames for use in
@@ -1318,66 +1400,27 @@
1318 ** }
1319 **
1320 ** On error it produces a JSON response as documented for
1321 ** ajax_route_error().
1322 */
1323 static void fileedit_ajax_filelist(void){
1324 const char * zCi = PD("checkin",P("ci"));
1325 Blob sql = empty_blob;
1326 Stmt q = empty_Stmt;
1327 int i = 0;
1328
1329 if(!ajax_route_bootstrap(1,0)){
1330 return;
1331 }
1332 cgi_set_content_type("application/json");
1333 if(zCi!=0){
1334 char * zCiFull = 0;
1335 int vid = 0;
1336 if(0==fileedit_ajax_setup_filerev(zCi, &zCiFull, &vid, 0, 0)){
1337 /* Error already reported */
1338 return;
1339 }
1340 CX("{\"checkin\":%!j,"
1341 "\"editableFiles\":[", zCiFull);
1342 blob_append_sql(&sql, "SELECT filename FROM files_of_checkin(%Q) "
1343 "ORDER BY filename %s",
1344 zCiFull, filename_collation());
1345 db_prepare_blob(&q, &sql);
1346 while( SQLITE_ROW==db_step(&q) ){
1347 const char * zFilename = db_column_text(&q, 0);
1348 if(fileedit_is_editable(zFilename)){
1349 if(i++){
1350 CX(",");
1351 }
1352 CX("%!j", zFilename);
1353 }
1354 }
1355 db_finalize(&q);
1356 CX("]}");
1357 }else if(P("leaves")!=0){
1358 blob_append(&sql, timeline_query_for_tty(), -1);
1359 blob_append_sql(&sql, " AND blob.rid IN (SElECT rid FROM leaf "
1360 "WHERE NOT EXISTS("
1361 "SELECT 1 from tagxref WHERE tagid=%d AND "
1362 "tagtype>0 AND rid=leaf.rid"
1363 ")) "
1364 "ORDER BY mtime DESC", TAG_CLOSED);
1365 db_prepare_blob(&q, &sql);
1366 CX("[");
1367 while( SQLITE_ROW==db_step(&q) ){
1368 if(i++){
1369 CX(",");
1370 }
1371 CX("{");
1372 CX("\"checkin\":%!j,", db_column_text(&q, 1));
1373 CX("\"branch\":%!j,", db_column_text(&q, 7));
1374 CX("\"timestamp\":%!j", db_column_text(&q, 2));
1375 CX("}");
1376 }
1377 CX("]");
1378 db_finalize(&q);
1379 }else{
1380 ajax_route_error(500, "Unhandled URL argument.");
1381 }
1382 }
1383
@@ -1484,52 +1527,60 @@
1484 }
1485
1486 /*
1487 ** WEBPAGE: fileedit
1488 **
1489 ** Enables the online editing and committing of individual text files.
1490 ** Requires that the user have Write permissions.
 
 
 
 
 
1491 **
1492 ** Optional query parameters:
1493 **
1494 ** filename=FILENAME Repo-relative path to the file.
1495 ** checkin=VERSION Checkin version, using any unambiguous
1496 ** supported symbolic version name.
1497 **
1498 ** Internal-use parameters:
1499 **
1500 ** name=string The name of a page-specific AJAX operation.
1501 **
1502 ** Noting that fossil internally stores all URL path components after
1503 ** the first as the "name" value. Thus /fileedit?name=blah is
1504 ** equivalent to /fileedit/blah. The latter is the preferred
1505 ** form. This means, however, that no fileedit ajax routes may make
1506 ** use of the name parameter.
1507 **
1508 ** Which additional parameters are used by each distinct ajax value is
1509 ** an internal implementation detail and may change with any given
1510 ** build of this code. An unknown "name" value triggers an error, as
1511 ** documented for ajax_route_error().
1512 */
1513 void fileedit_page(void){
1514 const char * zFilename = 0; /* filename. We'll accept 'name'
1515 because that param is handled
1516 specially by the core. */
1517 const char * zRev = 0; /* checkin version */
1518 const char * zFileMime = 0; /* File mime type guess */
1519 CheckinMiniInfo cimi; /* Checkin state */
1520 int previewRenderMode = AJAX_RENDER_GUESS; /* preview mode */
1521 Blob err = empty_blob; /* Error report */
1522 Blob endScript = empty_blob; /* Script code to run at the
1523 end. This content will be
1524 combined into a single JS
1525 function call, thus each
1526 entry must end with a
1527 semicolon. */
1528 const char *zAjax = P("name"); /* Name of AJAX route for
1529 sub-dispatching. */
1530
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1531 /* Allow no access to this page without check-in privilege */
1532 login_check_credentials();
1533 if( !g.perm.Write ){
1534 if(zAjax!=0){
1535 ajax_route_error(403, "Write permissions required.");
@@ -1590,14 +1641,11 @@
1590 ** transaction cleanly.
1591 */
1592 {
1593 int isMissingArg = 0;
1594 if(fileedit_setup_cimi_from_p(&cimi, &err, &isMissingArg)==0){
1595 zFilename = cimi.zFilename;
1596 zRev = cimi.zParentUuid;
1597 assert(zRev);
1598 assert(zFilename);
1599 zFileMime = mimetype_from_name(cimi.zFilename);
1600 }else if(isMissingArg!=0){
1601 /* Squelch these startup warnings - they're non-fatal now but
1602 ** used to be fatal. */
1603 blob_reset(&err);
@@ -1626,34 +1674,39 @@
1626 /* Status bar */
1627 CX("<div id='fossil-status-bar' "
1628 "title='Status message area. Double-click to clear them.'>"
1629 "Status messages will go here.</div>\n"
1630 /* will be moved into the tab container via JS */);
 
 
 
 
 
1631
1632 /* Main tab container... */
1633 CX("<div id='fileedit-tabs' class='tab-container'></div>");
 
 
 
1634
1635 /***** File/version info tab *****/
1636 {
1637 CX("<div id='fileedit-tab-fileselect' "
1638 "data-tab-parent='fileedit-tabs' "
1639 "data-tab-label='File Info &amp; Selection'"
 
1640 ">");
1641 CX("<fieldset id='file-version-details'>"
1642 "<legend>File/Version</legend>"
1643 "<div>No file loaded.</div>"
1644 "</fieldset>");
1645 CX("<h1>Select a file to edit:</h1>");
1646 CX("<div id='fileedit-file-selector'></div>");
1647 CX("</div>"/*#fileedit-tab-fileselect*/);
1648 }
1649
1650 /******* Content tab *******/
1651 {
1652 CX("<div id='fileedit-tab-content' "
1653 "data-tab-parent='fileedit-tabs' "
1654 "data-tab-label='File Content'"
 
1655 ">");
1656 CX("<div class='flex-container flex-row child-gap-small'>");
1657 CX("<button class='fileedit-content-reload confirmer' "
1658 "title='Reload the file from the server, discarding "
1659 "any local edits. To help avoid accidental loss of "
@@ -1668,22 +1721,22 @@
1668 "150%", 150, "175%", 175,
1669 "200%", 200, NULL);
1670 CX("</div>");
1671 CX("<div class='flex-container flex-column stretch'>");
1672 CX("<textarea name='content' id='fileedit-content-editor' "
1673 "class='fileedit' "
1674 "rows='20' cols='80'>");
1675 CX("</textarea>");
1676 CX("</div>"/*textarea wrapper*/);
1677 CX("</div>"/*#tab-file-content*/);
1678 }
1679
1680 /****** Preview tab ******/
1681 {
1682 CX("<div id='fileedit-tab-preview' "
1683 "data-tab-parent='fileedit-tabs' "
1684 "data-tab-label='Preview'"
 
1685 ">");
1686 CX("<div class='fileedit-options flex-container flex-row'>");
1687 CX("<button id='btn-preview-refresh' "
1688 "data-f-preview-from='fileContent' "
1689 /* ^^^ fossil.page[methodName]() OR text source elem ID,
@@ -1741,14 +1794,16 @@
1741
1742 /****** Diff tab ******/
1743 {
1744 CX("<div id='fileedit-tab-diff' "
1745 "data-tab-parent='fileedit-tabs' "
1746 "data-tab-label='Diff'"
 
1747 ">");
1748
1749 CX("<div class='fileedit-options flex-container flex-row' "
 
1750 "id='fileedit-tab-diff-buttons'>");
1751 CX("<button class='sbs'>Side-by-side</button>"
1752 "<button class='unified'>Unified</button>");
1753 if(0){
1754 /* For the time being let's just ignore all whitespace
@@ -1773,11 +1828,12 @@
1773 }
1774
1775 /****** Commit ******/
1776 CX("<div id='fileedit-tab-commit' "
1777 "data-tab-parent='fileedit-tabs' "
1778 "data-tab-label='Commit'"
 
1779 ">");
1780 {
1781 /******* Commit flags/options *******/
1782 CX("<div class='fileedit-options flex-container flex-row'>");
1783 style_labeled_checkbox("cb-dry-run",
@@ -1894,11 +1950,12 @@
1894 CX("</div>"/*#fileedit-tab-commit*/);
1895
1896 /****** Help/Tips ******/
1897 CX("<div id='fileedit-tab-help' "
1898 "data-tab-parent='fileedit-tabs' "
1899 "data-tab-label='Help'"
 
1900 ">");
1901 {
1902 CX("<h1>Help &amp; Tips</h1>");
1903 CX("<ul>");
1904 CX("<li><strong>Only files matching the <code>fileedit-glob</code> "
@@ -1922,61 +1979,81 @@
1922 "file/check-in combination are discarded.</li>");
1923 CX("</ul>");
1924 }
1925 CX("</div>"/*#fileedit-tab-help*/);
1926
1927 {
1928 /* Dynamically populate the editor, display any error in the err
1929 ** blob, and/or switch to tab #0, where the file selector
1930 ** lives... */
1931 blob_appendf(&endScript,
1932 "fossil.onPageLoad(");
1933 if(zRev && zFilename){
1934 assert(0==blob_size(&err));
1935 blob_appendf(&endScript,
1936 "()=>fossil.page.loadFile(%!j,%!j)",
1937 zFilename, cimi.zParentUuid);
1938 }else{
1939 blob_appendf(&endScript,"function(){\n");
1940 if(blob_size(&err)>0){
1941 blob_appendf(&endScript,
1942 "fossil.error(%!j);\n",
1943 blob_str(&err));
1944 }
1945 blob_appendf(&endScript,
1946 "fossil.page.tabs.switchToTab(0);\n");
1947 blob_appendf(&endScript,"}");
1948 }
1949 blob_appendf(&endScript,");\n");
1950 }
1951
1952 blob_reset(&err);
1953 CheckinMiniInfo_cleanup(&cimi);
1954 style_emit_script_fossil_bootstrap(0);
1955 append_diff_javascript(1);
1956 style_emit_script_fetch(0);
1957 style_emit_script_tabs(0)/*also emits fossil.dom*/;
1958 style_emit_script_confirmer(0);
1959 style_emit_script_builtin(0, "fossil.storage.js");
1960
1961 /*
1962 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1963 ** used for dynamically toggling certain UI components on and off.
1964 ** Must come before fossil.page.fileedit.js.
 
 
 
1965 */
1966 ajax_emit_js_preview_modes(1);
1967
1968 style_emit_script_builtin(0, "fossil.page.fileedit.js");
1969 if(blob_size(&endScript)>0){
 
 
 
 
1970 style_emit_script_tag(0,0);
1971 CX("\n(function(){\n");
1972 CX("try{\n%b}\n"
1973 "catch(e){"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1974 "fossil.error(e); console.error('Exception:',e);"
1975 "}\n",
1976 &endScript);
1977 CX("})();");
1978 style_emit_script_tag(1,0);
1979 }
 
 
1980 db_end_transaction(0);
1981 style_footer();
1982 }
1983
--- src/fileedit.c
+++ src/fileedit.c
@@ -364,14 +364,10 @@
364 blob_appendf(pOut, "B %s\n",
365 pCI->pParent->zBaseline
366 ? pCI->pParent->zBaseline
367 : pCI->zParentUuid);
368 }
 
 
 
 
369 if(blob_size(&pCI->comment)!=0){
370 blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment));
371 }else{
372 blob_append(pOut, "C (no\\scomment)\n", 16);
373 }
@@ -965,11 +961,12 @@
961 ** populates:
962 **
963 ** - *zRevUuid = the fully-expanded value of zRev (owned by the
964 ** caller). zRevUuid may be NULL.
965 **
966 ** - *pVid = the RID of zRevUuid. pVid May be NULL. If the vid
967 ** cannot be resolved or is ambiguous, pVid is not assigned.
968 **
969 ** - *frid = the RID of zFilename's blob content. May not be NULL
970 ** unless zFilename is also NULL. If BOTH of zFilename and frid are
971 ** NULL then no confirmation is done on the filename argument - only
972 ** zRev is checked.
@@ -979,38 +976,41 @@
976 ** returns false, it queues up an error response and the caller must
977 ** return immediately.
978 */
979 static int fileedit_ajax_setup_filerev(const char * zRev,
980 char ** zRevUuid,
981 int * pVid,
982 const char * zFilename,
983 int * frid){
984 char * zFileUuid = 0; /* file content UUID */
985 const int checkFile = zFilename!=0 || frid!=0;
986 int vid = 0;
987
988 if(checkFile && !fileedit_ajax_check_filename(zFilename)){
989 return 0;
990 }
991 vid = symbolic_name_to_rid(zRev, "ci");
992 if(0==vid){
993 ajax_route_error(404,"Cannot resolve name as a checkin: %s",
994 zRev);
995 return 0;
996 }else if(vid<0){
997 ajax_route_error(400,"Checkin name is ambiguous: %s",
998 zRev);
999 return 0;
1000 }else if(pVid!=0){
1001 *pVid = vid;
1002 }
1003 if(checkFile){
1004 zFileUuid = fileedit_file_uuid(zFilename, vid, 0);
1005 if(zFileUuid==0){
1006 ajax_route_error(404, "Checkin does not contain file.");
1007 return 0;
1008 }
1009 }
1010 if(zRevUuid!=0){
1011 *zRevUuid = rid_to_uuid(vid);
1012 }
1013 if(checkFile){
1014 assert(zFileUuid!=0);
1015 if(frid!=0){
1016 *frid = fast_uuid_to_rid(zFileUuid);
@@ -1290,10 +1290,92 @@
1290 end_fail:
1291 #undef fail
1292 fossil_free(zFileUuid);
1293 return rc ? rc : 500;
1294 }
1295
1296 /*
1297 ** Renders a list of all open leaves in JSON form:
1298 **
1299 ** [
1300 ** {checkin: UUID, branch: branchName, timestamp: string}
1301 ** ]
1302 **
1303 ** The entries are ordered newest first.
1304 **
1305 ** If zFirstUuid is not NULL then *zFirstUuid is set to a copy of the
1306 ** full UUID of the first (most recent) leaf, which must be freed by
1307 ** the caller. It is set to 0 if there are no leaves.
1308 */
1309 static void fileedit_render_leaves_list(char ** zFirstUuid){
1310 Blob sql = empty_blob;
1311 Stmt q = empty_Stmt;
1312 int i = 0;
1313
1314 if(zFirstUuid){
1315 *zFirstUuid = 0;
1316 }
1317 blob_append(&sql, timeline_query_for_tty(), -1);
1318 blob_append_sql(&sql, " AND blob.rid IN (SElECT rid FROM leaf "
1319 "WHERE NOT EXISTS("
1320 "SELECT 1 from tagxref WHERE tagid=%d AND "
1321 "tagtype>0 AND rid=leaf.rid"
1322 ")) "
1323 "ORDER BY mtime DESC", TAG_CLOSED);
1324 db_prepare_blob(&q, &sql);
1325 CX("[");
1326 while( SQLITE_ROW==db_step(&q) ){
1327 const char * zUuid = db_column_text(&q, 1);
1328 if(i++){
1329 CX(",");
1330 }else if(zFirstUuid){
1331 *zFirstUuid = fossil_strdup(zUuid);
1332 }
1333 CX("{");
1334 CX("\"checkin\":%!j,", zUuid);
1335 CX("\"branch\":%!j,", db_column_text(&q, 7));
1336 CX("\"timestamp\":%!j", db_column_text(&q, 2));
1337 CX("}");
1338 }
1339 CX("]");
1340 db_finalize(&q);
1341 }
1342
1343 /*
1344 ** For the given fully resolved UUID, renders a JSON object containing
1345 ** the fileeedit-editable files in that checkin:
1346 **
1347 ** {
1348 ** checkin: UUID,
1349 ** editableFiles: [ filename1, ... filenameN ]
1350 ** }
1351 **
1352 ** They are sorted by name using filename_collation().
1353 */
1354 static void fileedit_render_checkin_files(const char * zFullUuid){
1355 Blob sql = empty_blob;
1356 Stmt q = empty_Stmt;
1357 int i = 0;
1358
1359 CX("{\"checkin\":%!j,"
1360 "\"editableFiles\":[", zFullUuid);
1361 blob_append_sql(&sql, "SELECT filename FROM files_of_checkin(%Q) "
1362 "ORDER BY filename %s",
1363 zFullUuid, filename_collation());
1364 db_prepare_blob(&q, &sql);
1365 while( SQLITE_ROW==db_step(&q) ){
1366 const char * zFilename = db_column_text(&q, 0);
1367 if(fileedit_is_editable(zFilename)){
1368 if(i++){
1369 CX(",");
1370 }
1371 CX("%!j", zFilename);
1372 }
1373 }
1374 db_finalize(&q);
1375 CX("]}");
1376 }
1377
1378 /*
1379 ** AJAX route /fileedit?ajax=filelist
1380 **
1381 ** Fetches a JSON-format list of leaves and/or filenames for use in
@@ -1318,66 +1400,27 @@
1400 ** }
1401 **
1402 ** On error it produces a JSON response as documented for
1403 ** ajax_route_error().
1404 */
1405 static void fileedit_ajax_filelist(){
1406 const char * zCi = PD("checkin",P("ci"));
 
 
 
1407
1408 if(!ajax_route_bootstrap(1,0)){
1409 return;
1410 }
1411 cgi_set_content_type("application/json");
1412 if(zCi!=0){
1413 char * zCiFull = 0;
1414 if(0==fileedit_ajax_setup_filerev(zCi, &zCiFull, 0, 0, 0)){
 
1415 /* Error already reported */
1416 return;
1417 }
1418 fileedit_render_checkin_files(zCiFull);
1419 fossil_free(zCiFull);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1420 }else if(P("leaves")!=0){
1421 fileedit_render_leaves_list(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1422 }else{
1423 ajax_route_error(500, "Unhandled URL argument.");
1424 }
1425 }
1426
@@ -1484,52 +1527,60 @@
1527 }
1528
1529 /*
1530 ** WEBPAGE: fileedit
1531 **
1532 ** Enables the online editing and committing of text files. Requires
1533 ** that the user have Write permissions and that a user with setup
1534 ** permissions has set the fileedit-glob setting to a list of glob
1535 ** patterns matching files which may be edited (e.g. "*.wiki,*.md").
1536 ** Note that fileedit-glob, by design, is a local-only setting.
1537 ** It does not sync across repository clones, and must be explicitly
1538 ** set on any repositories where this page should be activated.
1539 **
1540 ** Optional query parameters:
1541 **
1542 ** filename=FILENAME Repo-relative path to the file.
1543 ** checkin=VERSION Checkin version, using any unambiguous
1544 ** symbolic version name.
1545 **
1546 ** If passed a filename but no checkin then it will attempt to
1547 ** load that file from the most recent leaf checkin.
1548 **
1549 ** Once the page is loaded, files may be selected from any open leaf
1550 ** version. The only way to edit files from non-leaf checkins is to
1551 ** pass both the filename and checkin as URL parameters to the page.
1552 ** Users with the proper permissions will be presented with "Edit"
1553 ** links in various file-specific contexts for files which match the
1554 ** fileedit-glob, regardless of whether they refer to leaf versions or
1555 ** not.
 
 
 
 
1556 */
1557 void fileedit_page(void){
 
 
 
 
1558 const char * zFileMime = 0; /* File mime type guess */
1559 CheckinMiniInfo cimi; /* Checkin state */
1560 int previewRenderMode = AJAX_RENDER_GUESS; /* preview mode */
1561 Blob err = empty_blob; /* Error report */
 
 
 
 
 
 
1562 const char *zAjax = P("name"); /* Name of AJAX route for
1563 sub-dispatching. */
1564
1565 /*
1566 ** Internal-use URL parameters:
1567 **
1568 ** name=string The name of a page-specific AJAX operation.
1569 **
1570 ** Noting that fossil internally stores all URL path components
1571 ** after the first as the "name" value. Thus /fileedit?name=blah is
1572 ** equivalent to /fileedit/blah. The latter is the preferred
1573 ** form. This means, however, that no fileedit ajax routes may make
1574 ** use of the name parameter.
1575 **
1576 ** Which additional parameters are used by each distinct ajax route
1577 ** is an internal implementation detail and may change with any
1578 ** given build of this code. An unknown "name" value triggers an
1579 ** error, as documented for ajax_route_error().
1580 */
1581
1582 /* Allow no access to this page without check-in privilege */
1583 login_check_credentials();
1584 if( !g.perm.Write ){
1585 if(zAjax!=0){
1586 ajax_route_error(403, "Write permissions required.");
@@ -1590,14 +1641,11 @@
1641 ** transaction cleanly.
1642 */
1643 {
1644 int isMissingArg = 0;
1645 if(fileedit_setup_cimi_from_p(&cimi, &err, &isMissingArg)==0){
1646 assert(cimi.zFilename);
 
 
 
1647 zFileMime = mimetype_from_name(cimi.zFilename);
1648 }else if(isMissingArg!=0){
1649 /* Squelch these startup warnings - they're non-fatal now but
1650 ** used to be fatal. */
1651 blob_reset(&err);
@@ -1626,34 +1674,39 @@
1674 /* Status bar */
1675 CX("<div id='fossil-status-bar' "
1676 "title='Status message area. Double-click to clear them.'>"
1677 "Status messages will go here.</div>\n"
1678 /* will be moved into the tab container via JS */);
1679
1680 CX("<div id='fileedit-edit-status'>"
1681 "<span class='name'>(no file loaded)</span>"
1682 "<span class='links'></span>"
1683 "</div>");
1684
1685 /* Main tab container... */
1686 CX("<div id='fileedit-tabs' class='tab-container'></div>");
1687
1688 /* The .hidden class on the following tab elements is to help lessen
1689 the FOUC effect of the tabs before JS re-assembles them. */
1690
1691 /***** File/version info tab *****/
1692 {
1693 CX("<div id='fileedit-tab-fileselect' "
1694 "data-tab-parent='fileedit-tabs' "
1695 "data-tab-label='File Selection' "
1696 "class='hidden'"
1697 ">");
 
 
 
 
 
1698 CX("<div id='fileedit-file-selector'></div>");
1699 CX("</div>"/*#fileedit-tab-fileselect*/);
1700 }
1701
1702 /******* Content tab *******/
1703 {
1704 CX("<div id='fileedit-tab-content' "
1705 "data-tab-parent='fileedit-tabs' "
1706 "data-tab-label='File Content' "
1707 "class='hidden'"
1708 ">");
1709 CX("<div class='flex-container flex-row child-gap-small'>");
1710 CX("<button class='fileedit-content-reload confirmer' "
1711 "title='Reload the file from the server, discarding "
1712 "any local edits. To help avoid accidental loss of "
@@ -1668,22 +1721,22 @@
1721 "150%", 150, "175%", 175,
1722 "200%", 200, NULL);
1723 CX("</div>");
1724 CX("<div class='flex-container flex-column stretch'>");
1725 CX("<textarea name='content' id='fileedit-content-editor' "
1726 "class='fileedit' rows='25'>");
 
1727 CX("</textarea>");
1728 CX("</div>"/*textarea wrapper*/);
1729 CX("</div>"/*#tab-file-content*/);
1730 }
1731
1732 /****** Preview tab ******/
1733 {
1734 CX("<div id='fileedit-tab-preview' "
1735 "data-tab-parent='fileedit-tabs' "
1736 "data-tab-label='Preview' "
1737 "class='hidden'"
1738 ">");
1739 CX("<div class='fileedit-options flex-container flex-row'>");
1740 CX("<button id='btn-preview-refresh' "
1741 "data-f-preview-from='fileContent' "
1742 /* ^^^ fossil.page[methodName]() OR text source elem ID,
@@ -1741,14 +1794,16 @@
1794
1795 /****** Diff tab ******/
1796 {
1797 CX("<div id='fileedit-tab-diff' "
1798 "data-tab-parent='fileedit-tabs' "
1799 "data-tab-label='Diff' "
1800 "class='hidden'"
1801 ">");
1802
1803 CX("<div class='fileedit-options flex-container "
1804 "flex-row child-gap-small' "
1805 "id='fileedit-tab-diff-buttons'>");
1806 CX("<button class='sbs'>Side-by-side</button>"
1807 "<button class='unified'>Unified</button>");
1808 if(0){
1809 /* For the time being let's just ignore all whitespace
@@ -1773,11 +1828,12 @@
1828 }
1829
1830 /****** Commit ******/
1831 CX("<div id='fileedit-tab-commit' "
1832 "data-tab-parent='fileedit-tabs' "
1833 "data-tab-label='Commit' "
1834 "class='hidden'"
1835 ">");
1836 {
1837 /******* Commit flags/options *******/
1838 CX("<div class='fileedit-options flex-container flex-row'>");
1839 style_labeled_checkbox("cb-dry-run",
@@ -1894,11 +1950,12 @@
1950 CX("</div>"/*#fileedit-tab-commit*/);
1951
1952 /****** Help/Tips ******/
1953 CX("<div id='fileedit-tab-help' "
1954 "data-tab-parent='fileedit-tabs' "
1955 "data-tab-label='Help' "
1956 "class='hidden'"
1957 ">");
1958 {
1959 CX("<h1>Help &amp; Tips</h1>");
1960 CX("<ul>");
1961 CX("<li><strong>Only files matching the <code>fileedit-glob</code> "
@@ -1922,61 +1979,81 @@
1979 "file/check-in combination are discarded.</li>");
1980 CX("</ul>");
1981 }
1982 CX("</div>"/*#fileedit-tab-help*/);
1983
1984 builtin_request_js("sbsdiff.js");
1985 style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1986 "storage", 0);
1987 builtin_fulfill_js_requests();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1988 /*
1989 ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is
1990 ** used for dynamically toggling certain UI components on and off.
1991 ** Must come after window.fossil has been intialized and before
1992 ** fossil.page.fileedit.js. Potential TODO: move this into the
1993 ** window.fossil bootstrapping so that we don't have to "fulfill"
1994 ** the JS multiple times.
1995 */
1996 ajax_emit_js_preview_modes(1);
1997 builtin_request_js("fossil.page.fileedit.js");
1998 builtin_fulfill_js_requests();
1999 {
2000 /* Dynamically populate the editor, display any error in the err
2001 ** blob, and/or switch to tab #0, where the file selector
2002 ** lives. The extra C scopes here correspond to JS-level scopes,
2003 ** to improve grokability. */
2004 style_emit_script_tag(0,0);
2005 CX("\n(function(){\n");
2006 CX("try{\n");
2007 {
2008 char * zFirstLeafUuid = 0;
2009 CX("fossil.config['fileedit-glob'] = ");
2010 glob_render_json_to_cgi(fileedit_glob());
2011 CX(";\n");
2012 if(blob_size(&err)>0){
2013 CX("fossil.error(%!j);\n", blob_str(&err));
2014 }
2015 /* Populate the page with the current leaves and, if available,
2016 the selected checkin's file list, to save 1 or 2 XHR requests
2017 at startup. That makes this page uncacheable, but compressed
2018 delivery of this page is currently less than 6k. */
2019 CX("fossil.page.initialLeaves = ");
2020 fileedit_render_leaves_list(cimi.zParentUuid ? 0 : &zFirstLeafUuid);
2021 CX(";\n");
2022 if(zFirstLeafUuid){
2023 assert(!cimi.zParentUuid);
2024 cimi.zParentUuid = zFirstLeafUuid;
2025 zFirstLeafUuid = 0;
2026 }
2027 if(cimi.zParentUuid){
2028 CX("fossil.page.initialFiles = ");
2029 fileedit_render_checkin_files(cimi.zParentUuid);
2030 CX(";\n");
2031 }
2032 CX("fossil.onPageLoad(function(){\n");
2033 {
2034 if(blob_size(&err)>0){
2035 CX("fossil.error(%!j);\n",
2036 blob_str(&err));
2037 CX("fossil.page.tabs.switchToTab(0);\n");
2038 }
2039 if(cimi.zParentUuid && cimi.zFilename){
2040 CX("fossil.page.loadFile(%!j,%!j);\n",
2041 cimi.zFilename, cimi.zParentUuid)
2042 /* Reminder we cannot embed the JSON-format
2043 content of the file here because if it contains
2044 a SCRIPT tag then it will break the whole page. */;
2045 }
2046 }
2047 CX("});\n")/*fossil.onPageLoad()*/;
2048 }
2049 CX("}catch(e){"
2050 "fossil.error(e); console.error('Exception:',e);"
2051 "}\n");
2052 CX("})();")/*anonymous function*/;
 
2053 style_emit_script_tag(1,0);
2054 }
2055 blob_reset(&err);
2056 CheckinMiniInfo_cleanup(&cimi);
2057 db_end_transaction(0);
2058 style_footer();
2059 }
2060
+2 -2
--- src/finfo.c
+++ src/finfo.c
@@ -54,11 +54,11 @@
5454
** -s|--status select status mode (print a status indicator for FILE)
5555
** -W|--width <num> Width of lines (default is to auto-detect). Must be
5656
** >22 or 0 (= no limit, resulting in a single line per
5757
** entry).
5858
**
59
-** See also: artifact, cat, descendants, info, leaves
59
+** See also: [[artifact]], [[cat]], [[descendants]], [[info]], [[leaves]]
6060
*/
6161
void finfo_cmd(void){
6262
db_must_be_within_tree();
6363
if( find_option("status","s",0) ){
6464
Stmt q;
@@ -245,11 +245,11 @@
245245
**
246246
** Options:
247247
** -R|--repository FILE Extract artifacts from repository FILE
248248
** -r VERSION The specific check-in containing the file
249249
**
250
-** See also: finfo
250
+** See also: [[finfo]]
251251
*/
252252
void cat_cmd(void){
253253
int i;
254254
Blob content, fname;
255255
const char *zRev;
256256
--- src/finfo.c
+++ src/finfo.c
@@ -54,11 +54,11 @@
54 ** -s|--status select status mode (print a status indicator for FILE)
55 ** -W|--width <num> Width of lines (default is to auto-detect). Must be
56 ** >22 or 0 (= no limit, resulting in a single line per
57 ** entry).
58 **
59 ** See also: artifact, cat, descendants, info, leaves
60 */
61 void finfo_cmd(void){
62 db_must_be_within_tree();
63 if( find_option("status","s",0) ){
64 Stmt q;
@@ -245,11 +245,11 @@
245 **
246 ** Options:
247 ** -R|--repository FILE Extract artifacts from repository FILE
248 ** -r VERSION The specific check-in containing the file
249 **
250 ** See also: finfo
251 */
252 void cat_cmd(void){
253 int i;
254 Blob content, fname;
255 const char *zRev;
256
--- src/finfo.c
+++ src/finfo.c
@@ -54,11 +54,11 @@
54 ** -s|--status select status mode (print a status indicator for FILE)
55 ** -W|--width <num> Width of lines (default is to auto-detect). Must be
56 ** >22 or 0 (= no limit, resulting in a single line per
57 ** entry).
58 **
59 ** See also: [[artifact]], [[cat]], [[descendants]], [[info]], [[leaves]]
60 */
61 void finfo_cmd(void){
62 db_must_be_within_tree();
63 if( find_option("status","s",0) ){
64 Stmt q;
@@ -245,11 +245,11 @@
245 **
246 ** Options:
247 ** -R|--repository FILE Extract artifacts from repository FILE
248 ** -r VERSION The specific check-in containing the file
249 **
250 ** See also: [[finfo]]
251 */
252 void cat_cmd(void){
253 int i;
254 Blob content, fname;
255 const char *zRev;
256
+7 -11
--- src/forum.c
+++ src/forum.c
@@ -749,24 +749,20 @@
749749
forumthread_delete(pThread);
750750
return target;
751751
}
752752
753753
/*
754
-** The first time this is called, it emits SCRIPT tags to load various
755
-** forum-related JavaScript. Ideally it should be called near the end
756
-** of the page, immediately before the call to style_footer() (which
757
-** closes the document's <BODY> and <HTML> tags). Calls after the first
758
-** are a no-op.
754
+** Emits all JS code required by /forumpost.
759755
*/
760
-static void forum_emit_page_js(){
756
+static void forumpost_emit_page_js(){
761757
static int once = 0;
762758
if(0==once){
763759
once = 1;
764
- style_load_js("forum.js");
765
- style_emit_script_fossil_bootstrap(0);
766
- style_emit_script_dom(0);
767
- style_emit_script_builtin(0, "fossil.page.forumpost.js");
760
+ style_emit_script_fossil_bootstrap(1);
761
+ builtin_request_js("forum.js");
762
+ builtin_request_js("fossil.dom.js");
763
+ builtin_request_js("fossil.page.forumpost.js");
768764
}
769765
}
770766
771767
/*
772768
** WEBPAGE: forumpost
@@ -894,11 +890,11 @@
894890
}else{
895891
style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
896892
style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
897893
forum_display_hierarchical(froot, fpid);
898894
}
899
- forum_emit_page_js();
895
+ forumpost_emit_page_js();
900896
style_footer();
901897
}
902898
903899
/*
904900
** Return true if a forum post should be moderated.
905901
--- src/forum.c
+++ src/forum.c
@@ -749,24 +749,20 @@
749 forumthread_delete(pThread);
750 return target;
751 }
752
753 /*
754 ** The first time this is called, it emits SCRIPT tags to load various
755 ** forum-related JavaScript. Ideally it should be called near the end
756 ** of the page, immediately before the call to style_footer() (which
757 ** closes the document's <BODY> and <HTML> tags). Calls after the first
758 ** are a no-op.
759 */
760 static void forum_emit_page_js(){
761 static int once = 0;
762 if(0==once){
763 once = 1;
764 style_load_js("forum.js");
765 style_emit_script_fossil_bootstrap(0);
766 style_emit_script_dom(0);
767 style_emit_script_builtin(0, "fossil.page.forumpost.js");
768 }
769 }
770
771 /*
772 ** WEBPAGE: forumpost
@@ -894,11 +890,11 @@
894 }else{
895 style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
896 style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
897 forum_display_hierarchical(froot, fpid);
898 }
899 forum_emit_page_js();
900 style_footer();
901 }
902
903 /*
904 ** Return true if a forum post should be moderated.
905
--- src/forum.c
+++ src/forum.c
@@ -749,24 +749,20 @@
749 forumthread_delete(pThread);
750 return target;
751 }
752
753 /*
754 ** Emits all JS code required by /forumpost.
 
 
 
 
755 */
756 static void forumpost_emit_page_js(){
757 static int once = 0;
758 if(0==once){
759 once = 1;
760 style_emit_script_fossil_bootstrap(1);
761 builtin_request_js("forum.js");
762 builtin_request_js("fossil.dom.js");
763 builtin_request_js("fossil.page.forumpost.js");
764 }
765 }
766
767 /*
768 ** WEBPAGE: forumpost
@@ -894,11 +890,11 @@
890 }else{
891 style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
892 style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
893 forum_display_hierarchical(froot, fpid);
894 }
895 forumpost_emit_page_js();
896 style_footer();
897 }
898
899 /*
900 ** Return true if a forum post should be moderated.
901
+1 -1
--- src/forum.js
+++ src/forum.js
@@ -14,6 +14,6 @@
1414
var h = x[0].scrollHeight;
1515
var y = absoluteY(x[0]);
1616
if( w>h ) y = y + (h-w)/2;
1717
if( y>0 ) window.scrollTo(0, y);
1818
}
19
-})()
19
+})();
2020
--- src/forum.js
+++ src/forum.js
@@ -14,6 +14,6 @@
14 var h = x[0].scrollHeight;
15 var y = absoluteY(x[0]);
16 if( w>h ) y = y + (h-w)/2;
17 if( y>0 ) window.scrollTo(0, y);
18 }
19 })()
20
--- src/forum.js
+++ src/forum.js
@@ -14,6 +14,6 @@
14 var h = x[0].scrollHeight;
15 var y = absoluteY(x[0]);
16 if( w>h ) y = y + (h-w)/2;
17 if( y>0 ) window.scrollTo(0, y);
18 }
19 })();
20
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -1,6 +1,18 @@
11
"use strict";
2
+(function () {
3
+ /* CustomEvent polyfill, courtesy of Mozilla:
4
+ https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
5
+ */
6
+ if(typeof window.CustomEvent === "function") return false;
7
+ window.CustomEvent = function(event, params) {
8
+ if(!params) params = {bubbles: false, cancelable: false, detail: null};
9
+ const evt = document.createEvent('CustomEvent');
10
+ evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
11
+ return evt;
12
+ };
13
+})();
214
(function(global){
315
/* Bootstrapping bits for the global.fossil object. Must be
416
loaded after style.c:style_emit_script_tag() has initialized
517
that object.
618
*/
@@ -17,10 +29,25 @@
1729
}
1830
const d = new Date();
1931
return d.toISOString().replace(f.rx1,'').split('T').join(' ');
2032
};
2133
34
+ /** Returns the local time string of Date object d, defaulting
35
+ to the current time. */
36
+ const localTimeString = function ff(d){
37
+ if(!ff.pad){
38
+ ff.pad = (x)=>(''+x).length>1 ? x : '0'+x;
39
+ }
40
+ d || (d = new Date());
41
+ return [
42
+ d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
43
+ '-',ff.pad(d.getDate()),
44
+ ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
45
+ ':',ff.pad(d.getSeconds())
46
+ ].join('');
47
+ };
48
+
2249
/*
2350
** By default fossil.message() sends its arguments console.debug(). If
2451
** fossil.message.targetElement is set, it is assumed to be a DOM
2552
** element, its innerText gets assigned to the concatenation of all
2653
** arguments (with a space between each), and the CSS 'error' class is
@@ -30,11 +57,14 @@
3057
** Returns this object.
3158
*/
3259
F.message = function f(msg){
3360
const args = Array.prototype.slice.call(arguments,0);
3461
const tgt = f.targetElement;
35
- if(args.length) args.unshift(timestring(),'UTC:');
62
+ if(args.length) args.unshift(
63
+ localTimeString()+':'
64
+ //timestring(),'UTC:'
65
+ );
3666
if(tgt){
3767
tgt.classList.remove('error');
3868
tgt.innerText = args.join(' ');
3969
}
4070
else{
@@ -107,20 +137,20 @@
107137
repoUrl( repoRelativePath [,urlParams] )
108138
109139
Creates a URL by prepending this.rootPath to the given path
110140
(which must be relative from the top of the site, without a
111141
leading slash). If urlParams is a string, it must be
112
- paramters encoded in the form "key=val&key2=val2...", WITHOUT
142
+ paramters encoded in the form "key=val&key2=val2..." WITHOUT
113143
a leading '?'. If it's an object, all of its properties get
114144
appended to the URL in that form.
115145
*/
116146
F.repoUrl = function(path,urlParams){
117147
if(!urlParams) return this.rootPath+path;
118148
const url=[this.rootPath,path];
119149
url.push('?');
120150
if('string'===typeof urlParams) url.push(urlParams);
121
- else if('object'===typeof urlParams){
151
+ else if(urlParams && 'object'===typeof urlParams){
122152
this.encodeUrlArgs(urlParams, url);
123153
}
124154
return url.join('');
125155
};
126156
127157
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -1,6 +1,18 @@
1 "use strict";
 
 
 
 
 
 
 
 
 
 
 
 
2 (function(global){
3 /* Bootstrapping bits for the global.fossil object. Must be
4 loaded after style.c:style_emit_script_tag() has initialized
5 that object.
6 */
@@ -17,10 +29,25 @@
17 }
18 const d = new Date();
19 return d.toISOString().replace(f.rx1,'').split('T').join(' ');
20 };
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22 /*
23 ** By default fossil.message() sends its arguments console.debug(). If
24 ** fossil.message.targetElement is set, it is assumed to be a DOM
25 ** element, its innerText gets assigned to the concatenation of all
26 ** arguments (with a space between each), and the CSS 'error' class is
@@ -30,11 +57,14 @@
30 ** Returns this object.
31 */
32 F.message = function f(msg){
33 const args = Array.prototype.slice.call(arguments,0);
34 const tgt = f.targetElement;
35 if(args.length) args.unshift(timestring(),'UTC:');
 
 
 
36 if(tgt){
37 tgt.classList.remove('error');
38 tgt.innerText = args.join(' ');
39 }
40 else{
@@ -107,20 +137,20 @@
107 repoUrl( repoRelativePath [,urlParams] )
108
109 Creates a URL by prepending this.rootPath to the given path
110 (which must be relative from the top of the site, without a
111 leading slash). If urlParams is a string, it must be
112 paramters encoded in the form "key=val&key2=val2...", WITHOUT
113 a leading '?'. If it's an object, all of its properties get
114 appended to the URL in that form.
115 */
116 F.repoUrl = function(path,urlParams){
117 if(!urlParams) return this.rootPath+path;
118 const url=[this.rootPath,path];
119 url.push('?');
120 if('string'===typeof urlParams) url.push(urlParams);
121 else if('object'===typeof urlParams){
122 this.encodeUrlArgs(urlParams, url);
123 }
124 return url.join('');
125 };
126
127
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -1,6 +1,18 @@
1 "use strict";
2 (function () {
3 /* CustomEvent polyfill, courtesy of Mozilla:
4 https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
5 */
6 if(typeof window.CustomEvent === "function") return false;
7 window.CustomEvent = function(event, params) {
8 if(!params) params = {bubbles: false, cancelable: false, detail: null};
9 const evt = document.createEvent('CustomEvent');
10 evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
11 return evt;
12 };
13 })();
14 (function(global){
15 /* Bootstrapping bits for the global.fossil object. Must be
16 loaded after style.c:style_emit_script_tag() has initialized
17 that object.
18 */
@@ -17,10 +29,25 @@
29 }
30 const d = new Date();
31 return d.toISOString().replace(f.rx1,'').split('T').join(' ');
32 };
33
34 /** Returns the local time string of Date object d, defaulting
35 to the current time. */
36 const localTimeString = function ff(d){
37 if(!ff.pad){
38 ff.pad = (x)=>(''+x).length>1 ? x : '0'+x;
39 }
40 d || (d = new Date());
41 return [
42 d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
43 '-',ff.pad(d.getDate()),
44 ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
45 ':',ff.pad(d.getSeconds())
46 ].join('');
47 };
48
49 /*
50 ** By default fossil.message() sends its arguments console.debug(). If
51 ** fossil.message.targetElement is set, it is assumed to be a DOM
52 ** element, its innerText gets assigned to the concatenation of all
53 ** arguments (with a space between each), and the CSS 'error' class is
@@ -30,11 +57,14 @@
57 ** Returns this object.
58 */
59 F.message = function f(msg){
60 const args = Array.prototype.slice.call(arguments,0);
61 const tgt = f.targetElement;
62 if(args.length) args.unshift(
63 localTimeString()+':'
64 //timestring(),'UTC:'
65 );
66 if(tgt){
67 tgt.classList.remove('error');
68 tgt.innerText = args.join(' ');
69 }
70 else{
@@ -107,20 +137,20 @@
137 repoUrl( repoRelativePath [,urlParams] )
138
139 Creates a URL by prepending this.rootPath to the given path
140 (which must be relative from the top of the site, without a
141 leading slash). If urlParams is a string, it must be
142 paramters encoded in the form "key=val&key2=val2..." WITHOUT
143 a leading '?'. If it's an object, all of its properties get
144 appended to the URL in that form.
145 */
146 F.repoUrl = function(path,urlParams){
147 if(!urlParams) return this.rootPath+path;
148 const url=[this.rootPath,path];
149 url.push('?');
150 if('string'===typeof urlParams) url.push(urlParams);
151 else if(urlParams && 'object'===typeof urlParams){
152 this.encodeUrlArgs(urlParams, url);
153 }
154 return url.join('');
155 };
156
157
--- src/fossil.confirmer.js
+++ src/fossil.confirmer.js
@@ -81,10 +81,21 @@
8181
action has been confirmed, immediately before the onconfirm or
8282
ontimeout callback. The intention of the callback is to update the
8383
label of the target element. If .ticks is set but .ontick is not
8484
then a default implementation is used which updates the element with
8585
the .confirmText, prepending a countdown to it.
86
+
87
+ .pinSize = if true AND confirmText is set, calculate the larger of
88
+ the element's original and confirmed size and pin it to the larger
89
+ of those sizes to avoid layout reflows when confirmation is
90
+ running. The pinning is implemented by setting its minWidth and
91
+ maxWidth style properties to the same value. This does not work if
92
+ the element text is updated dynamically via ontick(). This ONLY
93
+ works if the element is in the DOM and is not hidden (e.g. via
94
+ display:none) at the time this routine is called, otherwise we
95
+ cannot calculate its size. If the element needs to be hidden, hide
96
+ it after initializing the confirmer.
8697
8798
.debug = boolean. If truthy, it sends some debug output to the dev
8899
console to track what it's doing.
89100
90101
Various notes:
@@ -99,17 +110,26 @@
99110
- Due to the nature of multi-threaded code, it is potentially possible
100111
that confirmation and timeout actions BOTH happen if the user
101112
triggers the associated action at "just the right millisecond"
102113
before the timeout is triggered.
103114
104
-TODO: add an invert option which activates if the timeout is reached
105
-and "times out" if the element is clicked again. e.g. a button which
106
-says "Saving..." and cancels the op if it's clicked again, else it
107
-saves after X time/ticks.
115
+TODO:
116
+
117
+- Add an invert option which activates if the timeout is reached and
118
+"times out" if the element is clicked again. e.g. a button which says
119
+"Saving..." and cancels the op if it's clicked again, else it saves
120
+after X time/ticks.
121
+
122
+- Internally we save/restore the initial text of non-INPUT elements
123
+using innerHTML. We should instead move their child nodes aside (into
124
+an internal out-of-DOM element) and restore them as needed.
108125
109126
Terse Change history:
110127
128
+- 20200811
129
+ - Added pinSize option.
130
+
111131
- 20200507:
112132
- Add a tick-based countdown in order to more easily support
113133
updating the target element with the countdown.
114134
115135
- 20200506:
@@ -138,14 +158,26 @@
138158
const isInput = f.isInput(target);
139159
const updateText = function(msg){
140160
if(isInput) target.value = msg;
141161
else target.innerHTML = msg;
142162
}
163
+ const formatCountdown = (txt, number) => txt + " ["+number+"]";
164
+ if(opt.pinSize && opt.confirmText){
165
+ /* Try to pin the element's width the the greater of its
166
+ current width or its waiting-on-confirmation width
167
+ to avoid layout reflow when it's activated. */
168
+ const digits = (''+(opt.timeout/1000 || opt.ticks)).length;
169
+ const lblLong = formatCountdown(opt.confirmText, "00000000".substr(0,digits));
170
+ const w1 = parseFloat(window.getComputedStyle(target).width);
171
+ updateText(lblLong);
172
+ const w2 = parseFloat(window.getComputedStyle(target).width);
173
+ target.style.minWidth = target.style.maxWidth = (w1>w2 ? w1 : w2)+"px";
174
+ }
143175
updateText(this.opt.initialText);
144176
if(this.opt.ticks && !this.opt.ontick){
145177
this.opt.ontick = function(tick){
146
- updateText("("+tick+") "+self.opt.confirmText);
178
+ updateText(formatCountdown(self.opt.confirmText,tick));
147179
};
148180
}
149181
this.setClasses(false);
150182
this.doTimeout = function() {
151183
if(this.timerID){
@@ -268,15 +300,16 @@
268300
};
269301
/**
270302
The default options for initConfirmer(). Tweak them to set the
271303
defaults. A couple of them (initialText and confirmText) are
272304
dynamically-generated, and can't reasonably be set in the
273
- defaults.
305
+ defaults. Some, like ticks, cannot be set here because that would
306
+ end up indirectly replacing non-tick timeouts with ticks.
274307
*/
275308
F.confirmer.defaultOpts = {
276
- timeout:3000,
277
- ticks: undefined,
309
+ timeout:undefined,
310
+ ticks: 3,
278311
ticktime: 998/*not *quite* 1000*/,
279312
onconfirm: undefined,
280313
ontimeout: undefined,
281314
onactivate: undefined,
282315
classInitial: '',
283316
284317
ADDED src/fossil.copybutton.js
--- src/fossil.confirmer.js
+++ src/fossil.confirmer.js
@@ -81,10 +81,21 @@
81 action has been confirmed, immediately before the onconfirm or
82 ontimeout callback. The intention of the callback is to update the
83 label of the target element. If .ticks is set but .ontick is not
84 then a default implementation is used which updates the element with
85 the .confirmText, prepending a countdown to it.
 
 
 
 
 
 
 
 
 
 
 
86
87 .debug = boolean. If truthy, it sends some debug output to the dev
88 console to track what it's doing.
89
90 Various notes:
@@ -99,17 +110,26 @@
99 - Due to the nature of multi-threaded code, it is potentially possible
100 that confirmation and timeout actions BOTH happen if the user
101 triggers the associated action at "just the right millisecond"
102 before the timeout is triggered.
103
104 TODO: add an invert option which activates if the timeout is reached
105 and "times out" if the element is clicked again. e.g. a button which
106 says "Saving..." and cancels the op if it's clicked again, else it
107 saves after X time/ticks.
 
 
 
 
 
 
108
109 Terse Change history:
110
 
 
 
111 - 20200507:
112 - Add a tick-based countdown in order to more easily support
113 updating the target element with the countdown.
114
115 - 20200506:
@@ -138,14 +158,26 @@
138 const isInput = f.isInput(target);
139 const updateText = function(msg){
140 if(isInput) target.value = msg;
141 else target.innerHTML = msg;
142 }
 
 
 
 
 
 
 
 
 
 
 
 
143 updateText(this.opt.initialText);
144 if(this.opt.ticks && !this.opt.ontick){
145 this.opt.ontick = function(tick){
146 updateText("("+tick+") "+self.opt.confirmText);
147 };
148 }
149 this.setClasses(false);
150 this.doTimeout = function() {
151 if(this.timerID){
@@ -268,15 +300,16 @@
268 };
269 /**
270 The default options for initConfirmer(). Tweak them to set the
271 defaults. A couple of them (initialText and confirmText) are
272 dynamically-generated, and can't reasonably be set in the
273 defaults.
 
274 */
275 F.confirmer.defaultOpts = {
276 timeout:3000,
277 ticks: undefined,
278 ticktime: 998/*not *quite* 1000*/,
279 onconfirm: undefined,
280 ontimeout: undefined,
281 onactivate: undefined,
282 classInitial: '',
283
284 DDED src/fossil.copybutton.js
--- src/fossil.confirmer.js
+++ src/fossil.confirmer.js
@@ -81,10 +81,21 @@
81 action has been confirmed, immediately before the onconfirm or
82 ontimeout callback. The intention of the callback is to update the
83 label of the target element. If .ticks is set but .ontick is not
84 then a default implementation is used which updates the element with
85 the .confirmText, prepending a countdown to it.
86
87 .pinSize = if true AND confirmText is set, calculate the larger of
88 the element's original and confirmed size and pin it to the larger
89 of those sizes to avoid layout reflows when confirmation is
90 running. The pinning is implemented by setting its minWidth and
91 maxWidth style properties to the same value. This does not work if
92 the element text is updated dynamically via ontick(). This ONLY
93 works if the element is in the DOM and is not hidden (e.g. via
94 display:none) at the time this routine is called, otherwise we
95 cannot calculate its size. If the element needs to be hidden, hide
96 it after initializing the confirmer.
97
98 .debug = boolean. If truthy, it sends some debug output to the dev
99 console to track what it's doing.
100
101 Various notes:
@@ -99,17 +110,26 @@
110 - Due to the nature of multi-threaded code, it is potentially possible
111 that confirmation and timeout actions BOTH happen if the user
112 triggers the associated action at "just the right millisecond"
113 before the timeout is triggered.
114
115 TODO:
116
117 - Add an invert option which activates if the timeout is reached and
118 "times out" if the element is clicked again. e.g. a button which says
119 "Saving..." and cancels the op if it's clicked again, else it saves
120 after X time/ticks.
121
122 - Internally we save/restore the initial text of non-INPUT elements
123 using innerHTML. We should instead move their child nodes aside (into
124 an internal out-of-DOM element) and restore them as needed.
125
126 Terse Change history:
127
128 - 20200811
129 - Added pinSize option.
130
131 - 20200507:
132 - Add a tick-based countdown in order to more easily support
133 updating the target element with the countdown.
134
135 - 20200506:
@@ -138,14 +158,26 @@
158 const isInput = f.isInput(target);
159 const updateText = function(msg){
160 if(isInput) target.value = msg;
161 else target.innerHTML = msg;
162 }
163 const formatCountdown = (txt, number) => txt + " ["+number+"]";
164 if(opt.pinSize && opt.confirmText){
165 /* Try to pin the element's width the the greater of its
166 current width or its waiting-on-confirmation width
167 to avoid layout reflow when it's activated. */
168 const digits = (''+(opt.timeout/1000 || opt.ticks)).length;
169 const lblLong = formatCountdown(opt.confirmText, "00000000".substr(0,digits));
170 const w1 = parseFloat(window.getComputedStyle(target).width);
171 updateText(lblLong);
172 const w2 = parseFloat(window.getComputedStyle(target).width);
173 target.style.minWidth = target.style.maxWidth = (w1>w2 ? w1 : w2)+"px";
174 }
175 updateText(this.opt.initialText);
176 if(this.opt.ticks && !this.opt.ontick){
177 this.opt.ontick = function(tick){
178 updateText(formatCountdown(self.opt.confirmText,tick));
179 };
180 }
181 this.setClasses(false);
182 this.doTimeout = function() {
183 if(this.timerID){
@@ -268,15 +300,16 @@
300 };
301 /**
302 The default options for initConfirmer(). Tweak them to set the
303 defaults. A couple of them (initialText and confirmText) are
304 dynamically-generated, and can't reasonably be set in the
305 defaults. Some, like ticks, cannot be set here because that would
306 end up indirectly replacing non-tick timeouts with ticks.
307 */
308 F.confirmer.defaultOpts = {
309 timeout:undefined,
310 ticks: 3,
311 ticktime: 998/*not *quite* 1000*/,
312 onconfirm: undefined,
313 ontimeout: undefined,
314 onactivate: undefined,
315 classInitial: '',
316
317 DDED src/fossil.copybutton.js
--- a/src/fossil.copybutton.js
+++ b/src/fossil.copybutton.js
@@ -0,0 +1,3 @@
1
+(function(F/*fossil object*/){
2
+ /**
3
+ A basic API for creating and
--- a/src/fossil.copybutton.js
+++ b/src/fossil.copybutton.js
@@ -0,0 +1,3 @@
 
 
 
--- a/src/fossil.copybutton.js
+++ b/src/fossil.copybutton.js
@@ -0,0 +1,3 @@
1 (function(F/*fossil object*/){
2 /**
3 A basic API for creating and
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -465,10 +465,103 @@
465465
e = src.querySelector(x);
466466
if(!e){
467467
e = new Error("Cannot find DOM element: "+x);
468468
console.error(e, src);
469469
throw e;
470
+ }
471
+ return e;
472
+ };
473
+
474
+ /**
475
+ "Blinks" the given element a single time for the given number of
476
+ milliseconds, defaulting (if the 2nd argument is falsy or not a
477
+ number) to flashOnce.defaultTimeMs. If a 3rd argument is passed
478
+ in, it must be a function, and it gets callback back at the end
479
+ of the asynchronous flashing processes.
480
+
481
+ This will only activate once per element during that timeframe -
482
+ further calls will become no-ops until the blink is
483
+ completed. This routine adds a dataset member to the element for
484
+ the duration of the blink, to allow it to block multiple blinks.
485
+
486
+ If passed 2 arguments and the 2nd is a function, it behaves as if
487
+ it were called as (arg1, undefined, arg2).
488
+
489
+ Returns e, noting that the flash itself is asynchronous and may
490
+ still be running, or not yet started, when this function returns.
491
+ */
492
+ dom.flashOnce = function f(e,howLongMs,afterFlashCallback){
493
+ if(e.dataset.isBlinking){
494
+ return;
495
+ }
496
+ if(2===arguments.length && 'function' ===typeof howLongMs){
497
+ afterFlashCallback = howLongMs;
498
+ howLongMs = f.defaultTimeMs;
499
+ }
500
+ if(!howLongMs || 'number'!==typeof howLongMs){
501
+ howLongMs = f.defaultTimeMs;
502
+ }
503
+ e.dataset.isBlinking = true;
504
+ const transition = e.style.transition;
505
+ e.style.transition = "opacity "+howLongMs+"ms ease-in-out";
506
+ const opacity = e.style.opacity;
507
+ e.style.opacity = 0;
508
+ setTimeout(function(){
509
+ e.style.transition = transition;
510
+ e.style.opacity = opacity;
511
+ delete e.dataset.isBlinking;
512
+ if(afterFlashCallback) afterFlashCallback();
513
+ }, howLongMs);
514
+ return e;
515
+ };
516
+ dom.flashOnce.defaultTimeMs = 400;
517
+
518
+ /**
519
+ Attempts to copy the given text to the system clipboard. Returns
520
+ true if it succeeds, else false.
521
+ */
522
+ dom.copyTextToClipboard = function(text){
523
+ if( window.clipboardData && window.clipboardData.setData ){
524
+ clipboardData.setData('Text',text);
525
+ return true;
526
+ }else{
527
+ const x = document.createElement("textarea");
528
+ x.style.position = 'fixed';
529
+ x.value = text;
530
+ document.body.appendChild(x);
531
+ x.select();
532
+ var rc;
533
+ try{
534
+ document.execCommand('copy');
535
+ rc = true;
536
+ }catch(err){
537
+ rc = false;
538
+ }finally{
539
+ document.body.removeChild(x);
540
+ }
541
+ return rc;
542
+ }
543
+ };
544
+
545
+ /**
546
+ Copies all properties from the 2nd argument (a plain object) into
547
+ the style member of the first argument (DOM element or a
548
+ forEach-capable list of elements). If the 2nd argument is falsy
549
+ or empty, this is a no-op.
550
+
551
+ Returns its first argument.
552
+ */
553
+ dom.copyStyle = function f(e, style){
554
+ if(e.forEach){
555
+ e.forEach((x)=>f(x, style));
556
+ return e;
557
+ }
558
+ if(style){
559
+ let k;
560
+ for(k in style){
561
+ if(style.hasOwnProperty(k)) e.style[k] = style[k];
562
+ }
470563
}
471564
return e;
472565
};
473566
474567
return F.dom = dom;
475568
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -465,10 +465,103 @@
465 e = src.querySelector(x);
466 if(!e){
467 e = new Error("Cannot find DOM element: "+x);
468 console.error(e, src);
469 throw e;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470 }
471 return e;
472 };
473
474 return F.dom = dom;
475
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -465,10 +465,103 @@
465 e = src.querySelector(x);
466 if(!e){
467 e = new Error("Cannot find DOM element: "+x);
468 console.error(e, src);
469 throw e;
470 }
471 return e;
472 };
473
474 /**
475 "Blinks" the given element a single time for the given number of
476 milliseconds, defaulting (if the 2nd argument is falsy or not a
477 number) to flashOnce.defaultTimeMs. If a 3rd argument is passed
478 in, it must be a function, and it gets callback back at the end
479 of the asynchronous flashing processes.
480
481 This will only activate once per element during that timeframe -
482 further calls will become no-ops until the blink is
483 completed. This routine adds a dataset member to the element for
484 the duration of the blink, to allow it to block multiple blinks.
485
486 If passed 2 arguments and the 2nd is a function, it behaves as if
487 it were called as (arg1, undefined, arg2).
488
489 Returns e, noting that the flash itself is asynchronous and may
490 still be running, or not yet started, when this function returns.
491 */
492 dom.flashOnce = function f(e,howLongMs,afterFlashCallback){
493 if(e.dataset.isBlinking){
494 return;
495 }
496 if(2===arguments.length && 'function' ===typeof howLongMs){
497 afterFlashCallback = howLongMs;
498 howLongMs = f.defaultTimeMs;
499 }
500 if(!howLongMs || 'number'!==typeof howLongMs){
501 howLongMs = f.defaultTimeMs;
502 }
503 e.dataset.isBlinking = true;
504 const transition = e.style.transition;
505 e.style.transition = "opacity "+howLongMs+"ms ease-in-out";
506 const opacity = e.style.opacity;
507 e.style.opacity = 0;
508 setTimeout(function(){
509 e.style.transition = transition;
510 e.style.opacity = opacity;
511 delete e.dataset.isBlinking;
512 if(afterFlashCallback) afterFlashCallback();
513 }, howLongMs);
514 return e;
515 };
516 dom.flashOnce.defaultTimeMs = 400;
517
518 /**
519 Attempts to copy the given text to the system clipboard. Returns
520 true if it succeeds, else false.
521 */
522 dom.copyTextToClipboard = function(text){
523 if( window.clipboardData && window.clipboardData.setData ){
524 clipboardData.setData('Text',text);
525 return true;
526 }else{
527 const x = document.createElement("textarea");
528 x.style.position = 'fixed';
529 x.value = text;
530 document.body.appendChild(x);
531 x.select();
532 var rc;
533 try{
534 document.execCommand('copy');
535 rc = true;
536 }catch(err){
537 rc = false;
538 }finally{
539 document.body.removeChild(x);
540 }
541 return rc;
542 }
543 };
544
545 /**
546 Copies all properties from the 2nd argument (a plain object) into
547 the style member of the first argument (DOM element or a
548 forEach-capable list of elements). If the 2nd argument is falsy
549 or empty, this is a no-op.
550
551 Returns its first argument.
552 */
553 dom.copyStyle = function f(e, style){
554 if(e.forEach){
555 e.forEach((x)=>f(x, style));
556 return e;
557 }
558 if(style){
559 let k;
560 for(k in style){
561 if(style.hasOwnProperty(k)) e.style[k] = style[k];
562 }
563 }
564 return e;
565 };
566
567 return F.dom = dom;
568
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -1,10 +1,13 @@
11
"use strict";
22
/**
33
Requires that window.fossil has already been set up.
4
-
5
- window.fossil.fetch() is an HTTP request/response mini-framework
4
+*/
5
+(function(namespace){
6
+const fossil = namespace;
7
+ /**
8
+ fetch() is an HTTP request/response mini-framework
69
similar (but not identical) to the not-quite-ubiquitous
710
window.fetch().
811
912
JS usages:
1013
@@ -87,19 +90,21 @@
8790
function with the same name, e.g. fossil.fetch.onload(). The
8891
default onload/onerror implementations route the data through the
8992
dev console and (for onerror()) through fossil.error(). The default
9093
beforesend/aftersend are no-ops. Individual pages may overwrite
9194
those members to provide default implementations suitable for the
92
- page's use, e.g. keeping track of how many in-flight
95
+ page's use, e.g. keeping track of how many in-flight ajax requests
96
+ are pending. Any exceptions thrown in an beforesend/aftersend
97
+ handler are current ignored (feature or bug?).
9398
9499
Note that this routine may add properties to the 2nd argument, so
95100
that instance should not be kept around for later use.
96101
97102
Returns this object, noting that the XHR request is asynchronous,
98103
and still in transit (or has yet to be sent) when that happens.
99104
*/
100
-window.fossil.fetch = function f(uri,opt){
105
+fossil.fetch = function f(uri,opt){
101106
const F = fossil;
102107
if(!f.onload){
103108
f.onload = (r)=>console.debug('fossil.fetch() XHR response:',r);
104109
}
105110
if(!f.onerror){
@@ -106,11 +111,11 @@
106111
f.onerror = function(e/*exception*/){
107112
console.error("fossil.fetch() XHR error:",e);
108113
if(e instanceof Error) F.error('Exception:',e);
109114
else F.error("Unknown error in handling of XHR request.");
110115
};
111
- }/*f.onerror()*/
116
+ }
112117
if(!f.parseResponseHeaders){
113118
f.parseResponseHeaders = function(h){
114119
const rc = {};
115120
if(!h) return rc;
116121
const ar = h.trim().split(/[\r\n]+/);
@@ -142,11 +147,11 @@
142147
|| payload instanceof Array)){
143148
payload = JSON.stringify(payload);
144149
opt.contentType = 'application/json';
145150
}
146151
}
147
- const url=[F.repoUrl(uri,opt.urlParams)],
152
+ const url=[f.urlTransform(uri,opt.urlParams)],
148153
x=new XMLHttpRequest();
149154
if('json'===opt.responseType){
150155
/* 'json' is an extension to the supported XHR.responseType
151156
list. We use it as a flag to tell us to JSON.parse()
152157
the response. */
@@ -201,8 +206,17 @@
201206
if(undefined!==payload) x.send(payload);
202207
else x.send();
203208
return this;
204209
};
205210
206
-window.fossil.fetch.beforesend = function(){};
207
-window.fossil.fetch.aftersend = function(){};
208
-window.fossil.fetch.timeout = 15000/* Default timeout, in ms. */;
211
+/**
212
+ urlTransform() must refer to a function which accepts a relative path
213
+ to the same site as fetch() is served from and an optional set of
214
+ URL parameters to pass with it (in the form a of a string
215
+ ("a=b&c=d...") or an object of key/value pairs (which it converts
216
+ to such a string), and returns the resulting URL or URI as a string.
217
+*/
218
+fossil.fetch.urlTransform = (u,p)=>fossil.repoUrl(u,p);
219
+fossil.fetch.beforesend = function(){};
220
+fossil.fetch.aftersend = function(){};
221
+fossil.fetch.timeout = 15000/* Default timeout, in ms. */;
222
+})(window.fossil);
209223
210224
ADDED src/fossil.numbered-lines.js
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -1,10 +1,13 @@
1 "use strict";
2 /**
3 Requires that window.fossil has already been set up.
4
5 window.fossil.fetch() is an HTTP request/response mini-framework
 
 
 
6 similar (but not identical) to the not-quite-ubiquitous
7 window.fetch().
8
9 JS usages:
10
@@ -87,19 +90,21 @@
87 function with the same name, e.g. fossil.fetch.onload(). The
88 default onload/onerror implementations route the data through the
89 dev console and (for onerror()) through fossil.error(). The default
90 beforesend/aftersend are no-ops. Individual pages may overwrite
91 those members to provide default implementations suitable for the
92 page's use, e.g. keeping track of how many in-flight
 
 
93
94 Note that this routine may add properties to the 2nd argument, so
95 that instance should not be kept around for later use.
96
97 Returns this object, noting that the XHR request is asynchronous,
98 and still in transit (or has yet to be sent) when that happens.
99 */
100 window.fossil.fetch = function f(uri,opt){
101 const F = fossil;
102 if(!f.onload){
103 f.onload = (r)=>console.debug('fossil.fetch() XHR response:',r);
104 }
105 if(!f.onerror){
@@ -106,11 +111,11 @@
106 f.onerror = function(e/*exception*/){
107 console.error("fossil.fetch() XHR error:",e);
108 if(e instanceof Error) F.error('Exception:',e);
109 else F.error("Unknown error in handling of XHR request.");
110 };
111 }/*f.onerror()*/
112 if(!f.parseResponseHeaders){
113 f.parseResponseHeaders = function(h){
114 const rc = {};
115 if(!h) return rc;
116 const ar = h.trim().split(/[\r\n]+/);
@@ -142,11 +147,11 @@
142 || payload instanceof Array)){
143 payload = JSON.stringify(payload);
144 opt.contentType = 'application/json';
145 }
146 }
147 const url=[F.repoUrl(uri,opt.urlParams)],
148 x=new XMLHttpRequest();
149 if('json'===opt.responseType){
150 /* 'json' is an extension to the supported XHR.responseType
151 list. We use it as a flag to tell us to JSON.parse()
152 the response. */
@@ -201,8 +206,17 @@
201 if(undefined!==payload) x.send(payload);
202 else x.send();
203 return this;
204 };
205
206 window.fossil.fetch.beforesend = function(){};
207 window.fossil.fetch.aftersend = function(){};
208 window.fossil.fetch.timeout = 15000/* Default timeout, in ms. */;
 
 
 
 
 
 
 
 
 
209
210 DDED src/fossil.numbered-lines.js
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -1,10 +1,13 @@
1 "use strict";
2 /**
3 Requires that window.fossil has already been set up.
4 */
5 (function(namespace){
6 const fossil = namespace;
7 /**
8 fetch() is an HTTP request/response mini-framework
9 similar (but not identical) to the not-quite-ubiquitous
10 window.fetch().
11
12 JS usages:
13
@@ -87,19 +90,21 @@
90 function with the same name, e.g. fossil.fetch.onload(). The
91 default onload/onerror implementations route the data through the
92 dev console and (for onerror()) through fossil.error(). The default
93 beforesend/aftersend are no-ops. Individual pages may overwrite
94 those members to provide default implementations suitable for the
95 page's use, e.g. keeping track of how many in-flight ajax requests
96 are pending. Any exceptions thrown in an beforesend/aftersend
97 handler are current ignored (feature or bug?).
98
99 Note that this routine may add properties to the 2nd argument, so
100 that instance should not be kept around for later use.
101
102 Returns this object, noting that the XHR request is asynchronous,
103 and still in transit (or has yet to be sent) when that happens.
104 */
105 fossil.fetch = function f(uri,opt){
106 const F = fossil;
107 if(!f.onload){
108 f.onload = (r)=>console.debug('fossil.fetch() XHR response:',r);
109 }
110 if(!f.onerror){
@@ -106,11 +111,11 @@
111 f.onerror = function(e/*exception*/){
112 console.error("fossil.fetch() XHR error:",e);
113 if(e instanceof Error) F.error('Exception:',e);
114 else F.error("Unknown error in handling of XHR request.");
115 };
116 }
117 if(!f.parseResponseHeaders){
118 f.parseResponseHeaders = function(h){
119 const rc = {};
120 if(!h) return rc;
121 const ar = h.trim().split(/[\r\n]+/);
@@ -142,11 +147,11 @@
147 || payload instanceof Array)){
148 payload = JSON.stringify(payload);
149 opt.contentType = 'application/json';
150 }
151 }
152 const url=[f.urlTransform(uri,opt.urlParams)],
153 x=new XMLHttpRequest();
154 if('json'===opt.responseType){
155 /* 'json' is an extension to the supported XHR.responseType
156 list. We use it as a flag to tell us to JSON.parse()
157 the response. */
@@ -201,8 +206,17 @@
206 if(undefined!==payload) x.send(payload);
207 else x.send();
208 return this;
209 };
210
211 /**
212 urlTransform() must refer to a function which accepts a relative path
213 to the same site as fetch() is served from and an optional set of
214 URL parameters to pass with it (in the form a of a string
215 ("a=b&c=d...") or an object of key/value pairs (which it converts
216 to such a string), and returns the resulting URL or URI as a string.
217 */
218 fossil.fetch.urlTransform = (u,p)=>fossil.repoUrl(u,p);
219 fossil.fetch.beforesend = function(){};
220 fossil.fetch.aftersend = function(){};
221 fossil.fetch.timeout = 15000/* Default timeout, in ms. */;
222 })(window.fossil);
223
224 DDED src/fossil.numbered-lines.js
--- a/src/fossil.numbered-lines.js
+++ b/src/fossil.numbered-lines.js
@@ -0,0 +1,8 @@
1
+(function callee(arg){
2
+ /*
3
+ JSelse if(!arg){tion callee(arg){
4
+ /*
5
+ JS(function callee(arg){
6
+ /*
7
+ JSfossil',
8
+ (
--- a/src/fossil.numbered-lines.js
+++ b/src/fossil.numbered-lines.js
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
--- a/src/fossil.numbered-lines.js
+++ b/src/fossil.numbered-lines.js
@@ -0,0 +1,8 @@
1 (function callee(arg){
2 /*
3 JSelse if(!arg){tion callee(arg){
4 /*
5 JS(function callee(arg){
6 /*
7 JSfossil',
8 (
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -121,11 +121,11 @@
121121
and that would be horribly inefficient (meaning "battery-consuming"
122122
on mobile devices).
123123
*/
124124
const $stash = {
125125
keys: {
126
- index: F.page.name+'/index'
126
+ index: F.page.name+'.index'
127127
},
128128
/**
129129
index: {
130130
"CHECKIN_HASH:FILENAME": {file info w/o content}
131131
...
@@ -149,27 +149,12 @@
149149
/** Returns the index object, fetching it from the stash or creating
150150
it anew on the first call. */
151151
getIndex: function(){
152152
if(!this.index){
153153
this.index = F.storage.getJSON(
154
- this.keys.index, undefined
154
+ this.keys.index, {}
155155
);
156
- if(!this.index){
157
- /*check for and remove/replace older name. This whole block
158
- can be removed once the test phase is done (don't want to
159
- invalidate the testers' edits on the test server). When
160
- doing so, be sure to replace undefined in the above
161
- getJSON() call with {}. */
162
- const oldName = F.page.name+':index';
163
- this.index = F.storage.getJSON(oldName,undefined);
164
- if(this.index){
165
- F.storage.remove(oldName);
166
- this.storeIndex();
167
- }else{
168
- this.index = {};
169
- }
170
- }
171156
}
172157
return this.index;
173158
},
174159
_fireStashEvent: function(){
175160
if(this._disableNextEvent) delete this._disableNextEvent;
@@ -300,30 +285,44 @@
300285
this.e.selectCi,
301286
this.e.selectFiles
302287
),"Loading leaves...");
303288
D.disable(this.e.btnLoadFile, this.e.selectFiles, this.e.selectCi);
304289
const self = this;
305
- F.fetch('fileedit/filelist',{
306
- urlParams:'leaves',
307
- responseType: 'json',
308
- onload: function(list){
309
- D.append(D.clearElement(self.e.ciListLabel),
310
- "Open leaves (newest first):");
311
- self.cache.checkins = list;
312
- D.clearElement(D.enable(self.e.selectCi));
313
- let loadThisOne;
314
- list.forEach(function(o,n){
315
- if(!n) loadThisOne = o;
316
- self.cache.branchNames[F.hashDigits(o.checkin,true)] = o.branch;
317
- D.option(self.e.selectCi, o.checkin,
318
- o.timestamp+' ['+o.branch+']: '
319
- +F.hashDigits(o.checkin));
320
- });
321
- F.storage.setJSON(self.cache.branchKey, self.cache.branchNames);
322
- self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
323
- }
324
- });
290
+ const onload = function(list){
291
+ D.append(D.clearElement(self.e.ciListLabel),
292
+ "Open leaves (newest first):");
293
+ self.cache.checkins = list;
294
+ D.clearElement(D.enable(self.e.selectCi));
295
+ let loadThisOne = P.initialFiles/*possibly injected at page-load time*/;
296
+ if(loadThisOne){
297
+ self.cache.files[loadThisOne.checkin] = loadThisOne;
298
+ delete P.initialFiles;
299
+ }
300
+ list.forEach(function(o,n){
301
+ if(!n && !loadThisOne) loadThisOne = o;
302
+ self.cache.branchNames[F.hashDigits(o.checkin,true)] = o.branch;
303
+ D.option(self.e.selectCi, o.checkin,
304
+ o.timestamp+' ['+o.branch+']: '
305
+ +F.hashDigits(o.checkin));
306
+ });
307
+ F.storage.setJSON(self.cache.branchKey, self.cache.branchNames);
308
+ if(loadThisOne){
309
+ self.e.selectCi.value = loadThisOne.checkin;
310
+ }
311
+ self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
312
+ };
313
+ if(P.initialLeaves/*injected at page-load time.*/){
314
+ const lv = P.initialLeaves;
315
+ delete P.initialLeaves;
316
+ onload(lv);
317
+ }else{
318
+ F.fetch('fileedit/filelist',{
319
+ urlParams:'leaves',
320
+ responseType: 'json',
321
+ onload: onload
322
+ });
323
+ }
325324
},
326325
/**
327326
Loads the file list for the given checkin UUID. It uses a
328327
cached copy on subsequent calls for the same UUID. If passed a
329328
falsy value, it instead clears and disables the file selection
@@ -387,20 +386,20 @@
387386
Initializes the checkin/file selector widget. Must only be
388387
called once.
389388
*/
390389
init: function(){
391390
this.cache.branchNames = F.storage.getJSON(this.cache.branchKey, {});
392
- const selCi = this.e.selectCi = D.select(),
391
+ const selCi = this.e.selectCi = D.addClass(D.select(), 'flex-grow'),
393392
selFiles = this.e.selectFiles
394393
= D.addClass(D.select(), 'file-list'),
395394
btnLoad = this.e.btnLoadFile =
396395
D.addClass(D.button("Load file"), "flex-shrink"),
397396
filesLabel = this.e.fileListLabel =
398397
D.addClass(D.div(),'flex-shrink','file-list-label'),
399398
ciLabelWrapper = D.addClass(
400399
D.div(), 'flex-container','flex-row', 'flex-shrink',
401
- 'stretch'
400
+ 'stretch', 'child-gap-small'
402401
),
403402
btnReload = D.addClass(
404403
D.button('Reload'), 'flex-shrink'
405404
),
406405
ciLabel = this.e.ciListLabel =
@@ -410,34 +409,47 @@
410409
D.attr(selFiles, 'title',
411410
"The list of editable files for the selected checkin.");
412411
D.attr(btnLoad, 'title',
413412
"Load the selected file into the editor.");
414413
D.disable(selCi, selFiles, btnLoad);
415
- D.attr(selFiles, 'size', 10);
414
+ D.attr(selFiles, 'size', 12);
416415
D.append(
417416
this.e.container,
417
+ ciLabel,
418418
D.append(ciLabelWrapper,
419
- btnReload, ciLabel),
420
- selCi,
419
+ selCi,
420
+ btnReload),
421421
filesLabel,
422422
selFiles,
423423
/* Use a wrapper for btnLoad so that the button itself does not
424424
stretch to fill the parent width: */
425425
D.append(D.addClass(D.div(), 'flex-shrink'), btnLoad)
426426
);
427
+ if(F.config['fileedit-glob']){
428
+ D.append(
429
+ this.e.container,
430
+ D.append(
431
+ D.span(),
432
+ D.append(D.code(),"fileedit-glob"),
433
+ " config setting = ",
434
+ D.append(D.code(), JSON.stringify(F.config['fileedit-glob']))
435
+ )
436
+ );
437
+ }
438
+
427439
this.loadLeaves();
428440
selCi.addEventListener(
429441
'change', (e)=>this.loadFiles(e.target.value), false
430442
);
431
- btnLoad.addEventListener(
432
- 'click', (e)=>{
433
- this.finfo.filename = selFiles.value;
434
- if(this.finfo.filename){
435
- P.loadFile(this.finfo.filename, this.finfo.checkin);
436
- }
437
- }, false
438
- );
443
+ const doLoad = (e)=>{
444
+ this.finfo.filename = selFiles.value;
445
+ if(this.finfo.filename){
446
+ P.loadFile(this.finfo.filename, this.finfo.checkin);
447
+ }
448
+ };
449
+ btnLoad.addEventListener('click', doLoad, false);
450
+ selFiles.addEventListener('dblclick', doLoad, false);
439451
btnReload.addEventListener(
440452
'click', (e)=>this.loadLeaves(), false
441453
);
442454
delete this.init;
443455
}
@@ -453,11 +465,11 @@
453465
D.attr(D.div(),'id','fileedit-stash-selector'),
454466
'input-with-label'
455467
);
456468
const sel = this.e.select = D.select();
457469
const btnClear = this.e.btnClear
458
- = D.addClass(D.button("Clear"),'hidden');
470
+ = D.button("Discard Edits");
459471
D.append(wrapper, "Local edits (",
460472
D.append(D.code(),
461473
F.storage.storageImplName()),
462474
"):",
463475
sel, btnClear);
@@ -472,23 +484,34 @@
472484
F.page.addEventListener('fileedit-file-loaded',(e)=>this.updateList($stash, e.detail));
473485
sel.addEventListener('change',function(e){
474486
const opt = this.selectedOptions[0];
475487
if(opt && opt._finfo) P.loadFile(opt._finfo);
476488
});
477
- F.confirmer(btnClear, {
478
- confirmText: "REALLY delete ALL local edits?",
479
- onconfirm: (e)=>P.clearStash().loadFile(/*in case P.finfo() was in the stash*/),
480
- ticks: 3
481
- });
482489
if(F.storage.isTransient()){/*Warn if our storage is particularly transient...*/
483490
D.append(wrapper, D.append(
484491
D.addClass(D.span(),'warning'),
485492
"Warning: persistent storage is not available, "+
486493
"so uncomitted edits will not survive a page reload."
487494
));
488495
}
489496
domInsertPoint.parentNode.insertBefore(wrapper, domInsertPoint);
497
+ F.confirmer(btnClear, {
498
+ /* must come after insertion into the DOM for the pinSize option to work. */
499
+ pinSize: true,
500
+ confirmText: "DISCARD all local edits?",
501
+ onconfirm: function(e){
502
+ if(P.finfo){
503
+ const stashed = P.getStashedFinfo(P.finfo);
504
+ P.clearStash();
505
+ if(stashed) P.loadFile(/*reload after discarding edits*/);
506
+ }else{
507
+ P.clearStash();
508
+ }
509
+ },
510
+ ticks: F.config.confirmerButtonTicks
511
+ });
512
+ D.addClass(this.e.btnClear,'hidden' /* must not be set until after confirmer is set up!*/);
490513
$stash._fireStashEvent(/*read the page-load-time stash*/);
491514
delete this.init;
492515
},
493516
/**
494517
Regenerates the edit selection list.
@@ -521,20 +544,20 @@
521544
return;
522545
}
523546
D.enable(this.e.select);
524547
D.removeClass(this.e.btnClear, 'hidden');
525548
D.disable(D.option(this.e.select,0,"Select a local edit..."));
526
- const currentFinfo = theFinfo || P.finfo || {};
549
+ const currentFinfo = theFinfo || P.finfo || {filename:''};
527550
ilist.sort(f.compare).forEach(function(finfo,n){
528551
const key = stasher.indexKey(finfo),
529552
branch = finfo.branch
530553
|| P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
531554
/* Remember that we don't know the branch name for non-leaf versions
532555
which P.fileSelectWidget() has never seen/cached. */
533556
const opt = D.option(
534557
self.e.select, n+1/*value is (almost) irrelevant*/,
535
- [F.hashDigits(finfo.checkin, 6), ' [',branch||'?branch?','] ',
558
+ [F.hashDigits(finfo.checkin), ' [',branch||'?branch?','] ',
536559
f.timestring(new Date(finfo.stashTime)),' ',
537560
false ? finfo.filename : F.shortenFilename(finfo.filename)
538561
].join('')
539562
);
540563
opt._finfo = finfo;
@@ -637,11 +660,11 @@
637660
previewTarget: E('#fileedit-tab-preview-wrapper'),
638661
manifestTarget: E('#fileedit-manifest'),
639662
diffTarget: E('#fileedit-tab-diff-wrapper'),
640663
cbIsExe: E('input[type=checkbox][name=exec_bit]'),
641664
cbManifest: E('input[type=checkbox][name=include_manifest]'),
642
- fsFileVersionDetails: E('#file-version-details'),
665
+ editStatus: E('#fileedit-edit-status'),
643666
tabs:{
644667
content: E('#fileedit-tab-content'),
645668
preview: E('#fileedit-tab-preview'),
646669
diff: E('#fileedit-tab-diff'),
647670
commit: E('#fileedit-tab-commit'),
@@ -659,24 +682,24 @@
659682
}else{
660683
P.e.taComment = P.e.taCommentSmall;
661684
D.addClass(P.e.taCommentBig, 'hidden');
662685
}
663686
D.removeClass(P.e.taComment, 'hidden');
664
-
665687
P.tabs.e.container.insertBefore(
666688
/* Move the status bar between the tab buttons and
667689
tab panels. Seems to be the best fit in terms of
668690
functionality and visibility. */
669691
E('#fossil-status-bar'), P.tabs.e.tabs
670692
);
693
+ P.tabs.e.container.insertBefore(P.e.editStatus, P.tabs.e.tabs);
671694
672695
P.tabs.addEventListener(
673696
/* Set up auto-refresh of the preview tab... */
674697
'before-switch-to', function(ev){
675698
if(ev.detail===P.e.tabs.preview){
676699
P.baseHrefForFile();
677
- if(P.e.cbAutoPreview.checked) P.preview();
700
+ if(P.previewNeedsUpdate && P.e.cbAutoPreview.checked) P.preview();
678701
}else if(ev.detail===P.e.tabs.diff){
679702
/* Work around a weird bug where the page gets wider than
680703
the window when the diff tab is NOT in view and the
681704
current SBS diff widget is wider than the window. When
682705
the diff IS in view then CSS overflow magically reduces
@@ -715,13 +738,14 @@
715738
);
716739
P.e.btnCommit.addEventListener(
717740
"click",(e)=>P.commit(), false
718741
);
719742
F.confirmer(P.e.btnReload, {
743
+ pinSize: true,
720744
confirmText: "Really reload, losing edits?",
721745
onconfirm: (e)=>P.unstashContent().loadFile(),
722
- ticks: 3
746
+ ticks: F.config.confirmerButtonTicks
723747
});
724748
E('#comment-toggle').addEventListener(
725749
"click",(e)=>P.toggleCommentMode(), false
726750
);
727751
@@ -774,11 +798,14 @@
774798
}
775799
776800
P.addEventListener(
777801
// Clear certain views when new content is loaded/set
778802
'fileedit-content-replaced',
779
- ()=>D.clearElement(P.e.diffTarget, P.e.previewTarget, P.e.manifestTarget)
803
+ ()=>{
804
+ P.previewNeedsUpdate = true;
805
+ D.clearElement(P.e.diffTarget, P.e.previewTarget, P.e.manifestTarget);
806
+ }
780807
);
781808
P.addEventListener(
782809
// Clear certain views after a non-dry-run commit
783810
'fileedit-committed',
784811
(e)=>{
@@ -789,11 +816,10 @@
789816
);
790817
791818
P.fileSelectWidget.init();
792819
P.stashWidget.init(
793820
P.e.tabs.content.lastElementChild
794
- //P.e.tabs.fileSelect.querySelector("h1")
795821
);
796822
}/*F.onPageLoad()*/);
797823
798824
/**
799825
Getter (if called with no args) or setter (if passed an arg) for
@@ -819,11 +845,11 @@
819845
For use when installing a custom editor widget. Pass it the
820846
getter and setter callbacks to fetch resp. set the content of the
821847
custom widget. They will be triggered via
822848
P.fileContent(). Returns this object.
823849
*/
824
- P.setFileContentMethods = function(getter, setter){
850
+ P.setContentMethods = function(getter, setter){
825851
this.fileContent.get = getter;
826852
this.fileContent.set = setter;
827853
return this;
828854
};
829855
@@ -929,63 +955,55 @@
929955
updateVersion() updates the filename and version in various UI
930956
elements...
931957
932958
Returns this object.
933959
*/
934
- P.updateVersion = function(file,rev){
960
+ P.updateVersion = function f(file,rev){
961
+ if(!f.eLinks){
962
+ f.eName = P.e.editStatus.querySelector('span.name');
963
+ f.eLinks = P.e.editStatus.querySelector('span.links');
964
+ }
935965
if(1===arguments.length){/*assume object*/
936966
this.finfo = arguments[0];
937967
file = this.finfo.filename;
938968
rev = this.finfo.checkin;
939969
}else if(0===arguments.length){
940
- if(!affirmHasFile()) return this;
941
- file = this.finfo.filename;
942
- rev = this.finfo.checkin;
970
+ if(affirmHasFile()){
971
+ file = this.finfo.filename;
972
+ rev = this.finfo.checkin;
973
+ }
943974
}else{
944975
this.finfo = {filename:file,checkin:rev};
945976
}
946
- const eTgt = this.e.fsFileVersionDetails.querySelector('div'),
947
- rHuman = F.hashDigits(rev),
948
- rUrl = F.hashDigits(rev,true);
949
- D.clearElement(eTgt);
950
- D.append(
951
- eTgt, "File: ",
952
- D.append(D.code(),
953
- D.a(F.repoUrl('finfo',{name:file, m:rUrl}), file)),
954
- D.br()
955
- );
956
- D.append(
957
- eTgt, "Checkin: ",
958
- D.append(D.code(), D.a(F.repoUrl('info/'+rUrl), rHuman)),
959
- " [",D.a(F.repoUrl('timeline',{m:rUrl}), "timeline"),"]",
960
- D.br()
961
- );
962
- D.append(
963
- eTgt, "Mimetype: ",
964
- D.append(D.code(), this.finfo.mimetype||'???'),
965
- D.br()
966
- );
967
- D.append(
968
- eTgt,
969
- D.append(D.code(), "[",
970
- D.a(F.repoUrl('annotate',{filename:file, checkin:rUrl}),
971
- 'annotate'), "]"),
972
- D.append(D.code(), "[",
973
- D.a(F.repoUrl('blame',{filename:file, checkin:rUrl}),
974
- 'blame'), "]")
977
+ const fi = this.finfo;
978
+ D.clearElement(f.eName, f.eLinks);
979
+ if(!fi){
980
+ D.append(f.eName, '(no file loaded)');
981
+ return this;
982
+ }
983
+ const rHuman = F.hashDigits(rev),
984
+ rUrl = F.hashDigits(rev,true);
985
+
986
+ //TODO? port over is-edited marker from /wikiedit
987
+ //var marker = getEditMarker(wi, false);
988
+ D.append(f.eName/*,marker*/,D.a(F.repoUrl('finfo',{name:file, m:rUrl}), file));
989
+
990
+ D.append(
991
+ f.eLinks,
992
+ D.append(D.span(), fi.mimetype||'?mimetype?'),
993
+ D.a(F.repoUrl('info/'+rUrl), rHuman),
994
+ D.a(F.repoUrl('timeline',{m:rUrl}), "timeline"),
995
+ D.a(F.repoUrl('annotate',{filename:file, checkin:rUrl}),'annotate'),
996
+ D.a(F.repoUrl('blame',{filename:file, checkin:rUrl}),'blame')
975997
);
976998
const purlArgs = F.encodeUrlArgs({
977999
filename: this.finfo.filename,
9781000
checkin: rUrl
9791001
},false,true);
9801002
const purl = F.repoUrl('fileedit',purlArgs);
981
- D.append(
982
- eTgt,
983
- D.append(D.code(),
984
- "[",D.a(purl,"Editor permalink"),"]")
985
- );
986
- this.setPageTitle("Edit: "+this.finfo.filename);
1003
+ D.append( f.eLinks, D.a(purl,"editor permalink") );
1004
+ this.setPageTitle("Edit: "+fi.filename);
9871005
return this;
9881006
};
9891007
9901008
/**
9911009
loadFile() loads (file,checkinVersion) and updates the relevant
@@ -1032,10 +1050,11 @@
10321050
mimetype: headers['content-type'].split(';').shift()
10331051
});
10341052
self.tabs.switchToTab(self.e.tabs.content);
10351053
self.e.cbIsExe.checked = self.finfo.isExe;
10361054
self.fileContent(r);
1055
+ P.previewNeedsUpdate = true;
10371056
self.dispatchEvent('fileedit-file-loaded', self.finfo);
10381057
};
10391058
const semiFinfo = {filename: file, checkin: rev};
10401059
const stashFinfo = this.getStashedFinfo(semiFinfo);
10411060
if(stashFinfo){ // fake a response from the stash...
@@ -1115,10 +1134,11 @@
11151134
P.selectPreviewMode(P.previewModes[header]);
11161135
if('wiki'===header) P.baseHrefForFile();
11171136
else P.baseHrefRestore();
11181137
callback(r);
11191138
F.message('Updated preview.');
1139
+ P.previewNeedsUpdate = false;
11201140
P.dispatchEvent('fileedit-preview-updated',{
11211141
previewMode: P.previewModes.current,
11221142
mimetype: P.finfo.mimetype,
11231143
element: P.e.previewTarget
11241144
});
@@ -1290,10 +1310,11 @@
12901310
}else{
12911311
$stash.updateFile(fi, P.fileContent());
12921312
}
12931313
F.message("Stashed change to",F.hashDigits(fi.checkin),fi.filename);
12941314
$stash.prune();
1315
+ this.previewNeedsUpdate = true;
12951316
}
12961317
return this;
12971318
};
12981319
12991320
/**
@@ -1301,10 +1322,11 @@
13011322
F.storage. Returns this.
13021323
*/
13031324
P.unstashContent = function(){
13041325
const finfo = arguments[0] || this.finfo;
13051326
if(finfo){
1327
+ this.previewNeedsUpdate = true;
13061328
$stash.unstash(finfo);
13071329
//console.debug("Unstashed",finfo);
13081330
F.message("Unstashed",F.hashDigits(finfo.checkin),finfo.filename);
13091331
}
13101332
return this;
13111333
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -121,11 +121,11 @@
121 and that would be horribly inefficient (meaning "battery-consuming"
122 on mobile devices).
123 */
124 const $stash = {
125 keys: {
126 index: F.page.name+'/index'
127 },
128 /**
129 index: {
130 "CHECKIN_HASH:FILENAME": {file info w/o content}
131 ...
@@ -149,27 +149,12 @@
149 /** Returns the index object, fetching it from the stash or creating
150 it anew on the first call. */
151 getIndex: function(){
152 if(!this.index){
153 this.index = F.storage.getJSON(
154 this.keys.index, undefined
155 );
156 if(!this.index){
157 /*check for and remove/replace older name. This whole block
158 can be removed once the test phase is done (don't want to
159 invalidate the testers' edits on the test server). When
160 doing so, be sure to replace undefined in the above
161 getJSON() call with {}. */
162 const oldName = F.page.name+':index';
163 this.index = F.storage.getJSON(oldName,undefined);
164 if(this.index){
165 F.storage.remove(oldName);
166 this.storeIndex();
167 }else{
168 this.index = {};
169 }
170 }
171 }
172 return this.index;
173 },
174 _fireStashEvent: function(){
175 if(this._disableNextEvent) delete this._disableNextEvent;
@@ -300,30 +285,44 @@
300 this.e.selectCi,
301 this.e.selectFiles
302 ),"Loading leaves...");
303 D.disable(this.e.btnLoadFile, this.e.selectFiles, this.e.selectCi);
304 const self = this;
305 F.fetch('fileedit/filelist',{
306 urlParams:'leaves',
307 responseType: 'json',
308 onload: function(list){
309 D.append(D.clearElement(self.e.ciListLabel),
310 "Open leaves (newest first):");
311 self.cache.checkins = list;
312 D.clearElement(D.enable(self.e.selectCi));
313 let loadThisOne;
314 list.forEach(function(o,n){
315 if(!n) loadThisOne = o;
316 self.cache.branchNames[F.hashDigits(o.checkin,true)] = o.branch;
317 D.option(self.e.selectCi, o.checkin,
318 o.timestamp+' ['+o.branch+']: '
319 +F.hashDigits(o.checkin));
320 });
321 F.storage.setJSON(self.cache.branchKey, self.cache.branchNames);
322 self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
323 }
324 });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325 },
326 /**
327 Loads the file list for the given checkin UUID. It uses a
328 cached copy on subsequent calls for the same UUID. If passed a
329 falsy value, it instead clears and disables the file selection
@@ -387,20 +386,20 @@
387 Initializes the checkin/file selector widget. Must only be
388 called once.
389 */
390 init: function(){
391 this.cache.branchNames = F.storage.getJSON(this.cache.branchKey, {});
392 const selCi = this.e.selectCi = D.select(),
393 selFiles = this.e.selectFiles
394 = D.addClass(D.select(), 'file-list'),
395 btnLoad = this.e.btnLoadFile =
396 D.addClass(D.button("Load file"), "flex-shrink"),
397 filesLabel = this.e.fileListLabel =
398 D.addClass(D.div(),'flex-shrink','file-list-label'),
399 ciLabelWrapper = D.addClass(
400 D.div(), 'flex-container','flex-row', 'flex-shrink',
401 'stretch'
402 ),
403 btnReload = D.addClass(
404 D.button('Reload'), 'flex-shrink'
405 ),
406 ciLabel = this.e.ciListLabel =
@@ -410,34 +409,47 @@
410 D.attr(selFiles, 'title',
411 "The list of editable files for the selected checkin.");
412 D.attr(btnLoad, 'title',
413 "Load the selected file into the editor.");
414 D.disable(selCi, selFiles, btnLoad);
415 D.attr(selFiles, 'size', 10);
416 D.append(
417 this.e.container,
 
418 D.append(ciLabelWrapper,
419 btnReload, ciLabel),
420 selCi,
421 filesLabel,
422 selFiles,
423 /* Use a wrapper for btnLoad so that the button itself does not
424 stretch to fill the parent width: */
425 D.append(D.addClass(D.div(), 'flex-shrink'), btnLoad)
426 );
 
 
 
 
 
 
 
 
 
 
 
 
427 this.loadLeaves();
428 selCi.addEventListener(
429 'change', (e)=>this.loadFiles(e.target.value), false
430 );
431 btnLoad.addEventListener(
432 'click', (e)=>{
433 this.finfo.filename = selFiles.value;
434 if(this.finfo.filename){
435 P.loadFile(this.finfo.filename, this.finfo.checkin);
436 }
437 }, false
438 );
439 btnReload.addEventListener(
440 'click', (e)=>this.loadLeaves(), false
441 );
442 delete this.init;
443 }
@@ -453,11 +465,11 @@
453 D.attr(D.div(),'id','fileedit-stash-selector'),
454 'input-with-label'
455 );
456 const sel = this.e.select = D.select();
457 const btnClear = this.e.btnClear
458 = D.addClass(D.button("Clear"),'hidden');
459 D.append(wrapper, "Local edits (",
460 D.append(D.code(),
461 F.storage.storageImplName()),
462 "):",
463 sel, btnClear);
@@ -472,23 +484,34 @@
472 F.page.addEventListener('fileedit-file-loaded',(e)=>this.updateList($stash, e.detail));
473 sel.addEventListener('change',function(e){
474 const opt = this.selectedOptions[0];
475 if(opt && opt._finfo) P.loadFile(opt._finfo);
476 });
477 F.confirmer(btnClear, {
478 confirmText: "REALLY delete ALL local edits?",
479 onconfirm: (e)=>P.clearStash().loadFile(/*in case P.finfo() was in the stash*/),
480 ticks: 3
481 });
482 if(F.storage.isTransient()){/*Warn if our storage is particularly transient...*/
483 D.append(wrapper, D.append(
484 D.addClass(D.span(),'warning'),
485 "Warning: persistent storage is not available, "+
486 "so uncomitted edits will not survive a page reload."
487 ));
488 }
489 domInsertPoint.parentNode.insertBefore(wrapper, domInsertPoint);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490 $stash._fireStashEvent(/*read the page-load-time stash*/);
491 delete this.init;
492 },
493 /**
494 Regenerates the edit selection list.
@@ -521,20 +544,20 @@
521 return;
522 }
523 D.enable(this.e.select);
524 D.removeClass(this.e.btnClear, 'hidden');
525 D.disable(D.option(this.e.select,0,"Select a local edit..."));
526 const currentFinfo = theFinfo || P.finfo || {};
527 ilist.sort(f.compare).forEach(function(finfo,n){
528 const key = stasher.indexKey(finfo),
529 branch = finfo.branch
530 || P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
531 /* Remember that we don't know the branch name for non-leaf versions
532 which P.fileSelectWidget() has never seen/cached. */
533 const opt = D.option(
534 self.e.select, n+1/*value is (almost) irrelevant*/,
535 [F.hashDigits(finfo.checkin, 6), ' [',branch||'?branch?','] ',
536 f.timestring(new Date(finfo.stashTime)),' ',
537 false ? finfo.filename : F.shortenFilename(finfo.filename)
538 ].join('')
539 );
540 opt._finfo = finfo;
@@ -637,11 +660,11 @@
637 previewTarget: E('#fileedit-tab-preview-wrapper'),
638 manifestTarget: E('#fileedit-manifest'),
639 diffTarget: E('#fileedit-tab-diff-wrapper'),
640 cbIsExe: E('input[type=checkbox][name=exec_bit]'),
641 cbManifest: E('input[type=checkbox][name=include_manifest]'),
642 fsFileVersionDetails: E('#file-version-details'),
643 tabs:{
644 content: E('#fileedit-tab-content'),
645 preview: E('#fileedit-tab-preview'),
646 diff: E('#fileedit-tab-diff'),
647 commit: E('#fileedit-tab-commit'),
@@ -659,24 +682,24 @@
659 }else{
660 P.e.taComment = P.e.taCommentSmall;
661 D.addClass(P.e.taCommentBig, 'hidden');
662 }
663 D.removeClass(P.e.taComment, 'hidden');
664
665 P.tabs.e.container.insertBefore(
666 /* Move the status bar between the tab buttons and
667 tab panels. Seems to be the best fit in terms of
668 functionality and visibility. */
669 E('#fossil-status-bar'), P.tabs.e.tabs
670 );
 
671
672 P.tabs.addEventListener(
673 /* Set up auto-refresh of the preview tab... */
674 'before-switch-to', function(ev){
675 if(ev.detail===P.e.tabs.preview){
676 P.baseHrefForFile();
677 if(P.e.cbAutoPreview.checked) P.preview();
678 }else if(ev.detail===P.e.tabs.diff){
679 /* Work around a weird bug where the page gets wider than
680 the window when the diff tab is NOT in view and the
681 current SBS diff widget is wider than the window. When
682 the diff IS in view then CSS overflow magically reduces
@@ -715,13 +738,14 @@
715 );
716 P.e.btnCommit.addEventListener(
717 "click",(e)=>P.commit(), false
718 );
719 F.confirmer(P.e.btnReload, {
 
720 confirmText: "Really reload, losing edits?",
721 onconfirm: (e)=>P.unstashContent().loadFile(),
722 ticks: 3
723 });
724 E('#comment-toggle').addEventListener(
725 "click",(e)=>P.toggleCommentMode(), false
726 );
727
@@ -774,11 +798,14 @@
774 }
775
776 P.addEventListener(
777 // Clear certain views when new content is loaded/set
778 'fileedit-content-replaced',
779 ()=>D.clearElement(P.e.diffTarget, P.e.previewTarget, P.e.manifestTarget)
 
 
 
780 );
781 P.addEventListener(
782 // Clear certain views after a non-dry-run commit
783 'fileedit-committed',
784 (e)=>{
@@ -789,11 +816,10 @@
789 );
790
791 P.fileSelectWidget.init();
792 P.stashWidget.init(
793 P.e.tabs.content.lastElementChild
794 //P.e.tabs.fileSelect.querySelector("h1")
795 );
796 }/*F.onPageLoad()*/);
797
798 /**
799 Getter (if called with no args) or setter (if passed an arg) for
@@ -819,11 +845,11 @@
819 For use when installing a custom editor widget. Pass it the
820 getter and setter callbacks to fetch resp. set the content of the
821 custom widget. They will be triggered via
822 P.fileContent(). Returns this object.
823 */
824 P.setFileContentMethods = function(getter, setter){
825 this.fileContent.get = getter;
826 this.fileContent.set = setter;
827 return this;
828 };
829
@@ -929,63 +955,55 @@
929 updateVersion() updates the filename and version in various UI
930 elements...
931
932 Returns this object.
933 */
934 P.updateVersion = function(file,rev){
 
 
 
 
935 if(1===arguments.length){/*assume object*/
936 this.finfo = arguments[0];
937 file = this.finfo.filename;
938 rev = this.finfo.checkin;
939 }else if(0===arguments.length){
940 if(!affirmHasFile()) return this;
941 file = this.finfo.filename;
942 rev = this.finfo.checkin;
 
943 }else{
944 this.finfo = {filename:file,checkin:rev};
945 }
946 const eTgt = this.e.fsFileVersionDetails.querySelector('div'),
947 rHuman = F.hashDigits(rev),
948 rUrl = F.hashDigits(rev,true);
949 D.clearElement(eTgt);
950 D.append(
951 eTgt, "File: ",
952 D.append(D.code(),
953 D.a(F.repoUrl('finfo',{name:file, m:rUrl}), file)),
954 D.br()
955 );
956 D.append(
957 eTgt, "Checkin: ",
958 D.append(D.code(), D.a(F.repoUrl('info/'+rUrl), rHuman)),
959 " [",D.a(F.repoUrl('timeline',{m:rUrl}), "timeline"),"]",
960 D.br()
961 );
962 D.append(
963 eTgt, "Mimetype: ",
964 D.append(D.code(), this.finfo.mimetype||'???'),
965 D.br()
966 );
967 D.append(
968 eTgt,
969 D.append(D.code(), "[",
970 D.a(F.repoUrl('annotate',{filename:file, checkin:rUrl}),
971 'annotate'), "]"),
972 D.append(D.code(), "[",
973 D.a(F.repoUrl('blame',{filename:file, checkin:rUrl}),
974 'blame'), "]")
975 );
976 const purlArgs = F.encodeUrlArgs({
977 filename: this.finfo.filename,
978 checkin: rUrl
979 },false,true);
980 const purl = F.repoUrl('fileedit',purlArgs);
981 D.append(
982 eTgt,
983 D.append(D.code(),
984 "[",D.a(purl,"Editor permalink"),"]")
985 );
986 this.setPageTitle("Edit: "+this.finfo.filename);
987 return this;
988 };
989
990 /**
991 loadFile() loads (file,checkinVersion) and updates the relevant
@@ -1032,10 +1050,11 @@
1032 mimetype: headers['content-type'].split(';').shift()
1033 });
1034 self.tabs.switchToTab(self.e.tabs.content);
1035 self.e.cbIsExe.checked = self.finfo.isExe;
1036 self.fileContent(r);
 
1037 self.dispatchEvent('fileedit-file-loaded', self.finfo);
1038 };
1039 const semiFinfo = {filename: file, checkin: rev};
1040 const stashFinfo = this.getStashedFinfo(semiFinfo);
1041 if(stashFinfo){ // fake a response from the stash...
@@ -1115,10 +1134,11 @@
1115 P.selectPreviewMode(P.previewModes[header]);
1116 if('wiki'===header) P.baseHrefForFile();
1117 else P.baseHrefRestore();
1118 callback(r);
1119 F.message('Updated preview.');
 
1120 P.dispatchEvent('fileedit-preview-updated',{
1121 previewMode: P.previewModes.current,
1122 mimetype: P.finfo.mimetype,
1123 element: P.e.previewTarget
1124 });
@@ -1290,10 +1310,11 @@
1290 }else{
1291 $stash.updateFile(fi, P.fileContent());
1292 }
1293 F.message("Stashed change to",F.hashDigits(fi.checkin),fi.filename);
1294 $stash.prune();
 
1295 }
1296 return this;
1297 };
1298
1299 /**
@@ -1301,10 +1322,11 @@
1301 F.storage. Returns this.
1302 */
1303 P.unstashContent = function(){
1304 const finfo = arguments[0] || this.finfo;
1305 if(finfo){
 
1306 $stash.unstash(finfo);
1307 //console.debug("Unstashed",finfo);
1308 F.message("Unstashed",F.hashDigits(finfo.checkin),finfo.filename);
1309 }
1310 return this;
1311
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -121,11 +121,11 @@
121 and that would be horribly inefficient (meaning "battery-consuming"
122 on mobile devices).
123 */
124 const $stash = {
125 keys: {
126 index: F.page.name+'.index'
127 },
128 /**
129 index: {
130 "CHECKIN_HASH:FILENAME": {file info w/o content}
131 ...
@@ -149,27 +149,12 @@
149 /** Returns the index object, fetching it from the stash or creating
150 it anew on the first call. */
151 getIndex: function(){
152 if(!this.index){
153 this.index = F.storage.getJSON(
154 this.keys.index, {}
155 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156 }
157 return this.index;
158 },
159 _fireStashEvent: function(){
160 if(this._disableNextEvent) delete this._disableNextEvent;
@@ -300,30 +285,44 @@
285 this.e.selectCi,
286 this.e.selectFiles
287 ),"Loading leaves...");
288 D.disable(this.e.btnLoadFile, this.e.selectFiles, this.e.selectCi);
289 const self = this;
290 const onload = function(list){
291 D.append(D.clearElement(self.e.ciListLabel),
292 "Open leaves (newest first):");
293 self.cache.checkins = list;
294 D.clearElement(D.enable(self.e.selectCi));
295 let loadThisOne = P.initialFiles/*possibly injected at page-load time*/;
296 if(loadThisOne){
297 self.cache.files[loadThisOne.checkin] = loadThisOne;
298 delete P.initialFiles;
299 }
300 list.forEach(function(o,n){
301 if(!n && !loadThisOne) loadThisOne = o;
302 self.cache.branchNames[F.hashDigits(o.checkin,true)] = o.branch;
303 D.option(self.e.selectCi, o.checkin,
304 o.timestamp+' ['+o.branch+']: '
305 +F.hashDigits(o.checkin));
306 });
307 F.storage.setJSON(self.cache.branchKey, self.cache.branchNames);
308 if(loadThisOne){
309 self.e.selectCi.value = loadThisOne.checkin;
310 }
311 self.loadFiles(loadThisOne ? loadThisOne.checkin : false);
312 };
313 if(P.initialLeaves/*injected at page-load time.*/){
314 const lv = P.initialLeaves;
315 delete P.initialLeaves;
316 onload(lv);
317 }else{
318 F.fetch('fileedit/filelist',{
319 urlParams:'leaves',
320 responseType: 'json',
321 onload: onload
322 });
323 }
324 },
325 /**
326 Loads the file list for the given checkin UUID. It uses a
327 cached copy on subsequent calls for the same UUID. If passed a
328 falsy value, it instead clears and disables the file selection
@@ -387,20 +386,20 @@
386 Initializes the checkin/file selector widget. Must only be
387 called once.
388 */
389 init: function(){
390 this.cache.branchNames = F.storage.getJSON(this.cache.branchKey, {});
391 const selCi = this.e.selectCi = D.addClass(D.select(), 'flex-grow'),
392 selFiles = this.e.selectFiles
393 = D.addClass(D.select(), 'file-list'),
394 btnLoad = this.e.btnLoadFile =
395 D.addClass(D.button("Load file"), "flex-shrink"),
396 filesLabel = this.e.fileListLabel =
397 D.addClass(D.div(),'flex-shrink','file-list-label'),
398 ciLabelWrapper = D.addClass(
399 D.div(), 'flex-container','flex-row', 'flex-shrink',
400 'stretch', 'child-gap-small'
401 ),
402 btnReload = D.addClass(
403 D.button('Reload'), 'flex-shrink'
404 ),
405 ciLabel = this.e.ciListLabel =
@@ -410,34 +409,47 @@
409 D.attr(selFiles, 'title',
410 "The list of editable files for the selected checkin.");
411 D.attr(btnLoad, 'title',
412 "Load the selected file into the editor.");
413 D.disable(selCi, selFiles, btnLoad);
414 D.attr(selFiles, 'size', 12);
415 D.append(
416 this.e.container,
417 ciLabel,
418 D.append(ciLabelWrapper,
419 selCi,
420 btnReload),
421 filesLabel,
422 selFiles,
423 /* Use a wrapper for btnLoad so that the button itself does not
424 stretch to fill the parent width: */
425 D.append(D.addClass(D.div(), 'flex-shrink'), btnLoad)
426 );
427 if(F.config['fileedit-glob']){
428 D.append(
429 this.e.container,
430 D.append(
431 D.span(),
432 D.append(D.code(),"fileedit-glob"),
433 " config setting = ",
434 D.append(D.code(), JSON.stringify(F.config['fileedit-glob']))
435 )
436 );
437 }
438
439 this.loadLeaves();
440 selCi.addEventListener(
441 'change', (e)=>this.loadFiles(e.target.value), false
442 );
443 const doLoad = (e)=>{
444 this.finfo.filename = selFiles.value;
445 if(this.finfo.filename){
446 P.loadFile(this.finfo.filename, this.finfo.checkin);
447 }
448 };
449 btnLoad.addEventListener('click', doLoad, false);
450 selFiles.addEventListener('dblclick', doLoad, false);
451 btnReload.addEventListener(
452 'click', (e)=>this.loadLeaves(), false
453 );
454 delete this.init;
455 }
@@ -453,11 +465,11 @@
465 D.attr(D.div(),'id','fileedit-stash-selector'),
466 'input-with-label'
467 );
468 const sel = this.e.select = D.select();
469 const btnClear = this.e.btnClear
470 = D.button("Discard Edits");
471 D.append(wrapper, "Local edits (",
472 D.append(D.code(),
473 F.storage.storageImplName()),
474 "):",
475 sel, btnClear);
@@ -472,23 +484,34 @@
484 F.page.addEventListener('fileedit-file-loaded',(e)=>this.updateList($stash, e.detail));
485 sel.addEventListener('change',function(e){
486 const opt = this.selectedOptions[0];
487 if(opt && opt._finfo) P.loadFile(opt._finfo);
488 });
 
 
 
 
 
489 if(F.storage.isTransient()){/*Warn if our storage is particularly transient...*/
490 D.append(wrapper, D.append(
491 D.addClass(D.span(),'warning'),
492 "Warning: persistent storage is not available, "+
493 "so uncomitted edits will not survive a page reload."
494 ));
495 }
496 domInsertPoint.parentNode.insertBefore(wrapper, domInsertPoint);
497 F.confirmer(btnClear, {
498 /* must come after insertion into the DOM for the pinSize option to work. */
499 pinSize: true,
500 confirmText: "DISCARD all local edits?",
501 onconfirm: function(e){
502 if(P.finfo){
503 const stashed = P.getStashedFinfo(P.finfo);
504 P.clearStash();
505 if(stashed) P.loadFile(/*reload after discarding edits*/);
506 }else{
507 P.clearStash();
508 }
509 },
510 ticks: F.config.confirmerButtonTicks
511 });
512 D.addClass(this.e.btnClear,'hidden' /* must not be set until after confirmer is set up!*/);
513 $stash._fireStashEvent(/*read the page-load-time stash*/);
514 delete this.init;
515 },
516 /**
517 Regenerates the edit selection list.
@@ -521,20 +544,20 @@
544 return;
545 }
546 D.enable(this.e.select);
547 D.removeClass(this.e.btnClear, 'hidden');
548 D.disable(D.option(this.e.select,0,"Select a local edit..."));
549 const currentFinfo = theFinfo || P.finfo || {filename:''};
550 ilist.sort(f.compare).forEach(function(finfo,n){
551 const key = stasher.indexKey(finfo),
552 branch = finfo.branch
553 || P.fileSelectWidget.checkinBranchName(finfo.checkin)||'';
554 /* Remember that we don't know the branch name for non-leaf versions
555 which P.fileSelectWidget() has never seen/cached. */
556 const opt = D.option(
557 self.e.select, n+1/*value is (almost) irrelevant*/,
558 [F.hashDigits(finfo.checkin), ' [',branch||'?branch?','] ',
559 f.timestring(new Date(finfo.stashTime)),' ',
560 false ? finfo.filename : F.shortenFilename(finfo.filename)
561 ].join('')
562 );
563 opt._finfo = finfo;
@@ -637,11 +660,11 @@
660 previewTarget: E('#fileedit-tab-preview-wrapper'),
661 manifestTarget: E('#fileedit-manifest'),
662 diffTarget: E('#fileedit-tab-diff-wrapper'),
663 cbIsExe: E('input[type=checkbox][name=exec_bit]'),
664 cbManifest: E('input[type=checkbox][name=include_manifest]'),
665 editStatus: E('#fileedit-edit-status'),
666 tabs:{
667 content: E('#fileedit-tab-content'),
668 preview: E('#fileedit-tab-preview'),
669 diff: E('#fileedit-tab-diff'),
670 commit: E('#fileedit-tab-commit'),
@@ -659,24 +682,24 @@
682 }else{
683 P.e.taComment = P.e.taCommentSmall;
684 D.addClass(P.e.taCommentBig, 'hidden');
685 }
686 D.removeClass(P.e.taComment, 'hidden');
 
687 P.tabs.e.container.insertBefore(
688 /* Move the status bar between the tab buttons and
689 tab panels. Seems to be the best fit in terms of
690 functionality and visibility. */
691 E('#fossil-status-bar'), P.tabs.e.tabs
692 );
693 P.tabs.e.container.insertBefore(P.e.editStatus, P.tabs.e.tabs);
694
695 P.tabs.addEventListener(
696 /* Set up auto-refresh of the preview tab... */
697 'before-switch-to', function(ev){
698 if(ev.detail===P.e.tabs.preview){
699 P.baseHrefForFile();
700 if(P.previewNeedsUpdate && P.e.cbAutoPreview.checked) P.preview();
701 }else if(ev.detail===P.e.tabs.diff){
702 /* Work around a weird bug where the page gets wider than
703 the window when the diff tab is NOT in view and the
704 current SBS diff widget is wider than the window. When
705 the diff IS in view then CSS overflow magically reduces
@@ -715,13 +738,14 @@
738 );
739 P.e.btnCommit.addEventListener(
740 "click",(e)=>P.commit(), false
741 );
742 F.confirmer(P.e.btnReload, {
743 pinSize: true,
744 confirmText: "Really reload, losing edits?",
745 onconfirm: (e)=>P.unstashContent().loadFile(),
746 ticks: F.config.confirmerButtonTicks
747 });
748 E('#comment-toggle').addEventListener(
749 "click",(e)=>P.toggleCommentMode(), false
750 );
751
@@ -774,11 +798,14 @@
798 }
799
800 P.addEventListener(
801 // Clear certain views when new content is loaded/set
802 'fileedit-content-replaced',
803 ()=>{
804 P.previewNeedsUpdate = true;
805 D.clearElement(P.e.diffTarget, P.e.previewTarget, P.e.manifestTarget);
806 }
807 );
808 P.addEventListener(
809 // Clear certain views after a non-dry-run commit
810 'fileedit-committed',
811 (e)=>{
@@ -789,11 +816,10 @@
816 );
817
818 P.fileSelectWidget.init();
819 P.stashWidget.init(
820 P.e.tabs.content.lastElementChild
 
821 );
822 }/*F.onPageLoad()*/);
823
824 /**
825 Getter (if called with no args) or setter (if passed an arg) for
@@ -819,11 +845,11 @@
845 For use when installing a custom editor widget. Pass it the
846 getter and setter callbacks to fetch resp. set the content of the
847 custom widget. They will be triggered via
848 P.fileContent(). Returns this object.
849 */
850 P.setContentMethods = function(getter, setter){
851 this.fileContent.get = getter;
852 this.fileContent.set = setter;
853 return this;
854 };
855
@@ -929,63 +955,55 @@
955 updateVersion() updates the filename and version in various UI
956 elements...
957
958 Returns this object.
959 */
960 P.updateVersion = function f(file,rev){
961 if(!f.eLinks){
962 f.eName = P.e.editStatus.querySelector('span.name');
963 f.eLinks = P.e.editStatus.querySelector('span.links');
964 }
965 if(1===arguments.length){/*assume object*/
966 this.finfo = arguments[0];
967 file = this.finfo.filename;
968 rev = this.finfo.checkin;
969 }else if(0===arguments.length){
970 if(affirmHasFile()){
971 file = this.finfo.filename;
972 rev = this.finfo.checkin;
973 }
974 }else{
975 this.finfo = {filename:file,checkin:rev};
976 }
977 const fi = this.finfo;
978 D.clearElement(f.eName, f.eLinks);
979 if(!fi){
980 D.append(f.eName, '(no file loaded)');
981 return this;
982 }
983 const rHuman = F.hashDigits(rev),
984 rUrl = F.hashDigits(rev,true);
985
986 //TODO? port over is-edited marker from /wikiedit
987 //var marker = getEditMarker(wi, false);
988 D.append(f.eName/*,marker*/,D.a(F.repoUrl('finfo',{name:file, m:rUrl}), file));
989
990 D.append(
991 f.eLinks,
992 D.append(D.span(), fi.mimetype||'?mimetype?'),
993 D.a(F.repoUrl('info/'+rUrl), rHuman),
994 D.a(F.repoUrl('timeline',{m:rUrl}), "timeline"),
995 D.a(F.repoUrl('annotate',{filename:file, checkin:rUrl}),'annotate'),
996 D.a(F.repoUrl('blame',{filename:file, checkin:rUrl}),'blame')
 
 
 
 
 
 
 
 
 
997 );
998 const purlArgs = F.encodeUrlArgs({
999 filename: this.finfo.filename,
1000 checkin: rUrl
1001 },false,true);
1002 const purl = F.repoUrl('fileedit',purlArgs);
1003 D.append( f.eLinks, D.a(purl,"editor permalink") );
1004 this.setPageTitle("Edit: "+fi.filename);
 
 
 
 
1005 return this;
1006 };
1007
1008 /**
1009 loadFile() loads (file,checkinVersion) and updates the relevant
@@ -1032,10 +1050,11 @@
1050 mimetype: headers['content-type'].split(';').shift()
1051 });
1052 self.tabs.switchToTab(self.e.tabs.content);
1053 self.e.cbIsExe.checked = self.finfo.isExe;
1054 self.fileContent(r);
1055 P.previewNeedsUpdate = true;
1056 self.dispatchEvent('fileedit-file-loaded', self.finfo);
1057 };
1058 const semiFinfo = {filename: file, checkin: rev};
1059 const stashFinfo = this.getStashedFinfo(semiFinfo);
1060 if(stashFinfo){ // fake a response from the stash...
@@ -1115,10 +1134,11 @@
1134 P.selectPreviewMode(P.previewModes[header]);
1135 if('wiki'===header) P.baseHrefForFile();
1136 else P.baseHrefRestore();
1137 callback(r);
1138 F.message('Updated preview.');
1139 P.previewNeedsUpdate = false;
1140 P.dispatchEvent('fileedit-preview-updated',{
1141 previewMode: P.previewModes.current,
1142 mimetype: P.finfo.mimetype,
1143 element: P.e.previewTarget
1144 });
@@ -1290,10 +1310,11 @@
1310 }else{
1311 $stash.updateFile(fi, P.fileContent());
1312 }
1313 F.message("Stashed change to",F.hashDigits(fi.checkin),fi.filename);
1314 $stash.prune();
1315 this.previewNeedsUpdate = true;
1316 }
1317 return this;
1318 };
1319
1320 /**
@@ -1301,10 +1322,11 @@
1322 F.storage. Returns this.
1323 */
1324 P.unstashContent = function(){
1325 const finfo = arguments[0] || this.finfo;
1326 if(finfo){
1327 this.previewNeedsUpdate = true;
1328 $stash.unstash(finfo);
1329 //console.debug("Unstashed",finfo);
1330 F.message("Unstashed",F.hashDigits(finfo.checkin),finfo.filename);
1331 }
1332 return this;
1333
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -11,26 +11,64 @@
1111
return function(ev){
1212
if(ev) ev.preventDefault();
1313
const wasExpanded = widget.classList.contains('expanded');
1414
widget.classList.toggle('expanded');
1515
contentElem.classList.toggle('expanded');
16
- if(wasExpanded) widget.scrollIntoView();
16
+ if(wasExpanded){
17
+ contentElem.classList.add('shrunken');
18
+ contentElem.parentElement.scrollIntoView({
19
+ /* This is non-standard, but !(MSIE, Safari) supposedly support it:
20
+ https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#Browser_compatibility
21
+ */ behavior: 'smooth'
22
+ });
23
+ }else{
24
+ contentElem.classList.remove('shrunken');
25
+ }
1726
return false;
1827
};
1928
};
29
+
2030
/* Adds an Expand/Collapse toggle to all div.forumPostBody
2131
elements which are deemed "too large" (those for which
2232
scrolling is currently activated because they are taller than
2333
their max-height). */
2434
document.querySelectorAll(
2535
'div.forumHier, div.forumTime, div.forumHierRoot'
26
- ).forEach(function(forumPostWrapper){
36
+ ).forEach(function f(forumPostWrapper){
2737
const content = forumPostWrapper.querySelector('div.forumPostBody');
2838
if(!content || !scrollbarIsVisible(content)) return;
29
- const widget = D.div(),
30
- widgetEventHandler = getWidgetHandler(widget, content);
31
- widget.classList.add('forum-post-collapser');
39
+ const parent = content.parentElement,
40
+ widget = D.addClass(
41
+ D.div(),
42
+ 'forum-post-collapser','bottom'
43
+ ),
44
+ rightTapZone = D.addClass(
45
+ D.div(),
46
+ 'forum-post-collapser','right'
47
+ );
48
+ /* Repopulates the rightTapZone with arrow indicators. Because
49
+ of the wildly varying height of these elements, This has to
50
+ be done dynamically at init time and upon collapse/expand. Will not
51
+ work until the rightTapZone has been added to the DOM. */
52
+ const refillTapZone = function f(){
53
+ if(!f.baseTapIndicatorHeight){
54
+ /* To figure out how often to place an arrow in the rightTapZone,
55
+ we simply grab the first header element from the page and use
56
+ its hight as our basis for calculation. */
57
+ const h1 = document.querySelector('h1, h2');
58
+ f.baseTapIndicatorHeight = h1.getBoundingClientRect().height;
59
+ }
60
+ D.clearElement(rightTapZone);
61
+ var rtzHeight = parseInt(window.getComputedStyle(rightTapZone).height);
62
+ do {
63
+ D.append(rightTapZone, D.span());
64
+ rtzHeight -= f.baseTapIndicatorHeight * 8;
65
+ }while(rtzHeight>0);
66
+ };
67
+ const handlerStep1 = getWidgetHandler(widget, content);
68
+ const widgetEventHandler = ()=>{ handlerStep1(); refillTapZone(); };
69
+ content.classList.add('with-expander');
3270
widget.addEventListener('click', widgetEventHandler, false);
3371
/** Append 3 children, which CSS will evenly space across the
3472
widget. This improves visibility over having the label
3573
in only the left, right, or center. */
3674
var i = 0;
@@ -38,14 +76,12 @@
3876
if(content.nextSibling){
3977
forumPostWrapper.insertBefore(widget, content.nextSibling);
4078
}else{
4179
forumPostWrapper.appendChild(widget);
4280
}
43
- /** A double-click toggle will select "the current word" on the
44
- post, which is minorly annoying but otherwise harmless. Such
45
- a toggle has proven convenient on "excessive" posts,
46
- though. */
47
- content.addEventListener('dblclick', widgetEventHandler);
81
+ content.appendChild(rightTapZone);
82
+ rightTapZone.addEventListener('click', widgetEventHandler, false);
83
+ refillTapZone();
4884
});
4985
})/*onload callback*/;
5086
5187
})(window.fossil);
5288
5389
ADDED src/fossil.page.wikiedit.js
5490
ADDED src/fossil.popupwidget.js
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -11,26 +11,64 @@
11 return function(ev){
12 if(ev) ev.preventDefault();
13 const wasExpanded = widget.classList.contains('expanded');
14 widget.classList.toggle('expanded');
15 contentElem.classList.toggle('expanded');
16 if(wasExpanded) widget.scrollIntoView();
 
 
 
 
 
 
 
 
 
17 return false;
18 };
19 };
 
20 /* Adds an Expand/Collapse toggle to all div.forumPostBody
21 elements which are deemed "too large" (those for which
22 scrolling is currently activated because they are taller than
23 their max-height). */
24 document.querySelectorAll(
25 'div.forumHier, div.forumTime, div.forumHierRoot'
26 ).forEach(function(forumPostWrapper){
27 const content = forumPostWrapper.querySelector('div.forumPostBody');
28 if(!content || !scrollbarIsVisible(content)) return;
29 const widget = D.div(),
30 widgetEventHandler = getWidgetHandler(widget, content);
31 widget.classList.add('forum-post-collapser');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32 widget.addEventListener('click', widgetEventHandler, false);
33 /** Append 3 children, which CSS will evenly space across the
34 widget. This improves visibility over having the label
35 in only the left, right, or center. */
36 var i = 0;
@@ -38,14 +76,12 @@
38 if(content.nextSibling){
39 forumPostWrapper.insertBefore(widget, content.nextSibling);
40 }else{
41 forumPostWrapper.appendChild(widget);
42 }
43 /** A double-click toggle will select "the current word" on the
44 post, which is minorly annoying but otherwise harmless. Such
45 a toggle has proven convenient on "excessive" posts,
46 though. */
47 content.addEventListener('dblclick', widgetEventHandler);
48 });
49 })/*onload callback*/;
50
51 })(window.fossil);
52
53 DDED src/fossil.page.wikiedit.js
54 DDED src/fossil.popupwidget.js
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -11,26 +11,64 @@
11 return function(ev){
12 if(ev) ev.preventDefault();
13 const wasExpanded = widget.classList.contains('expanded');
14 widget.classList.toggle('expanded');
15 contentElem.classList.toggle('expanded');
16 if(wasExpanded){
17 contentElem.classList.add('shrunken');
18 contentElem.parentElement.scrollIntoView({
19 /* This is non-standard, but !(MSIE, Safari) supposedly support it:
20 https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#Browser_compatibility
21 */ behavior: 'smooth'
22 });
23 }else{
24 contentElem.classList.remove('shrunken');
25 }
26 return false;
27 };
28 };
29
30 /* Adds an Expand/Collapse toggle to all div.forumPostBody
31 elements which are deemed "too large" (those for which
32 scrolling is currently activated because they are taller than
33 their max-height). */
34 document.querySelectorAll(
35 'div.forumHier, div.forumTime, div.forumHierRoot'
36 ).forEach(function f(forumPostWrapper){
37 const content = forumPostWrapper.querySelector('div.forumPostBody');
38 if(!content || !scrollbarIsVisible(content)) return;
39 const parent = content.parentElement,
40 widget = D.addClass(
41 D.div(),
42 'forum-post-collapser','bottom'
43 ),
44 rightTapZone = D.addClass(
45 D.div(),
46 'forum-post-collapser','right'
47 );
48 /* Repopulates the rightTapZone with arrow indicators. Because
49 of the wildly varying height of these elements, This has to
50 be done dynamically at init time and upon collapse/expand. Will not
51 work until the rightTapZone has been added to the DOM. */
52 const refillTapZone = function f(){
53 if(!f.baseTapIndicatorHeight){
54 /* To figure out how often to place an arrow in the rightTapZone,
55 we simply grab the first header element from the page and use
56 its hight as our basis for calculation. */
57 const h1 = document.querySelector('h1, h2');
58 f.baseTapIndicatorHeight = h1.getBoundingClientRect().height;
59 }
60 D.clearElement(rightTapZone);
61 var rtzHeight = parseInt(window.getComputedStyle(rightTapZone).height);
62 do {
63 D.append(rightTapZone, D.span());
64 rtzHeight -= f.baseTapIndicatorHeight * 8;
65 }while(rtzHeight>0);
66 };
67 const handlerStep1 = getWidgetHandler(widget, content);
68 const widgetEventHandler = ()=>{ handlerStep1(); refillTapZone(); };
69 content.classList.add('with-expander');
70 widget.addEventListener('click', widgetEventHandler, false);
71 /** Append 3 children, which CSS will evenly space across the
72 widget. This improves visibility over having the label
73 in only the left, right, or center. */
74 var i = 0;
@@ -38,14 +76,12 @@
76 if(content.nextSibling){
77 forumPostWrapper.insertBefore(widget, content.nextSibling);
78 }else{
79 forumPostWrapper.appendChild(widget);
80 }
81 content.appendChild(rightTapZone);
82 rightTapZone.addEventListener('click', widgetEventHandler, false);
83 refillTapZone();
 
 
84 });
85 })/*onload callback*/;
86
87 })(window.fossil);
88
89 DDED src/fossil.page.wikiedit.js
90 DDED src/fossil.popupwidget.js
--- a/src/fossil.page.wikiedit.js
+++ b/src/fossil.page.wikiedit.js
@@ -0,0 +1,43 @@
1
+notag" |(function(F/*ttarget.innerHTML =for a sandbox page or new page,
2
+ parent: parent UUID string or null if no parent,
3
+ isEmpty: true if page has no content (is "dele ctrnormal" | "tag" |(function(F/*the fossil object*/){
4
+ "use strict";
5
+ /**
6
+ Clienuires that
7
+ the fossil JS bootstrapping is complete and that several fossil
8
+ JS APIs have been installed: fossil.fetch, fossil.dom,
9
+ fossil.tabs, fossil.storage, fossil.confirmer, fossil.popupwidget.
10
+
11
+ Custom events which can be listened for via
12
+ fossil.page.addEventListener():
13
+
14
+ - Event 'wiki-page-loaded': passes on information when it
15
+ loads a wiki (whether from the network or its internal local-edit
16
+ cache), in the form of an "winfo" objec
17
+ 'change',n information when it
18
+ loads a wiki (whether from the network or its internal local-edit
19
+ cache), in the form of an "winfo" objecnot'localStorage'),' uses browD.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'update > input[type=checkbox], 'title);cb;
20
+ constD.attr(wrapper, "title", [
21
+',
22
+ 'Only themost recent pages',
23
+'
24
+ ].join(' '));
25
+D.attr(title' 'Save changes and Pfunction(F/*ttargenotag" |(function(F/*ttarget.innerHTML =for a sandbox page or new page,
26
+ parent: parent UUID string or null if no parent,
27
+ isEmpty: true if page has no content (is "dele ctrnormal" | "tag" |(function(F/*the fossil object*/){
28
+ "use strict";
29
+ /**
30
+ Client-side implementation of the /wikiedit app. Requires that
31
+ the fossil JS bootstrapping is complete and that several fossil
32
+ JS APIs have been installed: fossil.fetch, fossil.dom,
33
+ fossil.tabs, fossil.storage, fossil.confirmer, fossil.popupwidget.
34
+
35
+ Custom events which can be listened for via
36
+ fossil.page.addEventListener():
37
+
38
+ - Event 'wiki-page-loaded': passes on information when it
39
+ loads a wiki (whether from the network or its internal local-edit
40
+ cache), in the form of an "winfo" objec
41
+ 'change',n information when it
42
+ loads a wiki (whether from the network or its internal local-edit
43
+ cache), in the form of an "winfo" objecnot'localStorage'),' uses */fossilfossil
--- a/src/fossil.page.wikiedit.js
+++ b/src/fossil.page.wikiedit.js
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/fossil.page.wikiedit.js
+++ b/src/fossil.page.wikiedit.js
@@ -0,0 +1,43 @@
1 notag" |(function(F/*ttarget.innerHTML =for a sandbox page or new page,
2 parent: parent UUID string or null if no parent,
3 isEmpty: true if page has no content (is "dele ctrnormal" | "tag" |(function(F/*the fossil object*/){
4 "use strict";
5 /**
6 Clienuires that
7 the fossil JS bootstrapping is complete and that several fossil
8 JS APIs have been installed: fossil.fetch, fossil.dom,
9 fossil.tabs, fossil.storage, fossil.confirmer, fossil.popupwidget.
10
11 Custom events which can be listened for via
12 fossil.page.addEventListener():
13
14 - Event 'wiki-page-loaded': passes on information when it
15 loads a wiki (whether from the network or its internal local-edit
16 cache), in the form of an "winfo" objec
17 'change',n information when it
18 loads a wiki (whether from the network or its internal local-edit
19 cache), in the form of an "winfo" objecnot'localStorage'),' uses browD.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'update > input[type=checkbox], 'title);cb;
20 constD.attr(wrapper, "title", [
21 ',
22 'Only themost recent pages',
23 '
24 ].join(' '));
25 D.attr(title' 'Save changes and Pfunction(F/*ttargenotag" |(function(F/*ttarget.innerHTML =for a sandbox page or new page,
26 parent: parent UUID string or null if no parent,
27 isEmpty: true if page has no content (is "dele ctrnormal" | "tag" |(function(F/*the fossil object*/){
28 "use strict";
29 /**
30 Client-side implementation of the /wikiedit app. Requires that
31 the fossil JS bootstrapping is complete and that several fossil
32 JS APIs have been installed: fossil.fetch, fossil.dom,
33 fossil.tabs, fossil.storage, fossil.confirmer, fossil.popupwidget.
34
35 Custom events which can be listened for via
36 fossil.page.addEventListener():
37
38 - Event 'wiki-page-loaded': passes on information when it
39 loads a wiki (whether from the network or its internal local-edit
40 cache), in the form of an "winfo" objec
41 'change',n information when it
42 loads a wiki (whether from the network or its internal local-edit
43 cache), in the form of an "winfo" objecnot'localStorage'),' uses */fossilfossil
--- a/src/fossil.popupwidget.js
+++ b/src/fossil.popupwidget.js
@@ -0,0 +1,65 @@
1
+(function(F/*fossil object*/){
2
+ 30 */
3
+ installClickToHiden or basic user intera(function(F/*fossil object*/){
4
+ 3000sClass = cssClass;
5
+ unct}, true);isplay basic information ClickToHide(nction(F/*fossil object*/fossil object*/){
6
+ 3000sClass = cssClass;
7
+ unction(F/*fossil object*/){
8
+ /**
9
+ A very basic tooltip-like widget. It's intended to be popped up
10
+ to display basic information or basic user interaction
11
+ components, e.g. a cop or movopy-to-clipboard butt
12
+ if needed,l.dom
13
+ */
14
+ const D = F.dom
15
+ base DOMwidget using the
16
+). If theallback whic
17
+ h is called just before*/){
18
+ 30 */
19
+ instfunction(F/*fossil object*/){
20
+ 30 */
21
+ installClickToHiden or basic user intera(function(F/*fossil object*/){
22
+ 3000sClass = cssClass;
23
+ unct}, true);isplay basic information ClickToHide(nction(F/*fossil object*/fossil object*/){
24
+ 3000sClass = cssClass;
25
+ unction(F/*fossil object*/){
26
+ /**
27
+ A very basic tooltip-like widget. It's intended to be popped up
28
+ to display basic information or basic user interaction
29
+ components, e.g. a copy-to-clipboard button.
30
+
31
+ Requires: fossil.bootstrap, fossil.dom
32
+ */
33
+ conbjecthe popup when either
34
+ call this
35
+ show(falseshow(falseshow(falseconst hide Just be careful to mess only with the X coordinate
36
+ and the width. The browser will try to keep the widget
37
+ from being truncated off-screen on the right, shifting it
38
+ to the left if needed, and we cannot generically be sure
39
+ that an enforced fully on-screen size will actually fit
40
+ the current help textclickHandler){const rect1unction(F/*fossil object*(function(F/*fossil object*/){})(window.fossil);
41
+deleteleft');
42
+ deletea toas(function(F/*fossil o*fossil object*/){
43
+function(F/*fossil ct*/){
44
+ 30 */
45
+ installClickToHiden or basic user intera(fun*/
46
+ F.toast = function f(/*...*/){
47
+ f.toast = function ff(argsObject){
48
+ if(!ff.toaster) f ['fossil-tooltip', 'fossil-toast']
49
+ });
50
+ i@1hi,X: D.clearElement(ff.toaster.e);9@1SA,2w:var i = 0;
51
+ for( ; i < argsObject.length; ++i ){
52
+ D.append(ff.toaster.e, argsObject[i]);
53
+ };
54
+ ff.toaster.show(f.config.position.x, f.config.position.y);
55
+ Q@1mw,1m:()=>ff.toaster.hide(), f.config.displayTimeMs);
56
+ };
57
+ }
58
+ f.toast(arguments);
59
+ };
60
+ F.toast.config = {
61
+10@1pR,i:displayTimeMs: 2500
62
+ };
63
+
64
+})(window.fossil);
65
+ZfWzX;
--- a/src/fossil.popupwidget.js
+++ b/src/fossil.popupwidget.js
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/fossil.popupwidget.js
+++ b/src/fossil.popupwidget.js
@@ -0,0 +1,65 @@
1 (function(F/*fossil object*/){
2 30 */
3 installClickToHiden or basic user intera(function(F/*fossil object*/){
4 3000sClass = cssClass;
5 unct}, true);isplay basic information ClickToHide(nction(F/*fossil object*/fossil object*/){
6 3000sClass = cssClass;
7 unction(F/*fossil object*/){
8 /**
9 A very basic tooltip-like widget. It's intended to be popped up
10 to display basic information or basic user interaction
11 components, e.g. a cop or movopy-to-clipboard butt
12 if needed,l.dom
13 */
14 const D = F.dom
15 base DOMwidget using the
16 ). If theallback whic
17 h is called just before*/){
18 30 */
19 instfunction(F/*fossil object*/){
20 30 */
21 installClickToHiden or basic user intera(function(F/*fossil object*/){
22 3000sClass = cssClass;
23 unct}, true);isplay basic information ClickToHide(nction(F/*fossil object*/fossil object*/){
24 3000sClass = cssClass;
25 unction(F/*fossil object*/){
26 /**
27 A very basic tooltip-like widget. It's intended to be popped up
28 to display basic information or basic user interaction
29 components, e.g. a copy-to-clipboard button.
30
31 Requires: fossil.bootstrap, fossil.dom
32 */
33 conbjecthe popup when either
34 call this
35 show(falseshow(falseshow(falseconst hide Just be careful to mess only with the X coordinate
36 and the width. The browser will try to keep the widget
37 from being truncated off-screen on the right, shifting it
38 to the left if needed, and we cannot generically be sure
39 that an enforced fully on-screen size will actually fit
40 the current help textclickHandler){const rect1unction(F/*fossil object*(function(F/*fossil object*/){})(window.fossil);
41 deleteleft');
42 deletea toas(function(F/*fossil o*fossil object*/){
43 function(F/*fossil ct*/){
44 30 */
45 installClickToHiden or basic user intera(fun*/
46 F.toast = function f(/*...*/){
47 f.toast = function ff(argsObject){
48 if(!ff.toaster) f ['fossil-tooltip', 'fossil-toast']
49 });
50 i@1hi,X: D.clearElement(ff.toaster.e);9@1SA,2w:var i = 0;
51 for( ; i < argsObject.length; ++i ){
52 D.append(ff.toaster.e, argsObject[i]);
53 };
54 ff.toaster.show(f.config.position.x, f.config.position.y);
55 Q@1mw,1m:()=>ff.toaster.hide(), f.config.displayTimeMs);
56 };
57 }
58 f.toast(arguments);
59 };
60 F.toast.config = {
61 10@1pR,i:displayTimeMs: 2500
62 };
63
64 })(window.fossil);
65 ZfWzX;
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -3,30 +3,53 @@
33
const E = (s)=>document.querySelector(s),
44
EA = (s)=>document.querySelectorAll(s),
55
D = F.dom;
66
77
/**
8
- Creates a TabManager. If passed an argument, it is
9
- passed to init().
8
+ Creates a TabManager. If passed a truthy first argument, it is
9
+ passed to init(). If passed a truthy second argument, it must be
10
+ an Object holding configuration options:
11
+
12
+ {
13
+ tabAccessKeys: boolean (=true)
14
+ If true, tab buttons are assigned "accesskey" values
15
+ equal to their 1-based tab number.
16
+ }
1017
*/
11
- const TabManager = function(domElem){
18
+ const TabManager = function(domElem, options){
1219
this.e = {};
20
+ this.options = F.mergeLastWins(TabManager.defaultOptions , options);
1321
if(domElem) this.init(domElem);
1422
};
1523
1624
/**
17
- Internal helper to normalize a method argument
18
- to a tab element.
25
+ Default values for the options object passed to the TabManager
26
+ constructor. Changing these affects the defaults of all
27
+ TabManager instances instantiated after that point.
28
+ */
29
+ TabManager.defaultOptions = {
30
+ tabAccessKeys: true
31
+ };
32
+
33
+ /**
34
+ Internal helper to normalize a method argument to a tab
35
+ element. arg may be a tab DOM element, a selector string, or an
36
+ index into tabMgr.e.tabs.childNodes. Returns the corresponding
37
+ tab element.
1938
*/
2039
const tabArg = function(arg,tabMgr){
2140
if('string'===typeof arg) arg = E(arg);
2241
else if(tabMgr && 'number'===typeof arg && arg>=0){
2342
arg = tabMgr.e.tabs.childNodes[arg];
2443
}
2544
return arg;
2645
};
2746
47
+ /**
48
+ Sets sets the visibility of tab element e to on or off. e MUST be
49
+ a TabManager tab element.
50
+ */
2851
const setVisible = function(e,yes){
2952
D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
3053
};
3154
3255
TabManager.prototype = {
@@ -33,16 +56,18 @@
3356
/**
3457
Initializes the tabs associated with the given tab container
3558
(DOM element or selector for a single element). This must be
3659
called once before using any other member functions of a given
3760
instance, noting that the constructor will call this if it is
38
- passed an argument.
61
+ passed an argument.
3962
4063
The tab container must have an 'id' attribute. This function
4164
looks through the DOM for all elements which have
4265
data-tab-parent=thatId. For each one it creates a button to
43
- switch to that tab and moves the element into this.e.tabs.
66
+ switch to that tab and moves the element into this.e.tabs,
67
+ *possibly* injecting an intermediary element between
68
+ this.e.tabs and the element.
4469
4570
The label for each tab is set by the data-tab-label attribute
4671
of each element, defaulting to something not terribly useful.
4772
4873
When it's done, it auto-selects the first tab unless a tab has
@@ -108,10 +133,18 @@
108133
},
109134
/**
110135
Adds the given DOM element or unique selector as the next
111136
tab in the tab container, adding a button to switch to
112137
the tab. Returns this object.
138
+
139
+ If this object's options include a truthy tabAccessKeys then
140
+ each tab button gets assigned an accesskey attribute equal to
141
+ its 1-based index in the tab list. e.g. key 1 is the first tab
142
+ and key 5 is the 5th. Whether/how that accesskey is accessed is
143
+ dependent on the browser and its OS:
144
+
145
+ https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/accesskey
113146
*/
114147
addTab: function f(tab){
115148
if(!f.click){
116149
f.click = function(e){
117150
e.target.$manager.switchToTab(e.target.$tab);
@@ -118,15 +151,19 @@
118151
};
119152
}
120153
tab = tabArg(tab);
121154
tab.remove();
122155
D.append(this.e.tabs, D.addClass(tab,'tab-panel'));
123
- const lbl = tab.dataset.tabLabel || 'Tab #'+(this.e.tabs.childNodes.length-1);
156
+ const tabCount = this.e.tabBar.childNodes.length+1;
157
+ const lbl = tab.dataset.tabLabel || 'Tab #'+tabCount;
124158
const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
125159
D.append(this.e.tabBar,btn);
126160
btn.$manager = this;
127161
btn.$tab = tab;
162
+ if(this.options.tabAccessKeys){
163
+ D.attr(btn, 'accesskey', tabCount);
164
+ }
128165
btn.addEventListener('click', f.click, false);
129166
return this;
130167
},
131168
132169
/**
133170
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -3,30 +3,53 @@
3 const E = (s)=>document.querySelector(s),
4 EA = (s)=>document.querySelectorAll(s),
5 D = F.dom;
6
7 /**
8 Creates a TabManager. If passed an argument, it is
9 passed to init().
 
 
 
 
 
 
 
10 */
11 const TabManager = function(domElem){
12 this.e = {};
 
13 if(domElem) this.init(domElem);
14 };
15
16 /**
17 Internal helper to normalize a method argument
18 to a tab element.
 
 
 
 
 
 
 
 
 
 
 
19 */
20 const tabArg = function(arg,tabMgr){
21 if('string'===typeof arg) arg = E(arg);
22 else if(tabMgr && 'number'===typeof arg && arg>=0){
23 arg = tabMgr.e.tabs.childNodes[arg];
24 }
25 return arg;
26 };
27
 
 
 
 
28 const setVisible = function(e,yes){
29 D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
30 };
31
32 TabManager.prototype = {
@@ -33,16 +56,18 @@
33 /**
34 Initializes the tabs associated with the given tab container
35 (DOM element or selector for a single element). This must be
36 called once before using any other member functions of a given
37 instance, noting that the constructor will call this if it is
38 passed an argument.
39
40 The tab container must have an 'id' attribute. This function
41 looks through the DOM for all elements which have
42 data-tab-parent=thatId. For each one it creates a button to
43 switch to that tab and moves the element into this.e.tabs.
 
 
44
45 The label for each tab is set by the data-tab-label attribute
46 of each element, defaulting to something not terribly useful.
47
48 When it's done, it auto-selects the first tab unless a tab has
@@ -108,10 +133,18 @@
108 },
109 /**
110 Adds the given DOM element or unique selector as the next
111 tab in the tab container, adding a button to switch to
112 the tab. Returns this object.
 
 
 
 
 
 
 
 
113 */
114 addTab: function f(tab){
115 if(!f.click){
116 f.click = function(e){
117 e.target.$manager.switchToTab(e.target.$tab);
@@ -118,15 +151,19 @@
118 };
119 }
120 tab = tabArg(tab);
121 tab.remove();
122 D.append(this.e.tabs, D.addClass(tab,'tab-panel'));
123 const lbl = tab.dataset.tabLabel || 'Tab #'+(this.e.tabs.childNodes.length-1);
 
124 const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
125 D.append(this.e.tabBar,btn);
126 btn.$manager = this;
127 btn.$tab = tab;
 
 
 
128 btn.addEventListener('click', f.click, false);
129 return this;
130 },
131
132 /**
133
--- src/fossil.tabs.js
+++ src/fossil.tabs.js
@@ -3,30 +3,53 @@
3 const E = (s)=>document.querySelector(s),
4 EA = (s)=>document.querySelectorAll(s),
5 D = F.dom;
6
7 /**
8 Creates a TabManager. If passed a truthy first argument, it is
9 passed to init(). If passed a truthy second argument, it must be
10 an Object holding configuration options:
11
12 {
13 tabAccessKeys: boolean (=true)
14 If true, tab buttons are assigned "accesskey" values
15 equal to their 1-based tab number.
16 }
17 */
18 const TabManager = function(domElem, options){
19 this.e = {};
20 this.options = F.mergeLastWins(TabManager.defaultOptions , options);
21 if(domElem) this.init(domElem);
22 };
23
24 /**
25 Default values for the options object passed to the TabManager
26 constructor. Changing these affects the defaults of all
27 TabManager instances instantiated after that point.
28 */
29 TabManager.defaultOptions = {
30 tabAccessKeys: true
31 };
32
33 /**
34 Internal helper to normalize a method argument to a tab
35 element. arg may be a tab DOM element, a selector string, or an
36 index into tabMgr.e.tabs.childNodes. Returns the corresponding
37 tab element.
38 */
39 const tabArg = function(arg,tabMgr){
40 if('string'===typeof arg) arg = E(arg);
41 else if(tabMgr && 'number'===typeof arg && arg>=0){
42 arg = tabMgr.e.tabs.childNodes[arg];
43 }
44 return arg;
45 };
46
47 /**
48 Sets sets the visibility of tab element e to on or off. e MUST be
49 a TabManager tab element.
50 */
51 const setVisible = function(e,yes){
52 D[yes ? 'removeClass' : 'addClass'](e, 'hidden');
53 };
54
55 TabManager.prototype = {
@@ -33,16 +56,18 @@
56 /**
57 Initializes the tabs associated with the given tab container
58 (DOM element or selector for a single element). This must be
59 called once before using any other member functions of a given
60 instance, noting that the constructor will call this if it is
61 passed an argument.
62
63 The tab container must have an 'id' attribute. This function
64 looks through the DOM for all elements which have
65 data-tab-parent=thatId. For each one it creates a button to
66 switch to that tab and moves the element into this.e.tabs,
67 *possibly* injecting an intermediary element between
68 this.e.tabs and the element.
69
70 The label for each tab is set by the data-tab-label attribute
71 of each element, defaulting to something not terribly useful.
72
73 When it's done, it auto-selects the first tab unless a tab has
@@ -108,10 +133,18 @@
133 },
134 /**
135 Adds the given DOM element or unique selector as the next
136 tab in the tab container, adding a button to switch to
137 the tab. Returns this object.
138
139 If this object's options include a truthy tabAccessKeys then
140 each tab button gets assigned an accesskey attribute equal to
141 its 1-based index in the tab list. e.g. key 1 is the first tab
142 and key 5 is the 5th. Whether/how that accesskey is accessed is
143 dependent on the browser and its OS:
144
145 https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/accesskey
146 */
147 addTab: function f(tab){
148 if(!f.click){
149 f.click = function(e){
150 e.target.$manager.switchToTab(e.target.$tab);
@@ -118,15 +151,19 @@
151 };
152 }
153 tab = tabArg(tab);
154 tab.remove();
155 D.append(this.e.tabs, D.addClass(tab,'tab-panel'));
156 const tabCount = this.e.tabBar.childNodes.length+1;
157 const lbl = tab.dataset.tabLabel || 'Tab #'+tabCount;
158 const btn = D.addClass(D.append(D.span(), lbl), 'tab-button');
159 D.append(this.e.tabBar,btn);
160 btn.$manager = this;
161 btn.$tab = tab;
162 if(this.options.tabAccessKeys){
163 D.attr(btn, 'accesskey', tabCount);
164 }
165 btn.addEventListener('click', f.click, false);
166 return this;
167 },
168
169 /**
170
+1 -1
--- src/fusefs.c
+++ src/fusefs.c
@@ -285,11 +285,11 @@
285285
.readdir = fusefs_readdir,
286286
.read = fusefs_read,
287287
};
288288
289289
/*
290
-** COMMAND: fusefs
290
+** COMMAND: fusefs*
291291
**
292292
** Usage: %fossil fusefs [--debug] DIRECTORY
293293
**
294294
** This command uses the Fuse Filesystem (FuseFS) to mount a directory
295295
** at DIRECTORY that contains the content of all check-ins in the
296296
--- src/fusefs.c
+++ src/fusefs.c
@@ -285,11 +285,11 @@
285 .readdir = fusefs_readdir,
286 .read = fusefs_read,
287 };
288
289 /*
290 ** COMMAND: fusefs
291 **
292 ** Usage: %fossil fusefs [--debug] DIRECTORY
293 **
294 ** This command uses the Fuse Filesystem (FuseFS) to mount a directory
295 ** at DIRECTORY that contains the content of all check-ins in the
296
--- src/fusefs.c
+++ src/fusefs.c
@@ -285,11 +285,11 @@
285 .readdir = fusefs_readdir,
286 .read = fusefs_read,
287 };
288
289 /*
290 ** COMMAND: fusefs*
291 **
292 ** Usage: %fossil fusefs [--debug] DIRECTORY
293 **
294 ** This command uses the Fuse Filesystem (FuseFS) to mount a directory
295 ** at DIRECTORY that contains the content of all check-ins in the
296
+33
--- src/glob.c
+++ src/glob.c
@@ -163,10 +163,43 @@
163163
if( pGlob ){
164164
fossil_free(pGlob->azPattern);
165165
fossil_free(pGlob);
166166
}
167167
}
168
+
169
+/*
170
+** Appends the given glob to the given buffer in the form of a
171
+** JS/JSON-compatible array. It requires that pDest have been
172
+** initialized. If pGlob is NULL or empty it emits [] (an empty
173
+** array).
174
+*/
175
+void glob_render_json_to_blob(Glob *pGlob, Blob *pDest){
176
+ int i = 0;
177
+ blob_append(pDest, "[", 1);
178
+ for( ; pGlob && i < pGlob->nPattern; ++i ){
179
+ if(i){
180
+ blob_append(pDest, ",", 1);
181
+ }
182
+ blob_appendf(pDest, "%!j", pGlob->azPattern[i]);
183
+ }
184
+ blob_append(pDest, "]", 1);
185
+}
186
+/*
187
+** Functionally equivalent to glob_render_json_to_blob()
188
+** but outputs via cgi_print().
189
+*/
190
+void glob_render_json_to_cgi(Glob *pGlob){
191
+ int i = 0;
192
+ CX("[");
193
+ for( ; pGlob && i < pGlob->nPattern; ++i ){
194
+ if(i){
195
+ CX(",");
196
+ }
197
+ CX("%!j", pGlob->azPattern[i]);
198
+ }
199
+ CX("]");
200
+}
168201
169202
/*
170203
** COMMAND: test-glob
171204
**
172205
** Usage: %fossil test-glob PATTERN STRING...
173206
--- src/glob.c
+++ src/glob.c
@@ -163,10 +163,43 @@
163 if( pGlob ){
164 fossil_free(pGlob->azPattern);
165 fossil_free(pGlob);
166 }
167 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
169 /*
170 ** COMMAND: test-glob
171 **
172 ** Usage: %fossil test-glob PATTERN STRING...
173
--- src/glob.c
+++ src/glob.c
@@ -163,10 +163,43 @@
163 if( pGlob ){
164 fossil_free(pGlob->azPattern);
165 fossil_free(pGlob);
166 }
167 }
168
169 /*
170 ** Appends the given glob to the given buffer in the form of a
171 ** JS/JSON-compatible array. It requires that pDest have been
172 ** initialized. If pGlob is NULL or empty it emits [] (an empty
173 ** array).
174 */
175 void glob_render_json_to_blob(Glob *pGlob, Blob *pDest){
176 int i = 0;
177 blob_append(pDest, "[", 1);
178 for( ; pGlob && i < pGlob->nPattern; ++i ){
179 if(i){
180 blob_append(pDest, ",", 1);
181 }
182 blob_appendf(pDest, "%!j", pGlob->azPattern[i]);
183 }
184 blob_append(pDest, "]", 1);
185 }
186 /*
187 ** Functionally equivalent to glob_render_json_to_blob()
188 ** but outputs via cgi_print().
189 */
190 void glob_render_json_to_cgi(Glob *pGlob){
191 int i = 0;
192 CX("[");
193 for( ; pGlob && i < pGlob->nPattern; ++i ){
194 if(i){
195 CX(",");
196 }
197 CX("%!j", pGlob->azPattern[i]);
198 }
199 CX("]");
200 }
201
202 /*
203 ** COMMAND: test-glob
204 **
205 ** Usage: %fossil test-glob PATTERN STRING...
206
+1 -1
--- src/graph.js
+++ src/graph.js
@@ -779,6 +779,6 @@
779779
if(!dataObj) break;
780780
var txJson = dataObj.textContent || dataObj.innerText;
781781
var tx = JSON.parse(txJson);
782782
TimelineGraph(tx);
783783
}
784
-}())
784
+}());
785785
--- src/graph.js
+++ src/graph.js
@@ -779,6 +779,6 @@
779 if(!dataObj) break;
780 var txJson = dataObj.textContent || dataObj.innerText;
781 var tx = JSON.parse(txJson);
782 TimelineGraph(tx);
783 }
784 }())
785
--- src/graph.js
+++ src/graph.js
@@ -779,6 +779,6 @@
779 if(!dataObj) break;
780 var txJson = dataObj.textContent || dataObj.innerText;
781 var tx = JSON.parse(txJson);
782 TimelineGraph(tx);
783 }
784 }());
785
+1 -1
--- src/hook.c
+++ src/hook.c
@@ -174,11 +174,11 @@
174174
}
175175
db_finalize(&q);
176176
}
177177
178178
/*
179
-** COMMAND: hook
179
+** COMMAND: hook*
180180
**
181181
** Usage: %fossil hook COMMAND ...
182182
**
183183
** Commands include:
184184
**
185185
--- src/hook.c
+++ src/hook.c
@@ -174,11 +174,11 @@
174 }
175 db_finalize(&q);
176 }
177
178 /*
179 ** COMMAND: hook
180 **
181 ** Usage: %fossil hook COMMAND ...
182 **
183 ** Commands include:
184 **
185
--- src/hook.c
+++ src/hook.c
@@ -174,11 +174,11 @@
174 }
175 db_finalize(&q);
176 }
177
178 /*
179 ** COMMAND: hook*
180 **
181 ** Usage: %fossil hook COMMAND ...
182 **
183 ** Commands include:
184 **
185
+1 -1
--- src/import.c
+++ src/import.c
@@ -1594,11 +1594,11 @@
15941594
db_finalize(&revSrc);
15951595
fossil_print(" Done!\n");
15961596
}
15971597
15981598
/*
1599
-** COMMAND: import
1599
+** COMMAND: import*
16001600
**
16011601
** Usage: %fossil import ?--git? ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?
16021602
** or: %fossil import --svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?
16031603
**
16041604
** Read interchange format generated by another VCS and use it to
16051605
--- src/import.c
+++ src/import.c
@@ -1594,11 +1594,11 @@
1594 db_finalize(&revSrc);
1595 fossil_print(" Done!\n");
1596 }
1597
1598 /*
1599 ** COMMAND: import
1600 **
1601 ** Usage: %fossil import ?--git? ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?
1602 ** or: %fossil import --svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?
1603 **
1604 ** Read interchange format generated by another VCS and use it to
1605
--- src/import.c
+++ src/import.c
@@ -1594,11 +1594,11 @@
1594 db_finalize(&revSrc);
1595 fossil_print(" Done!\n");
1596 }
1597
1598 /*
1599 ** COMMAND: import*
1600 **
1601 ** Usage: %fossil import ?--git? ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?
1602 ** or: %fossil import --svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?
1603 **
1604 ** Read interchange format generated by another VCS and use it to
1605
+104 -48
--- src/info.c
+++ src/info.c
@@ -191,11 +191,11 @@
191191
** Options:
192192
**
193193
** -R|--repository FILE Extract info from repository FILE
194194
** -v|--verbose Show extra information about repositories
195195
**
196
-** See also: annotate, artifact, finfo, timeline
196
+** See also: [[annotate]], [[artifact]], [[finfo]], [[timeline]]
197197
*/
198198
void info_cmd(void){
199199
i64 fsize;
200200
int verboseFlag = find_option("verbose","v",0)!=0;
201201
if( !verboseFlag ){
@@ -441,11 +441,11 @@
441441
/*
442442
** Generate javascript to enhance HTML diffs.
443443
*/
444444
void append_diff_javascript(int sideBySide){
445445
if( !sideBySide ) return;
446
- style_load_one_js_file("sbsdiff.js");
446
+ builtin_request_js("sbsdiff.js");
447447
}
448448
449449
/*
450450
** Construct an appropriate diffFlag for text_diff() based on query
451451
** parameters and the to boolean arguments.
@@ -2011,27 +2011,37 @@
20112011
manifest_destroy(pManifest);
20122012
return rid;
20132013
}
20142014
20152015
/*
2016
-** The "z" argument is a string that contains the text of a source code
2017
-** file. This routine appends that text to the HTTP reply with line numbering.
2016
+** The "z" argument is a string that contains the text of a source
2017
+** code file and nZ is its length in bytes. This routine appends that
2018
+** text to the HTTP reply with line numbering.
2019
+**
2020
+** zName is the content's file name, if any (it may be NULL). If that
2021
+** name contains a '.' then the part after the final '.' is used as
2022
+** the X part of a "language-X" CSS class on the generated CODE block.
20182023
**
20192024
** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
20202025
** then highlight that line number and scroll to it once the page loads.
20212026
** If there are two line numbers, highlight the range of lines.
20222027
** Multiple ranges can be highlighed by adding additional line numbers
20232028
** separated by a non-digit character (also not one of [-,.]).
20242029
*/
20252030
void output_text_with_line_numbers(
20262031
const char *z,
2032
+ int nZ,
2033
+ const char *zName,
20272034
const char *zLn
20282035
){
20292036
int iStart, iEnd; /* Start and end of region to highlight */
20302037
int n = 0; /* Current line number */
20312038
int i = 0; /* Loop index */
20322039
int iTop = 0; /* Scroll so that this line is on top of screen. */
2040
+ int nLine = 0; /* content line count */
2041
+ int nSpans = 0; /* number of distinct zLn spans */
2042
+ const char *zExt = file_extension(zName);
20332043
Stmt q;
20342044
20352045
iStart = iEnd = atoi(zLn);
20362046
db_multi_exec(
20372047
"CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
@@ -2047,56 +2057,101 @@
20472057
while( fossil_isdigit(zLn[i]) ) i++;
20482058
if( iEnd<iStart ) iEnd = iStart;
20492059
db_multi_exec(
20502060
"INSERT OR REPLACE INTO lnos VALUES(%d,%d)", iStart, iEnd
20512061
);
2062
+ ++nSpans;
20522063
iStart = iEnd = atoi(&zLn[i++]);
20532064
}while( zLn[i] && iStart && iEnd );
20542065
}
2055
- db_prepare(&q, "SELECT min(iStart), max(iEnd) FROM lnos");
2056
- if( db_step(&q)==SQLITE_ROW ){
2057
- iStart = db_column_int(&q, 0);
2058
- iEnd = db_column_int(&q, 1);
2059
- iTop = iStart - 15 + (iEnd-iStart)/4;
2060
- if( iTop>iStart - 2 ) iTop = iStart-2;
2061
- }
2062
- db_finalize(&q);
2063
- @ <pre>
2064
- while( z[0] ){
2065
- n++;
2066
- db_prepare(&q,
2067
- "SELECT min(iStart), max(iEnd) FROM lnos"
2068
- " WHERE iStart <= %d AND iEnd >= %d", n, n);
2069
- if( db_step(&q)==SQLITE_ROW ){
2070
- iStart = db_column_int(&q, 0);
2071
- iEnd = db_column_int(&q, 1);
2072
- }
2073
- db_finalize(&q);
2074
- for(i=0; z[i] && z[i]!='\n'; i++){}
2075
- if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1);
2076
- if( n==iStart ){
2077
- cgi_append_content("<div class=\"selectedText\">",-1);
2078
- }
2079
- cgi_printf("%6d ", n);
2080
- if( i>0 ){
2081
- char *zHtml = htmlize(z, i);
2082
- cgi_append_content(zHtml, -1);
2083
- fossil_free(zHtml);
2084
- }
2085
- if( n==iTop ) cgi_append_content("</span>", -1);
2086
- if( n==iEnd ) cgi_append_content("</div>", -1);
2087
- else cgi_append_content("\n", 1);
2088
- z += i;
2089
- if( z[0]=='\n' ) z++;
2090
- }
2091
- if( n<iEnd ) cgi_printf("</div>");
2092
- @ </pre>
2066
+ /*cgi_printf("<!-- ln span count=%d -->", nSpans);*/
2067
+ cgi_append_content("<table class='numbered-lines'><tbody>"
2068
+ "<tr><td class='line-numbers'>", -1);
2069
+ iStart = iEnd = 0;
2070
+ count_lines(z, nZ, &nLine);
2071
+ for( n=1 ; n<=nLine; ++n ){
2072
+ const char * zAttr = "";
2073
+ const char * zId = "";
2074
+ if(nSpans>0 && iEnd==0){/*Grab the next range of zLn marking*/
2075
+ db_prepare(&q, "SELECT iStart, iEnd FROM lnos "
2076
+ "WHERE iStart >= %d ORDER BY iStart", n);
2077
+ if( db_step(&q)==SQLITE_ROW ){
2078
+ iStart = db_column_int(&q, 0);
2079
+ iEnd = db_column_int(&q, 1);
2080
+ if(!iTop){
2081
+ iTop = iStart - 15 + (iEnd-iStart)/4;
2082
+ if( iTop>iStart - 2 ) iTop = iStart-2;
2083
+ }
2084
+ }else{
2085
+ /* Note that overlapping multi-spans, e.g. 10-15+12-20,
2086
+ can cause us to miss a row. */
2087
+ iStart = iEnd = 0;
2088
+ }
2089
+ db_finalize(&q);
2090
+ --nSpans;
2091
+ /*cgi_printf("<!-- iStart=%d, iEnd=%d -->", iStart, iEnd);*/
2092
+ }
2093
+ if(n==iTop) {
2094
+ zId = " id='scrollToMe'";
2095
+ }
2096
+ if(n==iStart){/*Figure out which CSS class(es) this line needs...*/
2097
+ if(n==iEnd){
2098
+ zAttr = " class='selected-line start end'";
2099
+ iEnd = 0;
2100
+ }else{
2101
+ zAttr = " class='selected-line start'";
2102
+ }
2103
+ iStart = 0;
2104
+ }else if(n==iEnd){
2105
+ zAttr = " class='selected-line end'";
2106
+ iEnd = 0;
2107
+ }else if( n>iStart && n<iEnd ){
2108
+ zAttr = " class='selected-line'";
2109
+ }
2110
+ cgi_printf("<span%s%s>%6d</span>", zId, zAttr, n);
2111
+ }
2112
+ cgi_append_content("</td><td class='file-content'><pre>",-1);
2113
+ if(zExt && *zExt){
2114
+ cgi_printf("<code class='language-%h'>",zExt);
2115
+ }else{
2116
+ cgi_append_content("<code>", -1);
2117
+ }
2118
+ cgi_printf("%z", htmlize(z, nZ));
2119
+ CX("</code></pre></td></tr></tbody></table>\n");
20932120
if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2094
- style_load_one_js_file("scroll.js");
2121
+ builtin_request_js("scroll.js");
20952122
}
2123
+ style_emit_fossil_js_apis(0, "dom", "copybutton", "popupwidget",
2124
+ "numbered-lines", 0);
20962125
}
20972126
2127
+/*
2128
+** COMMAND: test-line-numbers
2129
+**
2130
+** Usage: %fossil test-line-numbers FILE ?LN-SPEC?
2131
+**
2132
+*/
2133
+void cmd_test_line_numbers(void){
2134
+ Blob content = empty_blob;
2135
+ const char * zLn = "";
2136
+ const char * zFilename = 0;
2137
+
2138
+ if(g.argc < 3){
2139
+ usage("FILE");
2140
+ }else if(g.argc>3){
2141
+ zLn = g.argv[3];
2142
+ }
2143
+ db_find_and_open_repository(0,0);
2144
+ zFilename = g.argv[2];
2145
+ fossil_print("%s %s\n", zFilename, zLn);
2146
+
2147
+ blob_read_from_file(&content, zFilename, ExtFILE);
2148
+ output_text_with_line_numbers(blob_str(&content), blob_size(&content),
2149
+ zFilename, zLn);
2150
+ blob_reset(&content);
2151
+ fossil_print("%b\n", cgi_output_blob());
2152
+}
20982153
20992154
/*
21002155
** WEBPAGE: artifact
21012156
** WEBPAGE: file
21022157
** WEBPAGE: whatis
@@ -2387,25 +2442,26 @@
23872442
if( zLn==0 || atoi(zLn)==0 ){
23882443
style_submenu_checkbox("ln", "Line Numbers", 0, 0);
23892444
}
23902445
blob_to_utf8_no_bom(&content, 0);
23912446
zMime = mimetype_from_content(&content);
2392
- @ <blockquote>
2447
+ @ <blockquote class="file-content">
23932448
if( zMime==0 ){
23942449
const char *z, *zFileName, *zExt;
23952450
z = blob_str(&content);
23962451
zFileName = db_text(0,
23972452
"SELECT name FROM mlink, filename"
23982453
" WHERE filename.fnid=mlink.fnid"
23992454
" AND mlink.fid=%d",
24002455
rid);
2401
- zExt = zFileName ? strrchr(zFileName, '.') : 0;
2456
+ zExt = file_extension(zFileName);
24022457
if( zLn ){
2403
- output_text_with_line_numbers(z, zLn);
2458
+ output_text_with_line_numbers(z, blob_size(&content),
2459
+ zFileName, zLn);
24042460
}else if( zExt && zExt[1] ){
24052461
@ <pre>
2406
- @ <code class="language-%s(zExt+1)">%h(z)</code>
2462
+ @ <code class="language-%s(zExt)">%h(z)</code>
24072463
@ </pre>
24082464
}else{
24092465
@ <pre>
24102466
@ %h(z)
24112467
@ </pre>
@@ -3113,11 +3169,11 @@
31133169
@ <input type="submit" name="apply" value="Apply Changes" />
31143170
}
31153171
@ </td></tr>
31163172
@ </table>
31173173
@ </div></form>
3118
- style_load_one_js_file("ci_edit.js");
3174
+ builtin_request_js("ci_edit.js");
31193175
style_footer();
31203176
}
31213177
31223178
/*
31233179
** Prepare an ammended commit comment. Let the user modify it using the
31243180
--- src/info.c
+++ src/info.c
@@ -191,11 +191,11 @@
191 ** Options:
192 **
193 ** -R|--repository FILE Extract info from repository FILE
194 ** -v|--verbose Show extra information about repositories
195 **
196 ** See also: annotate, artifact, finfo, timeline
197 */
198 void info_cmd(void){
199 i64 fsize;
200 int verboseFlag = find_option("verbose","v",0)!=0;
201 if( !verboseFlag ){
@@ -441,11 +441,11 @@
441 /*
442 ** Generate javascript to enhance HTML diffs.
443 */
444 void append_diff_javascript(int sideBySide){
445 if( !sideBySide ) return;
446 style_load_one_js_file("sbsdiff.js");
447 }
448
449 /*
450 ** Construct an appropriate diffFlag for text_diff() based on query
451 ** parameters and the to boolean arguments.
@@ -2011,27 +2011,37 @@
2011 manifest_destroy(pManifest);
2012 return rid;
2013 }
2014
2015 /*
2016 ** The "z" argument is a string that contains the text of a source code
2017 ** file. This routine appends that text to the HTTP reply with line numbering.
 
 
 
 
 
2018 **
2019 ** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
2020 ** then highlight that line number and scroll to it once the page loads.
2021 ** If there are two line numbers, highlight the range of lines.
2022 ** Multiple ranges can be highlighed by adding additional line numbers
2023 ** separated by a non-digit character (also not one of [-,.]).
2024 */
2025 void output_text_with_line_numbers(
2026 const char *z,
 
 
2027 const char *zLn
2028 ){
2029 int iStart, iEnd; /* Start and end of region to highlight */
2030 int n = 0; /* Current line number */
2031 int i = 0; /* Loop index */
2032 int iTop = 0; /* Scroll so that this line is on top of screen. */
 
 
 
2033 Stmt q;
2034
2035 iStart = iEnd = atoi(zLn);
2036 db_multi_exec(
2037 "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
@@ -2047,56 +2057,101 @@
2047 while( fossil_isdigit(zLn[i]) ) i++;
2048 if( iEnd<iStart ) iEnd = iStart;
2049 db_multi_exec(
2050 "INSERT OR REPLACE INTO lnos VALUES(%d,%d)", iStart, iEnd
2051 );
 
2052 iStart = iEnd = atoi(&zLn[i++]);
2053 }while( zLn[i] && iStart && iEnd );
2054 }
2055 db_prepare(&q, "SELECT min(iStart), max(iEnd) FROM lnos");
2056 if( db_step(&q)==SQLITE_ROW ){
2057 iStart = db_column_int(&q, 0);
2058 iEnd = db_column_int(&q, 1);
2059 iTop = iStart - 15 + (iEnd-iStart)/4;
2060 if( iTop>iStart - 2 ) iTop = iStart-2;
2061 }
2062 db_finalize(&q);
2063 @ <pre>
2064 while( z[0] ){
2065 n++;
2066 db_prepare(&q,
2067 "SELECT min(iStart), max(iEnd) FROM lnos"
2068 " WHERE iStart <= %d AND iEnd >= %d", n, n);
2069 if( db_step(&q)==SQLITE_ROW ){
2070 iStart = db_column_int(&q, 0);
2071 iEnd = db_column_int(&q, 1);
2072 }
2073 db_finalize(&q);
2074 for(i=0; z[i] && z[i]!='\n'; i++){}
2075 if( n==iTop ) cgi_append_content("<span id=\"scrollToMe\">", -1);
2076 if( n==iStart ){
2077 cgi_append_content("<div class=\"selectedText\">",-1);
2078 }
2079 cgi_printf("%6d ", n);
2080 if( i>0 ){
2081 char *zHtml = htmlize(z, i);
2082 cgi_append_content(zHtml, -1);
2083 fossil_free(zHtml);
2084 }
2085 if( n==iTop ) cgi_append_content("</span>", -1);
2086 if( n==iEnd ) cgi_append_content("</div>", -1);
2087 else cgi_append_content("\n", 1);
2088 z += i;
2089 if( z[0]=='\n' ) z++;
2090 }
2091 if( n<iEnd ) cgi_printf("</div>");
2092 @ </pre>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2093 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2094 style_load_one_js_file("scroll.js");
2095 }
 
 
2096 }
2097
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2098
2099 /*
2100 ** WEBPAGE: artifact
2101 ** WEBPAGE: file
2102 ** WEBPAGE: whatis
@@ -2387,25 +2442,26 @@
2387 if( zLn==0 || atoi(zLn)==0 ){
2388 style_submenu_checkbox("ln", "Line Numbers", 0, 0);
2389 }
2390 blob_to_utf8_no_bom(&content, 0);
2391 zMime = mimetype_from_content(&content);
2392 @ <blockquote>
2393 if( zMime==0 ){
2394 const char *z, *zFileName, *zExt;
2395 z = blob_str(&content);
2396 zFileName = db_text(0,
2397 "SELECT name FROM mlink, filename"
2398 " WHERE filename.fnid=mlink.fnid"
2399 " AND mlink.fid=%d",
2400 rid);
2401 zExt = zFileName ? strrchr(zFileName, '.') : 0;
2402 if( zLn ){
2403 output_text_with_line_numbers(z, zLn);
 
2404 }else if( zExt && zExt[1] ){
2405 @ <pre>
2406 @ <code class="language-%s(zExt+1)">%h(z)</code>
2407 @ </pre>
2408 }else{
2409 @ <pre>
2410 @ %h(z)
2411 @ </pre>
@@ -3113,11 +3169,11 @@
3113 @ <input type="submit" name="apply" value="Apply Changes" />
3114 }
3115 @ </td></tr>
3116 @ </table>
3117 @ </div></form>
3118 style_load_one_js_file("ci_edit.js");
3119 style_footer();
3120 }
3121
3122 /*
3123 ** Prepare an ammended commit comment. Let the user modify it using the
3124
--- src/info.c
+++ src/info.c
@@ -191,11 +191,11 @@
191 ** Options:
192 **
193 ** -R|--repository FILE Extract info from repository FILE
194 ** -v|--verbose Show extra information about repositories
195 **
196 ** See also: [[annotate]], [[artifact]], [[finfo]], [[timeline]]
197 */
198 void info_cmd(void){
199 i64 fsize;
200 int verboseFlag = find_option("verbose","v",0)!=0;
201 if( !verboseFlag ){
@@ -441,11 +441,11 @@
441 /*
442 ** Generate javascript to enhance HTML diffs.
443 */
444 void append_diff_javascript(int sideBySide){
445 if( !sideBySide ) return;
446 builtin_request_js("sbsdiff.js");
447 }
448
449 /*
450 ** Construct an appropriate diffFlag for text_diff() based on query
451 ** parameters and the to boolean arguments.
@@ -2011,27 +2011,37 @@
2011 manifest_destroy(pManifest);
2012 return rid;
2013 }
2014
2015 /*
2016 ** The "z" argument is a string that contains the text of a source
2017 ** code file and nZ is its length in bytes. This routine appends that
2018 ** text to the HTTP reply with line numbering.
2019 **
2020 ** zName is the content's file name, if any (it may be NULL). If that
2021 ** name contains a '.' then the part after the final '.' is used as
2022 ** the X part of a "language-X" CSS class on the generated CODE block.
2023 **
2024 ** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
2025 ** then highlight that line number and scroll to it once the page loads.
2026 ** If there are two line numbers, highlight the range of lines.
2027 ** Multiple ranges can be highlighed by adding additional line numbers
2028 ** separated by a non-digit character (also not one of [-,.]).
2029 */
2030 void output_text_with_line_numbers(
2031 const char *z,
2032 int nZ,
2033 const char *zName,
2034 const char *zLn
2035 ){
2036 int iStart, iEnd; /* Start and end of region to highlight */
2037 int n = 0; /* Current line number */
2038 int i = 0; /* Loop index */
2039 int iTop = 0; /* Scroll so that this line is on top of screen. */
2040 int nLine = 0; /* content line count */
2041 int nSpans = 0; /* number of distinct zLn spans */
2042 const char *zExt = file_extension(zName);
2043 Stmt q;
2044
2045 iStart = iEnd = atoi(zLn);
2046 db_multi_exec(
2047 "CREATE TEMP TABLE lnos(iStart INTEGER PRIMARY KEY, iEnd INTEGER)");
@@ -2047,56 +2057,101 @@
2057 while( fossil_isdigit(zLn[i]) ) i++;
2058 if( iEnd<iStart ) iEnd = iStart;
2059 db_multi_exec(
2060 "INSERT OR REPLACE INTO lnos VALUES(%d,%d)", iStart, iEnd
2061 );
2062 ++nSpans;
2063 iStart = iEnd = atoi(&zLn[i++]);
2064 }while( zLn[i] && iStart && iEnd );
2065 }
2066 /*cgi_printf("<!-- ln span count=%d -->", nSpans);*/
2067 cgi_append_content("<table class='numbered-lines'><tbody>"
2068 "<tr><td class='line-numbers'>", -1);
2069 iStart = iEnd = 0;
2070 count_lines(z, nZ, &nLine);
2071 for( n=1 ; n<=nLine; ++n ){
2072 const char * zAttr = "";
2073 const char * zId = "";
2074 if(nSpans>0 && iEnd==0){/*Grab the next range of zLn marking*/
2075 db_prepare(&q, "SELECT iStart, iEnd FROM lnos "
2076 "WHERE iStart >= %d ORDER BY iStart", n);
2077 if( db_step(&q)==SQLITE_ROW ){
2078 iStart = db_column_int(&q, 0);
2079 iEnd = db_column_int(&q, 1);
2080 if(!iTop){
2081 iTop = iStart - 15 + (iEnd-iStart)/4;
2082 if( iTop>iStart - 2 ) iTop = iStart-2;
2083 }
2084 }else{
2085 /* Note that overlapping multi-spans, e.g. 10-15+12-20,
2086 can cause us to miss a row. */
2087 iStart = iEnd = 0;
2088 }
2089 db_finalize(&q);
2090 --nSpans;
2091 /*cgi_printf("<!-- iStart=%d, iEnd=%d -->", iStart, iEnd);*/
2092 }
2093 if(n==iTop) {
2094 zId = " id='scrollToMe'";
2095 }
2096 if(n==iStart){/*Figure out which CSS class(es) this line needs...*/
2097 if(n==iEnd){
2098 zAttr = " class='selected-line start end'";
2099 iEnd = 0;
2100 }else{
2101 zAttr = " class='selected-line start'";
2102 }
2103 iStart = 0;
2104 }else if(n==iEnd){
2105 zAttr = " class='selected-line end'";
2106 iEnd = 0;
2107 }else if( n>iStart && n<iEnd ){
2108 zAttr = " class='selected-line'";
2109 }
2110 cgi_printf("<span%s%s>%6d</span>", zId, zAttr, n);
2111 }
2112 cgi_append_content("</td><td class='file-content'><pre>",-1);
2113 if(zExt && *zExt){
2114 cgi_printf("<code class='language-%h'>",zExt);
2115 }else{
2116 cgi_append_content("<code>", -1);
2117 }
2118 cgi_printf("%z", htmlize(z, nZ));
2119 CX("</code></pre></td></tr></tbody></table>\n");
2120 if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){
2121 builtin_request_js("scroll.js");
2122 }
2123 style_emit_fossil_js_apis(0, "dom", "copybutton", "popupwidget",
2124 "numbered-lines", 0);
2125 }
2126
2127 /*
2128 ** COMMAND: test-line-numbers
2129 **
2130 ** Usage: %fossil test-line-numbers FILE ?LN-SPEC?
2131 **
2132 */
2133 void cmd_test_line_numbers(void){
2134 Blob content = empty_blob;
2135 const char * zLn = "";
2136 const char * zFilename = 0;
2137
2138 if(g.argc < 3){
2139 usage("FILE");
2140 }else if(g.argc>3){
2141 zLn = g.argv[3];
2142 }
2143 db_find_and_open_repository(0,0);
2144 zFilename = g.argv[2];
2145 fossil_print("%s %s\n", zFilename, zLn);
2146
2147 blob_read_from_file(&content, zFilename, ExtFILE);
2148 output_text_with_line_numbers(blob_str(&content), blob_size(&content),
2149 zFilename, zLn);
2150 blob_reset(&content);
2151 fossil_print("%b\n", cgi_output_blob());
2152 }
2153
2154 /*
2155 ** WEBPAGE: artifact
2156 ** WEBPAGE: file
2157 ** WEBPAGE: whatis
@@ -2387,25 +2442,26 @@
2442 if( zLn==0 || atoi(zLn)==0 ){
2443 style_submenu_checkbox("ln", "Line Numbers", 0, 0);
2444 }
2445 blob_to_utf8_no_bom(&content, 0);
2446 zMime = mimetype_from_content(&content);
2447 @ <blockquote class="file-content">
2448 if( zMime==0 ){
2449 const char *z, *zFileName, *zExt;
2450 z = blob_str(&content);
2451 zFileName = db_text(0,
2452 "SELECT name FROM mlink, filename"
2453 " WHERE filename.fnid=mlink.fnid"
2454 " AND mlink.fid=%d",
2455 rid);
2456 zExt = file_extension(zFileName);
2457 if( zLn ){
2458 output_text_with_line_numbers(z, blob_size(&content),
2459 zFileName, zLn);
2460 }else if( zExt && zExt[1] ){
2461 @ <pre>
2462 @ <code class="language-%s(zExt)">%h(z)</code>
2463 @ </pre>
2464 }else{
2465 @ <pre>
2466 @ %h(z)
2467 @ </pre>
@@ -3113,11 +3169,11 @@
3169 @ <input type="submit" name="apply" value="Apply Changes" />
3170 }
3171 @ </td></tr>
3172 @ </table>
3173 @ </div></form>
3174 builtin_request_js("ci_edit.js");
3175 style_footer();
3176 }
3177
3178 /*
3179 ** Prepare an ammended commit comment. Let the user modify it using the
3180
--- src/json_config.c
+++ src/json_config.c
@@ -61,10 +61,12 @@
6161
{ "details", CONFIGSET_SKIN },
6262
{ "logo-mimetype", CONFIGSET_SKIN },
6363
{ "logo-image", CONFIGSET_SKIN },
6464
{ "background-mimetype", CONFIGSET_SKIN },
6565
{ "background-image", CONFIGSET_SKIN },
66
+{ "icon-mimetype", CONFIGSET_SKIN },
67
+{ "icon-image", CONFIGSET_SKIN },
6668
{ "timeline-block-markup", CONFIGSET_SKIN },
6769
{ "timeline-max-comment", CONFIGSET_SKIN },
6870
{ "timeline-plaintext", CONFIGSET_SKIN },
6971
{ "adunit", CONFIGSET_SKIN },
7072
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
7173
--- src/json_config.c
+++ src/json_config.c
@@ -61,10 +61,12 @@
61 { "details", CONFIGSET_SKIN },
62 { "logo-mimetype", CONFIGSET_SKIN },
63 { "logo-image", CONFIGSET_SKIN },
64 { "background-mimetype", CONFIGSET_SKIN },
65 { "background-image", CONFIGSET_SKIN },
 
 
66 { "timeline-block-markup", CONFIGSET_SKIN },
67 { "timeline-max-comment", CONFIGSET_SKIN },
68 { "timeline-plaintext", CONFIGSET_SKIN },
69 { "adunit", CONFIGSET_SKIN },
70 { "adunit-omit-if-admin", CONFIGSET_SKIN },
71
--- src/json_config.c
+++ src/json_config.c
@@ -61,10 +61,12 @@
61 { "details", CONFIGSET_SKIN },
62 { "logo-mimetype", CONFIGSET_SKIN },
63 { "logo-image", CONFIGSET_SKIN },
64 { "background-mimetype", CONFIGSET_SKIN },
65 { "background-image", CONFIGSET_SKIN },
66 { "icon-mimetype", CONFIGSET_SKIN },
67 { "icon-image", CONFIGSET_SKIN },
68 { "timeline-block-markup", CONFIGSET_SKIN },
69 { "timeline-max-comment", CONFIGSET_SKIN },
70 { "timeline-plaintext", CONFIGSET_SKIN },
71 { "adunit", CONFIGSET_SKIN },
72 { "adunit-omit-if-admin", CONFIGSET_SKIN },
73
+5 -4
--- src/login.c
+++ src/login.c
@@ -752,11 +752,11 @@
752752
@ %h(zCaptcha)
753753
@ </pre></td></tr></table>
754754
if( bAutoCaptcha ) {
755755
@ <input type="button" value="Fill out captcha" id='autofillButton' \
756756
@ data-af='%s(zDecoded)' />
757
- style_load_one_js_file("login.js");
757
+ builtin_request_js("login.js");
758758
}
759759
@ </div>
760760
free(zCaptcha);
761761
}
762762
@ </form>
@@ -1591,13 +1591,14 @@
15911591
/* If the email is found anywhere in USER.INFO... */
15921592
db_exists("SELECT 1 FROM user WHERE info LIKE '%%%q%%'", zEAddr)
15931593
||
15941594
/* Or if the email is a verify subscriber email with an associated
15951595
** user... */
1596
- db_exists(
1597
- "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL"
1598
- " AND sverified",zEAddr)
1596
+ (alert_tables_exist() &&
1597
+ db_exists(
1598
+ "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL"
1599
+ " AND sverified",zEAddr))
15991600
){
16001601
iErrLine = 3;
16011602
zErr = "This email address is already claimed by another user";
16021603
}else{
16031604
/* If all of the tests above have passed, that means that the submitted
16041605
--- src/login.c
+++ src/login.c
@@ -752,11 +752,11 @@
752 @ %h(zCaptcha)
753 @ </pre></td></tr></table>
754 if( bAutoCaptcha ) {
755 @ <input type="button" value="Fill out captcha" id='autofillButton' \
756 @ data-af='%s(zDecoded)' />
757 style_load_one_js_file("login.js");
758 }
759 @ </div>
760 free(zCaptcha);
761 }
762 @ </form>
@@ -1591,13 +1591,14 @@
1591 /* If the email is found anywhere in USER.INFO... */
1592 db_exists("SELECT 1 FROM user WHERE info LIKE '%%%q%%'", zEAddr)
1593 ||
1594 /* Or if the email is a verify subscriber email with an associated
1595 ** user... */
1596 db_exists(
1597 "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL"
1598 " AND sverified",zEAddr)
 
1599 ){
1600 iErrLine = 3;
1601 zErr = "This email address is already claimed by another user";
1602 }else{
1603 /* If all of the tests above have passed, that means that the submitted
1604
--- src/login.c
+++ src/login.c
@@ -752,11 +752,11 @@
752 @ %h(zCaptcha)
753 @ </pre></td></tr></table>
754 if( bAutoCaptcha ) {
755 @ <input type="button" value="Fill out captcha" id='autofillButton' \
756 @ data-af='%s(zDecoded)' />
757 builtin_request_js("login.js");
758 }
759 @ </div>
760 free(zCaptcha);
761 }
762 @ </form>
@@ -1591,13 +1591,14 @@
1591 /* If the email is found anywhere in USER.INFO... */
1592 db_exists("SELECT 1 FROM user WHERE info LIKE '%%%q%%'", zEAddr)
1593 ||
1594 /* Or if the email is a verify subscriber email with an associated
1595 ** user... */
1596 (alert_tables_exist() &&
1597 db_exists(
1598 "SELECT 1 FROM subscriber WHERE semail=%Q AND suname IS NOT NULL"
1599 " AND sverified",zEAddr))
1600 ){
1601 iErrLine = 3;
1602 zErr = "This email address is already claimed by another user";
1603 }else{
1604 /* If all of the tests above have passed, that means that the submitted
1605
+50 -4
--- src/main.c
+++ src/main.c
@@ -2095,15 +2095,19 @@
20952095
** REPO for a check-in or ticket that matches the
20962096
** value of "name", then redirect to URL. There
20972097
** can be multiple "redirect:" lines that are
20982098
** processed in order. If the REPO is "*", then
20992099
** an unconditional redirect to URL is taken.
2100
+**
2101
+** jsmode: VALUE Specifies the delivery mode for JavaScript
2102
+** files. See the help text for the --jsmode
2103
+** flag of the http command.
21002104
**
21012105
** Most CGI files contain only a "repository:" line. It is uncommon to
21022106
** use any other option.
21032107
**
2104
-** See also: http, server, winsrv
2108
+** See also: [[http]], [[server]], [[winsrv]]
21052109
*/
21062110
void cmd_cgi(void){
21072111
const char *zFile;
21082112
const char *zNotFound = 0;
21092113
char **azRedirect = 0; /* List of repositories to redirect to */
@@ -2270,10 +2274,25 @@
22702274
** this directive is a silent no-op.
22712275
*/
22722276
skin_use_alternative(blob_str(&value));
22732277
blob_reset(&value);
22742278
continue;
2279
+ }
2280
+ if( blob_eq(&key, "jsmode:") && blob_token(&line, &value) ){
2281
+ /* jsmode: MODE
2282
+ **
2283
+ ** Change how JavaScript resources are delivered with each HTML
2284
+ ** page. MODE is "inline" to put all JS inline, or "separate" to
2285
+ ** cause each JS file to be requested using a separate HTTP request,
2286
+ ** or "bundled" to have all JS files to be fetched with a single
2287
+ ** auxiliary HTTP request. Noting, however, that "single" might
2288
+ ** actually mean more than one, depending on the script-timing
2289
+ ** requirements of any given page.
2290
+ */
2291
+ builtin_set_js_delivery_mode(blob_str(&value),0);
2292
+ blob_reset(&value);
2293
+ continue;
22752294
}
22762295
if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
22772296
/* cgi-debug: FILENAME
22782297
**
22792298
** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
@@ -2455,10 +2474,23 @@
24552474
** --files GLOB comma-separate glob patterns for static file to serve
24562475
** --host NAME specify hostname of the server
24572476
** --https signal a request coming in via https
24582477
** --in FILE Take input from FILE instead of standard input
24592478
** --ipaddr ADDR Assume the request comes from the given IP address
2479
+** --jsmode MODE Determine how JavaScript is delivered with pages.
2480
+** Mode can be one of:
2481
+** inline All JavaScript is inserted inline at
2482
+** one or more points in the HTML file.
2483
+** separate Separate HTTP requests are made for
2484
+** each JavaScript file.
2485
+** bundled Groups JavaScript files into one or
2486
+** more bundled requests which
2487
+** concatenate scripts together.
2488
+** Depending on the needs of any given page, inline
2489
+** and bundled modes might result in a single
2490
+** amalgamated script or several, but both approaches
2491
+** result in fewer HTTP requests than the separate mode.
24602492
** --localauth enable automatic login for local connections
24612493
** --nocompress do not compress HTTP replies
24622494
** --nodelay omit backoffice processing if it would delay process exit
24632495
** --nojail drop root privilege but do not enter the chroot jail
24642496
** --nossl signal that no SSL connections are available
@@ -2469,11 +2501,11 @@
24692501
** --skin LABEL Use override skin LABEL
24702502
** --th-trace trace TH1 execution (for debugging purposes)
24712503
** --usepidkey Use saved encryption key from parent process. This is
24722504
** only necessary when using SEE on Windows.
24732505
**
2474
-** See also: cgi, server, winsrv
2506
+** See also: [[cgi]], [[server]], [[winsrv]]
24752507
*/
24762508
void cmd_http(void){
24772509
const char *zIpAddr = 0;
24782510
const char *zNotFound;
24792511
const char *zHost;
@@ -2484,10 +2516,11 @@
24842516
int useSCGI;
24852517
int noJail;
24862518
int allowRepoList;
24872519
24882520
Th_InitTraceLog();
2521
+ builtin_set_js_delivery_mode(find_option("jsmode",0,1),0);
24892522
24902523
/* The winhttp module passes the --files option as --files-urlenc with
24912524
** the argument being URL encoded, to avoid wildcard expansion in the
24922525
** shell. This option is for internal use and is undocumented.
24932526
*/
@@ -2574,11 +2607,11 @@
25742607
/*
25752608
** Note that the following command is used by ssh:// processing.
25762609
**
25772610
** COMMAND: test-http
25782611
**
2579
-** Works like the http command but gives setup permission to all users.
2612
+** Works like the [[http]] command but gives setup permission to all users.
25802613
**
25812614
** Options:
25822615
** --th-trace trace TH1 execution (for debugging purposes)
25832616
** --usercap CAP user capability string. (Default: "sx")
25842617
**
@@ -2714,10 +2747,22 @@
27142747
** --files GLOBLIST Comma-separated list of glob patterns for static files
27152748
** --localauth enable automatic login for requests from localhost
27162749
** --localhost listen on 127.0.0.1 only (always true for "ui")
27172750
** --https Indicates that the input is coming through a reverse
27182751
** proxy that has already translated HTTPS into HTTP.
2752
+** --jsmode MODE Determine how JavaScript is delivered with pages.
2753
+** Mode can be one of:
2754
+** inline All JavaScript is inserted inline at
2755
+** the end of the HTML file.
2756
+** separate Separate HTTP requests are made for
2757
+** each JavaScript file.
2758
+** bundled One single separate HTTP fetches all
2759
+** JavaScript concatenated together.
2760
+** Depending on the needs of any given page, inline
2761
+** and bundled modes might result in a single
2762
+** amalgamated script or several, but both approaches
2763
+** result in fewer HTTP requests than the separate mode.
27192764
** --max-latency N Do not let any single HTTP request run for more than N
27202765
** seconds (only works on unix)
27212766
** --nocompress Do not compress HTTP replies
27222767
** --nojail Drop root privileges but do not enter the chroot jail
27232768
** --nossl signal that no SSL connections are available (Always
@@ -2730,11 +2775,11 @@
27302775
** --scgi Accept SCGI rather than HTTP
27312776
** --skin LABEL Use override skin LABEL
27322777
** --usepidkey Use saved encryption key from parent process. This is
27332778
** only necessary when using SEE on Windows.
27342779
**
2735
-** See also: cgi, http, winsrv
2780
+** See also: [[cgi]], [[http]], [[winsrv]]
27362781
*/
27372782
void cmd_webserver(void){
27382783
int iPort, mxPort; /* Range of TCP ports allowed */
27392784
const char *zPort; /* Value of the --port option */
27402785
const char *zBrowser; /* Name of web browser program */
@@ -2760,10 +2805,11 @@
27602805
27612806
if( g.zErrlog==0 ){
27622807
g.zErrlog = "-";
27632808
}
27642809
g.zExtRoot = find_option("extroot",0,1);
2810
+ builtin_set_js_delivery_mode(find_option("jsmode",0,1),0);
27652811
zFileGlob = find_option("files-urlenc",0,1);
27662812
if( zFileGlob ){
27672813
char *z = mprintf("%s", zFileGlob);
27682814
dehttpize(z);
27692815
zFileGlob = z;
27702816
--- src/main.c
+++ src/main.c
@@ -2095,15 +2095,19 @@
2095 ** REPO for a check-in or ticket that matches the
2096 ** value of "name", then redirect to URL. There
2097 ** can be multiple "redirect:" lines that are
2098 ** processed in order. If the REPO is "*", then
2099 ** an unconditional redirect to URL is taken.
 
 
 
 
2100 **
2101 ** Most CGI files contain only a "repository:" line. It is uncommon to
2102 ** use any other option.
2103 **
2104 ** See also: http, server, winsrv
2105 */
2106 void cmd_cgi(void){
2107 const char *zFile;
2108 const char *zNotFound = 0;
2109 char **azRedirect = 0; /* List of repositories to redirect to */
@@ -2270,10 +2274,25 @@
2270 ** this directive is a silent no-op.
2271 */
2272 skin_use_alternative(blob_str(&value));
2273 blob_reset(&value);
2274 continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2275 }
2276 if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
2277 /* cgi-debug: FILENAME
2278 **
2279 ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
@@ -2455,10 +2474,23 @@
2455 ** --files GLOB comma-separate glob patterns for static file to serve
2456 ** --host NAME specify hostname of the server
2457 ** --https signal a request coming in via https
2458 ** --in FILE Take input from FILE instead of standard input
2459 ** --ipaddr ADDR Assume the request comes from the given IP address
 
 
 
 
 
 
 
 
 
 
 
 
 
2460 ** --localauth enable automatic login for local connections
2461 ** --nocompress do not compress HTTP replies
2462 ** --nodelay omit backoffice processing if it would delay process exit
2463 ** --nojail drop root privilege but do not enter the chroot jail
2464 ** --nossl signal that no SSL connections are available
@@ -2469,11 +2501,11 @@
2469 ** --skin LABEL Use override skin LABEL
2470 ** --th-trace trace TH1 execution (for debugging purposes)
2471 ** --usepidkey Use saved encryption key from parent process. This is
2472 ** only necessary when using SEE on Windows.
2473 **
2474 ** See also: cgi, server, winsrv
2475 */
2476 void cmd_http(void){
2477 const char *zIpAddr = 0;
2478 const char *zNotFound;
2479 const char *zHost;
@@ -2484,10 +2516,11 @@
2484 int useSCGI;
2485 int noJail;
2486 int allowRepoList;
2487
2488 Th_InitTraceLog();
 
2489
2490 /* The winhttp module passes the --files option as --files-urlenc with
2491 ** the argument being URL encoded, to avoid wildcard expansion in the
2492 ** shell. This option is for internal use and is undocumented.
2493 */
@@ -2574,11 +2607,11 @@
2574 /*
2575 ** Note that the following command is used by ssh:// processing.
2576 **
2577 ** COMMAND: test-http
2578 **
2579 ** Works like the http command but gives setup permission to all users.
2580 **
2581 ** Options:
2582 ** --th-trace trace TH1 execution (for debugging purposes)
2583 ** --usercap CAP user capability string. (Default: "sx")
2584 **
@@ -2714,10 +2747,22 @@
2714 ** --files GLOBLIST Comma-separated list of glob patterns for static files
2715 ** --localauth enable automatic login for requests from localhost
2716 ** --localhost listen on 127.0.0.1 only (always true for "ui")
2717 ** --https Indicates that the input is coming through a reverse
2718 ** proxy that has already translated HTTPS into HTTP.
 
 
 
 
 
 
 
 
 
 
 
 
2719 ** --max-latency N Do not let any single HTTP request run for more than N
2720 ** seconds (only works on unix)
2721 ** --nocompress Do not compress HTTP replies
2722 ** --nojail Drop root privileges but do not enter the chroot jail
2723 ** --nossl signal that no SSL connections are available (Always
@@ -2730,11 +2775,11 @@
2730 ** --scgi Accept SCGI rather than HTTP
2731 ** --skin LABEL Use override skin LABEL
2732 ** --usepidkey Use saved encryption key from parent process. This is
2733 ** only necessary when using SEE on Windows.
2734 **
2735 ** See also: cgi, http, winsrv
2736 */
2737 void cmd_webserver(void){
2738 int iPort, mxPort; /* Range of TCP ports allowed */
2739 const char *zPort; /* Value of the --port option */
2740 const char *zBrowser; /* Name of web browser program */
@@ -2760,10 +2805,11 @@
2760
2761 if( g.zErrlog==0 ){
2762 g.zErrlog = "-";
2763 }
2764 g.zExtRoot = find_option("extroot",0,1);
 
2765 zFileGlob = find_option("files-urlenc",0,1);
2766 if( zFileGlob ){
2767 char *z = mprintf("%s", zFileGlob);
2768 dehttpize(z);
2769 zFileGlob = z;
2770
--- src/main.c
+++ src/main.c
@@ -2095,15 +2095,19 @@
2095 ** REPO for a check-in or ticket that matches the
2096 ** value of "name", then redirect to URL. There
2097 ** can be multiple "redirect:" lines that are
2098 ** processed in order. If the REPO is "*", then
2099 ** an unconditional redirect to URL is taken.
2100 **
2101 ** jsmode: VALUE Specifies the delivery mode for JavaScript
2102 ** files. See the help text for the --jsmode
2103 ** flag of the http command.
2104 **
2105 ** Most CGI files contain only a "repository:" line. It is uncommon to
2106 ** use any other option.
2107 **
2108 ** See also: [[http]], [[server]], [[winsrv]]
2109 */
2110 void cmd_cgi(void){
2111 const char *zFile;
2112 const char *zNotFound = 0;
2113 char **azRedirect = 0; /* List of repositories to redirect to */
@@ -2270,10 +2274,25 @@
2274 ** this directive is a silent no-op.
2275 */
2276 skin_use_alternative(blob_str(&value));
2277 blob_reset(&value);
2278 continue;
2279 }
2280 if( blob_eq(&key, "jsmode:") && blob_token(&line, &value) ){
2281 /* jsmode: MODE
2282 **
2283 ** Change how JavaScript resources are delivered with each HTML
2284 ** page. MODE is "inline" to put all JS inline, or "separate" to
2285 ** cause each JS file to be requested using a separate HTTP request,
2286 ** or "bundled" to have all JS files to be fetched with a single
2287 ** auxiliary HTTP request. Noting, however, that "single" might
2288 ** actually mean more than one, depending on the script-timing
2289 ** requirements of any given page.
2290 */
2291 builtin_set_js_delivery_mode(blob_str(&value),0);
2292 blob_reset(&value);
2293 continue;
2294 }
2295 if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
2296 /* cgi-debug: FILENAME
2297 **
2298 ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
@@ -2455,10 +2474,23 @@
2474 ** --files GLOB comma-separate glob patterns for static file to serve
2475 ** --host NAME specify hostname of the server
2476 ** --https signal a request coming in via https
2477 ** --in FILE Take input from FILE instead of standard input
2478 ** --ipaddr ADDR Assume the request comes from the given IP address
2479 ** --jsmode MODE Determine how JavaScript is delivered with pages.
2480 ** Mode can be one of:
2481 ** inline All JavaScript is inserted inline at
2482 ** one or more points in the HTML file.
2483 ** separate Separate HTTP requests are made for
2484 ** each JavaScript file.
2485 ** bundled Groups JavaScript files into one or
2486 ** more bundled requests which
2487 ** concatenate scripts together.
2488 ** Depending on the needs of any given page, inline
2489 ** and bundled modes might result in a single
2490 ** amalgamated script or several, but both approaches
2491 ** result in fewer HTTP requests than the separate mode.
2492 ** --localauth enable automatic login for local connections
2493 ** --nocompress do not compress HTTP replies
2494 ** --nodelay omit backoffice processing if it would delay process exit
2495 ** --nojail drop root privilege but do not enter the chroot jail
2496 ** --nossl signal that no SSL connections are available
@@ -2469,11 +2501,11 @@
2501 ** --skin LABEL Use override skin LABEL
2502 ** --th-trace trace TH1 execution (for debugging purposes)
2503 ** --usepidkey Use saved encryption key from parent process. This is
2504 ** only necessary when using SEE on Windows.
2505 **
2506 ** See also: [[cgi]], [[server]], [[winsrv]]
2507 */
2508 void cmd_http(void){
2509 const char *zIpAddr = 0;
2510 const char *zNotFound;
2511 const char *zHost;
@@ -2484,10 +2516,11 @@
2516 int useSCGI;
2517 int noJail;
2518 int allowRepoList;
2519
2520 Th_InitTraceLog();
2521 builtin_set_js_delivery_mode(find_option("jsmode",0,1),0);
2522
2523 /* The winhttp module passes the --files option as --files-urlenc with
2524 ** the argument being URL encoded, to avoid wildcard expansion in the
2525 ** shell. This option is for internal use and is undocumented.
2526 */
@@ -2574,11 +2607,11 @@
2607 /*
2608 ** Note that the following command is used by ssh:// processing.
2609 **
2610 ** COMMAND: test-http
2611 **
2612 ** Works like the [[http]] command but gives setup permission to all users.
2613 **
2614 ** Options:
2615 ** --th-trace trace TH1 execution (for debugging purposes)
2616 ** --usercap CAP user capability string. (Default: "sx")
2617 **
@@ -2714,10 +2747,22 @@
2747 ** --files GLOBLIST Comma-separated list of glob patterns for static files
2748 ** --localauth enable automatic login for requests from localhost
2749 ** --localhost listen on 127.0.0.1 only (always true for "ui")
2750 ** --https Indicates that the input is coming through a reverse
2751 ** proxy that has already translated HTTPS into HTTP.
2752 ** --jsmode MODE Determine how JavaScript is delivered with pages.
2753 ** Mode can be one of:
2754 ** inline All JavaScript is inserted inline at
2755 ** the end of the HTML file.
2756 ** separate Separate HTTP requests are made for
2757 ** each JavaScript file.
2758 ** bundled One single separate HTTP fetches all
2759 ** JavaScript concatenated together.
2760 ** Depending on the needs of any given page, inline
2761 ** and bundled modes might result in a single
2762 ** amalgamated script or several, but both approaches
2763 ** result in fewer HTTP requests than the separate mode.
2764 ** --max-latency N Do not let any single HTTP request run for more than N
2765 ** seconds (only works on unix)
2766 ** --nocompress Do not compress HTTP replies
2767 ** --nojail Drop root privileges but do not enter the chroot jail
2768 ** --nossl signal that no SSL connections are available (Always
@@ -2730,11 +2775,11 @@
2775 ** --scgi Accept SCGI rather than HTTP
2776 ** --skin LABEL Use override skin LABEL
2777 ** --usepidkey Use saved encryption key from parent process. This is
2778 ** only necessary when using SEE on Windows.
2779 **
2780 ** See also: [[cgi]], [[http]], [[winsrv]]
2781 */
2782 void cmd_webserver(void){
2783 int iPort, mxPort; /* Range of TCP ports allowed */
2784 const char *zPort; /* Value of the --port option */
2785 const char *zBrowser; /* Name of web browser program */
@@ -2760,10 +2805,11 @@
2805
2806 if( g.zErrlog==0 ){
2807 g.zErrlog = "-";
2808 }
2809 g.zExtRoot = find_option("extroot",0,1);
2810 builtin_set_js_delivery_mode(find_option("jsmode",0,1),0);
2811 zFileGlob = find_option("files-urlenc",0,1);
2812 if( zFileGlob ){
2813 char *z = mprintf("%s", zFileGlob);
2814 dehttpize(z);
2815 zFileGlob = z;
2816
+9 -13
--- src/main.mk
+++ src/main.mk
@@ -154,11 +154,10 @@
154154
$(SRCDIR)/webmail.c \
155155
$(SRCDIR)/wiki.c \
156156
$(SRCDIR)/wikiformat.c \
157157
$(SRCDIR)/winfile.c \
158158
$(SRCDIR)/winhttp.c \
159
- $(SRCDIR)/wysiwyg.c \
160159
$(SRCDIR)/xfer.c \
161160
$(SRCDIR)/xfersetup.c \
162161
$(SRCDIR)/zip.c
163162
164163
EXTRA_FILES = \
@@ -224,14 +223,18 @@
224223
$(SRCDIR)/default.css \
225224
$(SRCDIR)/diff.tcl \
226225
$(SRCDIR)/forum.js \
227226
$(SRCDIR)/fossil.bootstrap.js \
228227
$(SRCDIR)/fossil.confirmer.js \
228
+ $(SRCDIR)/fossil.copybutton.js \
229229
$(SRCDIR)/fossil.dom.js \
230230
$(SRCDIR)/fossil.fetch.js \
231
+ $(SRCDIR)/fossil.numbered-lines.js \
231232
$(SRCDIR)/fossil.page.fileedit.js \
232233
$(SRCDIR)/fossil.page.forumpost.js \
234
+ $(SRCDIR)/fossil.page.wikiedit.js \
235
+ $(SRCDIR)/fossil.popupwidget.js \
233236
$(SRCDIR)/fossil.storage.js \
234237
$(SRCDIR)/fossil.tabs.js \
235238
$(SRCDIR)/graph.js \
236239
$(SRCDIR)/href.js \
237240
$(SRCDIR)/login.js \
@@ -257,10 +260,11 @@
257260
$(SRCDIR)/sounds/d.wav \
258261
$(SRCDIR)/sounds/e.wav \
259262
$(SRCDIR)/sounds/f.wav \
260263
$(SRCDIR)/style.admin_log.css \
261264
$(SRCDIR)/style.fileedit.css \
265
+ $(SRCDIR)/style.wikiedit.css \
262266
$(SRCDIR)/tree.js \
263267
$(SRCDIR)/useredit.js \
264268
$(SRCDIR)/wiki.wiki
265269
266270
TRANS_SRC = \
@@ -402,11 +406,10 @@
402406
$(OBJDIR)/webmail_.c \
403407
$(OBJDIR)/wiki_.c \
404408
$(OBJDIR)/wikiformat_.c \
405409
$(OBJDIR)/winfile_.c \
406410
$(OBJDIR)/winhttp_.c \
407
- $(OBJDIR)/wysiwyg_.c \
408411
$(OBJDIR)/xfer_.c \
409412
$(OBJDIR)/xfersetup_.c \
410413
$(OBJDIR)/zip_.c
411414
412415
OBJ = \
@@ -548,11 +551,10 @@
548551
$(OBJDIR)/webmail.o \
549552
$(OBJDIR)/wiki.o \
550553
$(OBJDIR)/wikiformat.o \
551554
$(OBJDIR)/winfile.o \
552555
$(OBJDIR)/winhttp.o \
553
- $(OBJDIR)/wysiwyg.o \
554556
$(OBJDIR)/xfer.o \
555557
$(OBJDIR)/xfersetup.o \
556558
$(OBJDIR)/zip.o
557559
all: $(OBJDIR) $(APPNAME)
558560
@@ -598,13 +600,16 @@
598600
# the run to just those test cases.
599601
#
600602
test: $(OBJDIR) $(APPNAME)
601603
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS)
602604
603
-$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
605
+$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h
604606
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
605607
608
+$(OBJDIR)/phony.h:
609
+ # Force rebuild of VERSION.h every time we run "make"
610
+
606611
# Setup the options used to compile the included SQLite library.
607612
SQLITE_OPTIONS = -DNDEBUG=1 \
608613
-DSQLITE_DQS=0 \
609614
-DSQLITE_THREADSAFE=0 \
610615
-DSQLITE_DEFAULT_MEMSTATUS=0 \
@@ -881,11 +886,10 @@
881886
$(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \
882887
$(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
883888
$(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
884889
$(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \
885890
$(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
886
- $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \
887891
$(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \
888892
$(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \
889893
$(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \
890894
$(SRCDIR)/sqlite3.h \
891895
$(SRCDIR)/th.h \
@@ -2012,18 +2016,10 @@
20122016
$(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h
20132017
$(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c
20142018
20152019
$(OBJDIR)/winhttp.h: $(OBJDIR)/headers
20162020
2017
-$(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(OBJDIR)/translate
2018
- $(OBJDIR)/translate $(SRCDIR)/wysiwyg.c >$@
2019
-
2020
-$(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h
2021
- $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c
2022
-
2023
-$(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers
2024
-
20252021
$(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(OBJDIR)/translate
20262022
$(OBJDIR)/translate $(SRCDIR)/xfer.c >$@
20272023
20282024
$(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h
20292025
$(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c
20302026
--- src/main.mk
+++ src/main.mk
@@ -154,11 +154,10 @@
154 $(SRCDIR)/webmail.c \
155 $(SRCDIR)/wiki.c \
156 $(SRCDIR)/wikiformat.c \
157 $(SRCDIR)/winfile.c \
158 $(SRCDIR)/winhttp.c \
159 $(SRCDIR)/wysiwyg.c \
160 $(SRCDIR)/xfer.c \
161 $(SRCDIR)/xfersetup.c \
162 $(SRCDIR)/zip.c
163
164 EXTRA_FILES = \
@@ -224,14 +223,18 @@
224 $(SRCDIR)/default.css \
225 $(SRCDIR)/diff.tcl \
226 $(SRCDIR)/forum.js \
227 $(SRCDIR)/fossil.bootstrap.js \
228 $(SRCDIR)/fossil.confirmer.js \
 
229 $(SRCDIR)/fossil.dom.js \
230 $(SRCDIR)/fossil.fetch.js \
 
231 $(SRCDIR)/fossil.page.fileedit.js \
232 $(SRCDIR)/fossil.page.forumpost.js \
 
 
233 $(SRCDIR)/fossil.storage.js \
234 $(SRCDIR)/fossil.tabs.js \
235 $(SRCDIR)/graph.js \
236 $(SRCDIR)/href.js \
237 $(SRCDIR)/login.js \
@@ -257,10 +260,11 @@
257 $(SRCDIR)/sounds/d.wav \
258 $(SRCDIR)/sounds/e.wav \
259 $(SRCDIR)/sounds/f.wav \
260 $(SRCDIR)/style.admin_log.css \
261 $(SRCDIR)/style.fileedit.css \
 
262 $(SRCDIR)/tree.js \
263 $(SRCDIR)/useredit.js \
264 $(SRCDIR)/wiki.wiki
265
266 TRANS_SRC = \
@@ -402,11 +406,10 @@
402 $(OBJDIR)/webmail_.c \
403 $(OBJDIR)/wiki_.c \
404 $(OBJDIR)/wikiformat_.c \
405 $(OBJDIR)/winfile_.c \
406 $(OBJDIR)/winhttp_.c \
407 $(OBJDIR)/wysiwyg_.c \
408 $(OBJDIR)/xfer_.c \
409 $(OBJDIR)/xfersetup_.c \
410 $(OBJDIR)/zip_.c
411
412 OBJ = \
@@ -548,11 +551,10 @@
548 $(OBJDIR)/webmail.o \
549 $(OBJDIR)/wiki.o \
550 $(OBJDIR)/wikiformat.o \
551 $(OBJDIR)/winfile.o \
552 $(OBJDIR)/winhttp.o \
553 $(OBJDIR)/wysiwyg.o \
554 $(OBJDIR)/xfer.o \
555 $(OBJDIR)/xfersetup.o \
556 $(OBJDIR)/zip.o
557 all: $(OBJDIR) $(APPNAME)
558
@@ -598,13 +600,16 @@
598 # the run to just those test cases.
599 #
600 test: $(OBJDIR) $(APPNAME)
601 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS)
602
603 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
604 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
605
 
 
 
606 # Setup the options used to compile the included SQLite library.
607 SQLITE_OPTIONS = -DNDEBUG=1 \
608 -DSQLITE_DQS=0 \
609 -DSQLITE_THREADSAFE=0 \
610 -DSQLITE_DEFAULT_MEMSTATUS=0 \
@@ -881,11 +886,10 @@
881 $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \
882 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
883 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
884 $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \
885 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
886 $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \
887 $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \
888 $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \
889 $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \
890 $(SRCDIR)/sqlite3.h \
891 $(SRCDIR)/th.h \
@@ -2012,18 +2016,10 @@
2012 $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h
2013 $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c
2014
2015 $(OBJDIR)/winhttp.h: $(OBJDIR)/headers
2016
2017 $(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(OBJDIR)/translate
2018 $(OBJDIR)/translate $(SRCDIR)/wysiwyg.c >$@
2019
2020 $(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h
2021 $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c
2022
2023 $(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers
2024
2025 $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(OBJDIR)/translate
2026 $(OBJDIR)/translate $(SRCDIR)/xfer.c >$@
2027
2028 $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h
2029 $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c
2030
--- src/main.mk
+++ src/main.mk
@@ -154,11 +154,10 @@
154 $(SRCDIR)/webmail.c \
155 $(SRCDIR)/wiki.c \
156 $(SRCDIR)/wikiformat.c \
157 $(SRCDIR)/winfile.c \
158 $(SRCDIR)/winhttp.c \
 
159 $(SRCDIR)/xfer.c \
160 $(SRCDIR)/xfersetup.c \
161 $(SRCDIR)/zip.c
162
163 EXTRA_FILES = \
@@ -224,14 +223,18 @@
223 $(SRCDIR)/default.css \
224 $(SRCDIR)/diff.tcl \
225 $(SRCDIR)/forum.js \
226 $(SRCDIR)/fossil.bootstrap.js \
227 $(SRCDIR)/fossil.confirmer.js \
228 $(SRCDIR)/fossil.copybutton.js \
229 $(SRCDIR)/fossil.dom.js \
230 $(SRCDIR)/fossil.fetch.js \
231 $(SRCDIR)/fossil.numbered-lines.js \
232 $(SRCDIR)/fossil.page.fileedit.js \
233 $(SRCDIR)/fossil.page.forumpost.js \
234 $(SRCDIR)/fossil.page.wikiedit.js \
235 $(SRCDIR)/fossil.popupwidget.js \
236 $(SRCDIR)/fossil.storage.js \
237 $(SRCDIR)/fossil.tabs.js \
238 $(SRCDIR)/graph.js \
239 $(SRCDIR)/href.js \
240 $(SRCDIR)/login.js \
@@ -257,10 +260,11 @@
260 $(SRCDIR)/sounds/d.wav \
261 $(SRCDIR)/sounds/e.wav \
262 $(SRCDIR)/sounds/f.wav \
263 $(SRCDIR)/style.admin_log.css \
264 $(SRCDIR)/style.fileedit.css \
265 $(SRCDIR)/style.wikiedit.css \
266 $(SRCDIR)/tree.js \
267 $(SRCDIR)/useredit.js \
268 $(SRCDIR)/wiki.wiki
269
270 TRANS_SRC = \
@@ -402,11 +406,10 @@
406 $(OBJDIR)/webmail_.c \
407 $(OBJDIR)/wiki_.c \
408 $(OBJDIR)/wikiformat_.c \
409 $(OBJDIR)/winfile_.c \
410 $(OBJDIR)/winhttp_.c \
 
411 $(OBJDIR)/xfer_.c \
412 $(OBJDIR)/xfersetup_.c \
413 $(OBJDIR)/zip_.c
414
415 OBJ = \
@@ -548,11 +551,10 @@
551 $(OBJDIR)/webmail.o \
552 $(OBJDIR)/wiki.o \
553 $(OBJDIR)/wikiformat.o \
554 $(OBJDIR)/winfile.o \
555 $(OBJDIR)/winhttp.o \
 
556 $(OBJDIR)/xfer.o \
557 $(OBJDIR)/xfersetup.o \
558 $(OBJDIR)/zip.o
559 all: $(OBJDIR) $(APPNAME)
560
@@ -598,13 +600,16 @@
600 # the run to just those test cases.
601 #
602 test: $(OBJDIR) $(APPNAME)
603 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS)
604
605 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h
606 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
607
608 $(OBJDIR)/phony.h:
609 # Force rebuild of VERSION.h every time we run "make"
610
611 # Setup the options used to compile the included SQLite library.
612 SQLITE_OPTIONS = -DNDEBUG=1 \
613 -DSQLITE_DQS=0 \
614 -DSQLITE_THREADSAFE=0 \
615 -DSQLITE_DEFAULT_MEMSTATUS=0 \
@@ -881,11 +886,10 @@
886 $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \
887 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
888 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
889 $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \
890 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
 
891 $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \
892 $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \
893 $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \
894 $(SRCDIR)/sqlite3.h \
895 $(SRCDIR)/th.h \
@@ -2012,18 +2016,10 @@
2016 $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h
2017 $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c
2018
2019 $(OBJDIR)/winhttp.h: $(OBJDIR)/headers
2020
 
 
 
 
 
 
 
 
2021 $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(OBJDIR)/translate
2022 $(OBJDIR)/translate $(SRCDIR)/xfer.c >$@
2023
2024 $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h
2025 $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c
2026
+13 -5
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -164,11 +164,10 @@
164164
webmail
165165
wiki
166166
wikiformat
167167
winfile
168168
winhttp
169
- wysiwyg
170169
xfer
171170
xfersetup
172171
zip
173172
http_ssl
174173
}
@@ -370,15 +369,18 @@
370369
# the run to just those test cases.
371370
#
372371
test: $(OBJDIR) $(APPNAME)
373372
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS)
374373
375
-$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
374
+$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h
376375
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
377376
$(SRCDIR)/../manifest \
378377
$(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
379378
379
+$(OBJDIR)/phony.h:
380
+ # Force rebuild of VERSION.h every time we run "make"
381
+
380382
# Setup the options used to compile the included SQLite library.
381383
SQLITE_OPTIONS = <<<SQLITE_OPTIONS>>>
382384
383385
# Setup the options used to compile the included SQLite shell.
384386
SHELL_OPTIONS = <<<SHELL_OPTIONS>>>
@@ -1081,13 +1083,16 @@
10811083
# build is done from, i.e. the checkout belongs to. Do not sync/push
10821084
# the repository after running the tests.
10831085
test: $(OBJDIR) $(APPNAME)
10841086
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
10851087
1086
-$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION)
1088
+$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(OBJDIR)/phony.h
10871089
$(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@
10881090
1091
+$(OBJDIR)/phony.h:
1092
+ # Force rebuild of VERSION.h every time "make" is run
1093
+
10891094
# The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
10901095
# to 1. If it is set to 1, then there is no need to build or link
10911096
# the sqlite3.o object. Instead, the system SQLite will be linked
10921097
# using -lsqlite3.
10931098
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
@@ -1907,12 +1912,15 @@
19071912
$(TCC) /Fo$@ /Fd$(@D)\ -c $**
19081913
19091914
"$(OX)\miniz$O" : "$(SRCDIR)\miniz.c"
19101915
$(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $**
19111916
1912
-"$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION"
1913
- $** > $@
1917
+"$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" "$(B)\phony.h"
1918
+ "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" > $@
1919
+
1920
+"$(B)\phony.h" :
1921
+ rem Force rebuild of VERSION.h whenever nmake is run
19141922
19151923
"$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c"
19161924
$(TCC) /Fo$@ /Fd$(@D)\ -c $**
19171925
19181926
"$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC)
19191927
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -164,11 +164,10 @@
164 webmail
165 wiki
166 wikiformat
167 winfile
168 winhttp
169 wysiwyg
170 xfer
171 xfersetup
172 zip
173 http_ssl
174 }
@@ -370,15 +369,18 @@
370 # the run to just those test cases.
371 #
372 test: $(OBJDIR) $(APPNAME)
373 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS)
374
375 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
376 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
377 $(SRCDIR)/../manifest \
378 $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
379
 
 
 
380 # Setup the options used to compile the included SQLite library.
381 SQLITE_OPTIONS = <<<SQLITE_OPTIONS>>>
382
383 # Setup the options used to compile the included SQLite shell.
384 SHELL_OPTIONS = <<<SHELL_OPTIONS>>>
@@ -1081,13 +1083,16 @@
1081 # build is done from, i.e. the checkout belongs to. Do not sync/push
1082 # the repository after running the tests.
1083 test: $(OBJDIR) $(APPNAME)
1084 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
1085
1086 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION)
1087 $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@
1088
 
 
 
1089 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
1090 # to 1. If it is set to 1, then there is no need to build or link
1091 # the sqlite3.o object. Instead, the system SQLite will be linked
1092 # using -lsqlite3.
1093 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
@@ -1907,12 +1912,15 @@
1907 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1908
1909 "$(OX)\miniz$O" : "$(SRCDIR)\miniz.c"
1910 $(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $**
1911
1912 "$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION"
1913 $** > $@
 
 
 
1914
1915 "$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c"
1916 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1917
1918 "$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC)
1919
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -164,11 +164,10 @@
164 webmail
165 wiki
166 wikiformat
167 winfile
168 winhttp
 
169 xfer
170 xfersetup
171 zip
172 http_ssl
173 }
@@ -370,15 +369,18 @@
369 # the run to just those test cases.
370 #
371 test: $(OBJDIR) $(APPNAME)
372 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS)
373
374 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h
375 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
376 $(SRCDIR)/../manifest \
377 $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
378
379 $(OBJDIR)/phony.h:
380 # Force rebuild of VERSION.h every time we run "make"
381
382 # Setup the options used to compile the included SQLite library.
383 SQLITE_OPTIONS = <<<SQLITE_OPTIONS>>>
384
385 # Setup the options used to compile the included SQLite shell.
386 SHELL_OPTIONS = <<<SHELL_OPTIONS>>>
@@ -1081,13 +1083,16 @@
1083 # build is done from, i.e. the checkout belongs to. Do not sync/push
1084 # the repository after running the tests.
1085 test: $(OBJDIR) $(APPNAME)
1086 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
1087
1088 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(OBJDIR)/phony.h
1089 $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@
1090
1091 $(OBJDIR)/phony.h:
1092 # Force rebuild of VERSION.h every time "make" is run
1093
1094 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
1095 # to 1. If it is set to 1, then there is no need to build or link
1096 # the sqlite3.o object. Instead, the system SQLite will be linked
1097 # using -lsqlite3.
1098 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
@@ -1907,12 +1912,15 @@
1912 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1913
1914 "$(OX)\miniz$O" : "$(SRCDIR)\miniz.c"
1915 $(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $**
1916
1917 "$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" "$(B)\phony.h"
1918 "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" > $@
1919
1920 "$(B)\phony.h" :
1921 rem Force rebuild of VERSION.h whenever nmake is run
1922
1923 "$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c"
1924 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1925
1926 "$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC)
1927
--- src/mkbuiltin.c
+++ src/mkbuiltin.c
@@ -62,10 +62,11 @@
6262
fclose(in);
6363
z[got] = 0;
6464
return z;
6565
}
6666
67
+#ifndef FOSSIL_DEBUG
6768
/*
6869
** Try to compress a javascript file by removing unnecessary whitespace.
6970
**
7071
** Warning: This compression routine does not necessarily work for any
7172
** arbitrary Javascript source file. But it should work ok for the
@@ -88,10 +89,11 @@
8889
i = k-1;
8990
continue;
9091
}
9192
}
9293
if( c=='\n' ){
94
+ if( j==0 ) continue;
9395
while( j>0 && isspace(z[j-1]) ) j--;
9496
z[j++] = '\n';
9597
while( i+1<n && isspace(z[i+1]) ) i++;
9698
continue;
9799
}
@@ -98,10 +100,11 @@
98100
z[j++] = c;
99101
}
100102
z[j] = 0;
101103
*pn = j;
102104
}
105
+#endif /* FOSSIL_DEBUG */
103106
104107
/*
105108
** There is an instance of the following for each file translated.
106109
*/
107110
typedef struct Resource Resource;
@@ -278,11 +281,13 @@
278281
int nRes;
279282
unsigned char *pData;
280283
int nErr = 0;
281284
int nSkip;
282285
int nPrefix = 0;
286
+#ifndef FOSSIL_DEBUG
283287
int nName;
288
+#endif
284289
285290
if( argc==1 ){
286291
fprintf(stderr, "usage\t:%s "
287292
"[--prefix path] [--reslist file] [resource-file1 ...]\n",
288293
argv[0]
@@ -349,19 +354,21 @@
349354
while( pData[nSkip]=='#' ){
350355
while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; }
351356
if( pData[nSkip]=='\n' ) nSkip++;
352357
}
353358
359
+#ifndef FOSSIL_DEBUG
354360
/* Compress javascript source files */
355361
nName = (int)strlen(aRes[i].zName);
356362
if( (nName>3 && strcmp(&aRes[i].zName[nName-3],".js")==0)
357363
|| (nName>7 && strcmp(&aRes[i].zName[nName-7], "/js.txt")==0)
358364
){
359365
int x = sz-nSkip;
360366
compressJavascript(pData+nSkip, &x);
361367
sz = x + nSkip;
362368
}
369
+#endif
363370
364371
aRes[i].nByte = sz - nSkip;
365372
aRes[i].idx = i;
366373
printf("/* Content of file %s */\n", aRes[i].zName);
367374
printf("static const unsigned char bidata%d[%d] = {\n ",
368375
--- src/mkbuiltin.c
+++ src/mkbuiltin.c
@@ -62,10 +62,11 @@
62 fclose(in);
63 z[got] = 0;
64 return z;
65 }
66
 
67 /*
68 ** Try to compress a javascript file by removing unnecessary whitespace.
69 **
70 ** Warning: This compression routine does not necessarily work for any
71 ** arbitrary Javascript source file. But it should work ok for the
@@ -88,10 +89,11 @@
88 i = k-1;
89 continue;
90 }
91 }
92 if( c=='\n' ){
 
93 while( j>0 && isspace(z[j-1]) ) j--;
94 z[j++] = '\n';
95 while( i+1<n && isspace(z[i+1]) ) i++;
96 continue;
97 }
@@ -98,10 +100,11 @@
98 z[j++] = c;
99 }
100 z[j] = 0;
101 *pn = j;
102 }
 
103
104 /*
105 ** There is an instance of the following for each file translated.
106 */
107 typedef struct Resource Resource;
@@ -278,11 +281,13 @@
278 int nRes;
279 unsigned char *pData;
280 int nErr = 0;
281 int nSkip;
282 int nPrefix = 0;
 
283 int nName;
 
284
285 if( argc==1 ){
286 fprintf(stderr, "usage\t:%s "
287 "[--prefix path] [--reslist file] [resource-file1 ...]\n",
288 argv[0]
@@ -349,19 +354,21 @@
349 while( pData[nSkip]=='#' ){
350 while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; }
351 if( pData[nSkip]=='\n' ) nSkip++;
352 }
353
 
354 /* Compress javascript source files */
355 nName = (int)strlen(aRes[i].zName);
356 if( (nName>3 && strcmp(&aRes[i].zName[nName-3],".js")==0)
357 || (nName>7 && strcmp(&aRes[i].zName[nName-7], "/js.txt")==0)
358 ){
359 int x = sz-nSkip;
360 compressJavascript(pData+nSkip, &x);
361 sz = x + nSkip;
362 }
 
363
364 aRes[i].nByte = sz - nSkip;
365 aRes[i].idx = i;
366 printf("/* Content of file %s */\n", aRes[i].zName);
367 printf("static const unsigned char bidata%d[%d] = {\n ",
368
--- src/mkbuiltin.c
+++ src/mkbuiltin.c
@@ -62,10 +62,11 @@
62 fclose(in);
63 z[got] = 0;
64 return z;
65 }
66
67 #ifndef FOSSIL_DEBUG
68 /*
69 ** Try to compress a javascript file by removing unnecessary whitespace.
70 **
71 ** Warning: This compression routine does not necessarily work for any
72 ** arbitrary Javascript source file. But it should work ok for the
@@ -88,10 +89,11 @@
89 i = k-1;
90 continue;
91 }
92 }
93 if( c=='\n' ){
94 if( j==0 ) continue;
95 while( j>0 && isspace(z[j-1]) ) j--;
96 z[j++] = '\n';
97 while( i+1<n && isspace(z[i+1]) ) i++;
98 continue;
99 }
@@ -98,10 +100,11 @@
100 z[j++] = c;
101 }
102 z[j] = 0;
103 *pn = j;
104 }
105 #endif /* FOSSIL_DEBUG */
106
107 /*
108 ** There is an instance of the following for each file translated.
109 */
110 typedef struct Resource Resource;
@@ -278,11 +281,13 @@
281 int nRes;
282 unsigned char *pData;
283 int nErr = 0;
284 int nSkip;
285 int nPrefix = 0;
286 #ifndef FOSSIL_DEBUG
287 int nName;
288 #endif
289
290 if( argc==1 ){
291 fprintf(stderr, "usage\t:%s "
292 "[--prefix path] [--reslist file] [resource-file1 ...]\n",
293 argv[0]
@@ -349,19 +354,21 @@
354 while( pData[nSkip]=='#' ){
355 while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; }
356 if( pData[nSkip]=='\n' ) nSkip++;
357 }
358
359 #ifndef FOSSIL_DEBUG
360 /* Compress javascript source files */
361 nName = (int)strlen(aRes[i].zName);
362 if( (nName>3 && strcmp(&aRes[i].zName[nName-3],".js")==0)
363 || (nName>7 && strcmp(&aRes[i].zName[nName-7], "/js.txt")==0)
364 ){
365 int x = sz-nSkip;
366 compressJavascript(pData+nSkip, &x);
367 sz = x + nSkip;
368 }
369 #endif
370
371 aRes[i].nByte = sz - nSkip;
372 aRes[i].idx = i;
373 printf("/* Content of file %s */\n", aRes[i].zName);
374 printf("static const unsigned char bidata%d[%d] = {\n ",
375
--- src/mkindex.c
+++ src/mkindex.c
@@ -391,11 +391,10 @@
391391
*/
392392
void build_table(void){
393393
int i;
394394
int nWeb = 0;
395395
int mxLen = 0;
396
- int len;
397396
398397
qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare);
399398
400399
printf(
401400
"/* Automatically generated code\n"
402401
--- src/mkindex.c
+++ src/mkindex.c
@@ -391,11 +391,10 @@
391 */
392 void build_table(void){
393 int i;
394 int nWeb = 0;
395 int mxLen = 0;
396 int len;
397
398 qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare);
399
400 printf(
401 "/* Automatically generated code\n"
402
--- src/mkindex.c
+++ src/mkindex.c
@@ -391,11 +391,10 @@
391 */
392 void build_table(void){
393 int i;
394 int nWeb = 0;
395 int mxLen = 0;
 
396
397 qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare);
398
399 printf(
400 "/* Automatically generated code\n"
401
+4 -1
--- src/piechart.c
+++ src/piechart.c
@@ -142,11 +142,14 @@
142142
if( r<0.33333*r2 ) r = 0.33333*r2;
143143
h = 0;
144144
zFg = skin_detail_boolean("white-foreground") ? "white" : "black";
145145
146146
db_prepare(&q, "SELECT sum(amt), count(*) FROM piechart");
147
- if( db_step(&q)!=SQLITE_ROW ) return;
147
+ if( db_step(&q)!=SQLITE_ROW ){
148
+ db_finalize(&q);
149
+ return;
150
+ }
148151
rTotal = db_column_double(&q, 0);
149152
nTotal = db_column_int(&q, 1);
150153
db_finalize(&q);
151154
rTooSmall = 0.0;
152155
nTooSmall = 0;
153156
--- src/piechart.c
+++ src/piechart.c
@@ -142,11 +142,14 @@
142 if( r<0.33333*r2 ) r = 0.33333*r2;
143 h = 0;
144 zFg = skin_detail_boolean("white-foreground") ? "white" : "black";
145
146 db_prepare(&q, "SELECT sum(amt), count(*) FROM piechart");
147 if( db_step(&q)!=SQLITE_ROW ) return;
 
 
 
148 rTotal = db_column_double(&q, 0);
149 nTotal = db_column_int(&q, 1);
150 db_finalize(&q);
151 rTooSmall = 0.0;
152 nTooSmall = 0;
153
--- src/piechart.c
+++ src/piechart.c
@@ -142,11 +142,14 @@
142 if( r<0.33333*r2 ) r = 0.33333*r2;
143 h = 0;
144 zFg = skin_detail_boolean("white-foreground") ? "white" : "black";
145
146 db_prepare(&q, "SELECT sum(amt), count(*) FROM piechart");
147 if( db_step(&q)!=SQLITE_ROW ){
148 db_finalize(&q);
149 return;
150 }
151 rTotal = db_column_double(&q, 0);
152 nTotal = db_column_int(&q, 1);
153 db_finalize(&q);
154 rTooSmall = 0.0;
155 nTooSmall = 0;
156
+2 -2
--- src/publish.c
+++ src/publish.c
@@ -21,11 +21,11 @@
2121
#include "config.h"
2222
#include "publish.h"
2323
#include <assert.h>
2424
2525
/*
26
-** COMMAND: unpublished
26
+** COMMAND: unpublished*
2727
**
2828
** Usage: %fossil unpublished ?OPTIONS?
2929
**
3030
** Show a list of unpublished or "private" artifacts. Unpublished artifacts
3131
** will never push and hence will not be shared with collaborators.
@@ -50,11 +50,11 @@
5050
" AND event.type='ci')", 0);
5151
}
5252
}
5353
5454
/*
55
-** COMMAND: publish
55
+** COMMAND: publish*
5656
**
5757
** Usage: %fossil publish ?--only? TAGS...
5858
**
5959
** Cause artifacts identified by TAGS... to be published (made non-private).
6060
** This can be used (for example) to convert a private branch into a public
6161
--- src/publish.c
+++ src/publish.c
@@ -21,11 +21,11 @@
21 #include "config.h"
22 #include "publish.h"
23 #include <assert.h>
24
25 /*
26 ** COMMAND: unpublished
27 **
28 ** Usage: %fossil unpublished ?OPTIONS?
29 **
30 ** Show a list of unpublished or "private" artifacts. Unpublished artifacts
31 ** will never push and hence will not be shared with collaborators.
@@ -50,11 +50,11 @@
50 " AND event.type='ci')", 0);
51 }
52 }
53
54 /*
55 ** COMMAND: publish
56 **
57 ** Usage: %fossil publish ?--only? TAGS...
58 **
59 ** Cause artifacts identified by TAGS... to be published (made non-private).
60 ** This can be used (for example) to convert a private branch into a public
61
--- src/publish.c
+++ src/publish.c
@@ -21,11 +21,11 @@
21 #include "config.h"
22 #include "publish.h"
23 #include <assert.h>
24
25 /*
26 ** COMMAND: unpublished*
27 **
28 ** Usage: %fossil unpublished ?OPTIONS?
29 **
30 ** Show a list of unpublished or "private" artifacts. Unpublished artifacts
31 ** will never push and hence will not be shared with collaborators.
@@ -50,11 +50,11 @@
50 " AND event.type='ci')", 0);
51 }
52 }
53
54 /*
55 ** COMMAND: publish*
56 **
57 ** Usage: %fossil publish ?--only? TAGS...
58 **
59 ** Cause artifacts identified by TAGS... to be published (made non-private).
60 ** This can be used (for example) to convert a private branch into a public
61
-11
--- src/purge.c
+++ src/purge.c
@@ -507,21 +507,10 @@
507507
**
508508
** COMMON OPTIONS:
509509
**
510510
** --explain Make no changes, but show what would happen.
511511
** --dry-run An alias for --explain
512
-**
513
-** SUMMARY:
514
-** * fossil purge artifacts HASH.. [OPTIONS]
515
-** * fossil purge cat HASH...
516
-** * fossil purge checkins TAGS... [OPTIONS]
517
-** * fossil purge files FILENAME... [OPTIONS]
518
-** * fossil purge list
519
-** * fossil purge obliterate ID...
520
-** * fossil purge tickets NAME... [OPTIONS]
521
-** * fossil purge undo ID
522
-** * fossil purge wiki NAME... [OPTIONS]
523512
*/
524513
void purge_cmd(void){
525514
int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY;
526515
const char *zSubcmd;
527516
int n;
528517
--- src/purge.c
+++ src/purge.c
@@ -507,21 +507,10 @@
507 **
508 ** COMMON OPTIONS:
509 **
510 ** --explain Make no changes, but show what would happen.
511 ** --dry-run An alias for --explain
512 **
513 ** SUMMARY:
514 ** * fossil purge artifacts HASH.. [OPTIONS]
515 ** * fossil purge cat HASH...
516 ** * fossil purge checkins TAGS... [OPTIONS]
517 ** * fossil purge files FILENAME... [OPTIONS]
518 ** * fossil purge list
519 ** * fossil purge obliterate ID...
520 ** * fossil purge tickets NAME... [OPTIONS]
521 ** * fossil purge undo ID
522 ** * fossil purge wiki NAME... [OPTIONS]
523 */
524 void purge_cmd(void){
525 int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY;
526 const char *zSubcmd;
527 int n;
528
--- src/purge.c
+++ src/purge.c
@@ -507,21 +507,10 @@
507 **
508 ** COMMON OPTIONS:
509 **
510 ** --explain Make no changes, but show what would happen.
511 ** --dry-run An alias for --explain
 
 
 
 
 
 
 
 
 
 
 
512 */
513 void purge_cmd(void){
514 int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY;
515 const char *zSubcmd;
516 int n;
517
--- src/rebuild.c
+++ src/rebuild.c
@@ -601,12 +601,10 @@
601601
** --quiet Only show output if there are errors
602602
** --randomize Scan artifacts in a random order
603603
** --stats Show artifact statistics after rebuilding
604604
** --vacuum Run VACUUM on the database after rebuilding
605605
** --wal Set Write-Ahead-Log journalling mode on the database
606
-**
607
-** See also: deconstruct, reconstruct
608606
*/
609607
void rebuild_database(void){
610608
int forceFlag;
611609
int randomizeFlag;
612610
int errCnt = 0;
@@ -1203,12 +1201,10 @@
12031201
** Options:
12041202
** -K|--keep-rid1 Read the filename of the artifact with RID=1 from the
12051203
** file .rid in DIRECTORY.
12061204
** -P|--keep-private Mark the artifacts listed in the file .private in
12071205
** DIRECTORY as private in the new Fossil repository.
1208
-**
1209
-** See also: deconstruct, rebuild
12101206
*/
12111207
void reconstruct_cmd(void) {
12121208
char *zPassword;
12131209
int fKeepPrivate;
12141210
fKeepRid1 = find_option("keep-rid1","K",0)!=0;
@@ -1278,12 +1274,10 @@
12781274
** subdirectories to N.
12791275
** --private Include private artifacts.
12801276
** -P|--keep-private Save the list of private artifacts to the file
12811277
** .private in the DESTINATION directory (implies
12821278
** the --private option).
1283
-**
1284
-** See also: reconstruct, rebuild
12851279
*/
12861280
void deconstruct_cmd(void){
12871281
const char *zPrefixOpt;
12881282
Stmt s;
12891283
int privateFlag;
12901284
--- src/rebuild.c
+++ src/rebuild.c
@@ -601,12 +601,10 @@
601 ** --quiet Only show output if there are errors
602 ** --randomize Scan artifacts in a random order
603 ** --stats Show artifact statistics after rebuilding
604 ** --vacuum Run VACUUM on the database after rebuilding
605 ** --wal Set Write-Ahead-Log journalling mode on the database
606 **
607 ** See also: deconstruct, reconstruct
608 */
609 void rebuild_database(void){
610 int forceFlag;
611 int randomizeFlag;
612 int errCnt = 0;
@@ -1203,12 +1201,10 @@
1203 ** Options:
1204 ** -K|--keep-rid1 Read the filename of the artifact with RID=1 from the
1205 ** file .rid in DIRECTORY.
1206 ** -P|--keep-private Mark the artifacts listed in the file .private in
1207 ** DIRECTORY as private in the new Fossil repository.
1208 **
1209 ** See also: deconstruct, rebuild
1210 */
1211 void reconstruct_cmd(void) {
1212 char *zPassword;
1213 int fKeepPrivate;
1214 fKeepRid1 = find_option("keep-rid1","K",0)!=0;
@@ -1278,12 +1274,10 @@
1278 ** subdirectories to N.
1279 ** --private Include private artifacts.
1280 ** -P|--keep-private Save the list of private artifacts to the file
1281 ** .private in the DESTINATION directory (implies
1282 ** the --private option).
1283 **
1284 ** See also: reconstruct, rebuild
1285 */
1286 void deconstruct_cmd(void){
1287 const char *zPrefixOpt;
1288 Stmt s;
1289 int privateFlag;
1290
--- src/rebuild.c
+++ src/rebuild.c
@@ -601,12 +601,10 @@
601 ** --quiet Only show output if there are errors
602 ** --randomize Scan artifacts in a random order
603 ** --stats Show artifact statistics after rebuilding
604 ** --vacuum Run VACUUM on the database after rebuilding
605 ** --wal Set Write-Ahead-Log journalling mode on the database
 
 
606 */
607 void rebuild_database(void){
608 int forceFlag;
609 int randomizeFlag;
610 int errCnt = 0;
@@ -1203,12 +1201,10 @@
1201 ** Options:
1202 ** -K|--keep-rid1 Read the filename of the artifact with RID=1 from the
1203 ** file .rid in DIRECTORY.
1204 ** -P|--keep-private Mark the artifacts listed in the file .private in
1205 ** DIRECTORY as private in the new Fossil repository.
 
 
1206 */
1207 void reconstruct_cmd(void) {
1208 char *zPassword;
1209 int fKeepPrivate;
1210 fKeepRid1 = find_option("keep-rid1","K",0)!=0;
@@ -1278,12 +1274,10 @@
1274 ** subdirectories to N.
1275 ** --private Include private artifacts.
1276 ** -P|--keep-private Save the list of private artifacts to the file
1277 ** .private in the DESTINATION directory (implies
1278 ** the --private option).
 
 
1279 */
1280 void deconstruct_cmd(void){
1281 const char *zPrefixOpt;
1282 Stmt s;
1283 int privateFlag;
1284
--- src/rebuild.c
+++ src/rebuild.c
@@ -601,12 +601,10 @@
601601
** --quiet Only show output if there are errors
602602
** --randomize Scan artifacts in a random order
603603
** --stats Show artifact statistics after rebuilding
604604
** --vacuum Run VACUUM on the database after rebuilding
605605
** --wal Set Write-Ahead-Log journalling mode on the database
606
-**
607
-** See also: deconstruct, reconstruct
608606
*/
609607
void rebuild_database(void){
610608
int forceFlag;
611609
int randomizeFlag;
612610
int errCnt = 0;
@@ -1203,12 +1201,10 @@
12031201
** Options:
12041202
** -K|--keep-rid1 Read the filename of the artifact with RID=1 from the
12051203
** file .rid in DIRECTORY.
12061204
** -P|--keep-private Mark the artifacts listed in the file .private in
12071205
** DIRECTORY as private in the new Fossil repository.
1208
-**
1209
-** See also: deconstruct, rebuild
12101206
*/
12111207
void reconstruct_cmd(void) {
12121208
char *zPassword;
12131209
int fKeepPrivate;
12141210
fKeepRid1 = find_option("keep-rid1","K",0)!=0;
@@ -1278,12 +1274,10 @@
12781274
** subdirectories to N.
12791275
** --private Include private artifacts.
12801276
** -P|--keep-private Save the list of private artifacts to the file
12811277
** .private in the DESTINATION directory (implies
12821278
** the --private option).
1283
-**
1284
-** See also: reconstruct, rebuild
12851279
*/
12861280
void deconstruct_cmd(void){
12871281
const char *zPrefixOpt;
12881282
Stmt s;
12891283
int privateFlag;
12901284
--- src/rebuild.c
+++ src/rebuild.c
@@ -601,12 +601,10 @@
601 ** --quiet Only show output if there are errors
602 ** --randomize Scan artifacts in a random order
603 ** --stats Show artifact statistics after rebuilding
604 ** --vacuum Run VACUUM on the database after rebuilding
605 ** --wal Set Write-Ahead-Log journalling mode on the database
606 **
607 ** See also: deconstruct, reconstruct
608 */
609 void rebuild_database(void){
610 int forceFlag;
611 int randomizeFlag;
612 int errCnt = 0;
@@ -1203,12 +1201,10 @@
1203 ** Options:
1204 ** -K|--keep-rid1 Read the filename of the artifact with RID=1 from the
1205 ** file .rid in DIRECTORY.
1206 ** -P|--keep-private Mark the artifacts listed in the file .private in
1207 ** DIRECTORY as private in the new Fossil repository.
1208 **
1209 ** See also: deconstruct, rebuild
1210 */
1211 void reconstruct_cmd(void) {
1212 char *zPassword;
1213 int fKeepPrivate;
1214 fKeepRid1 = find_option("keep-rid1","K",0)!=0;
@@ -1278,12 +1274,10 @@
1278 ** subdirectories to N.
1279 ** --private Include private artifacts.
1280 ** -P|--keep-private Save the list of private artifacts to the file
1281 ** .private in the DESTINATION directory (implies
1282 ** the --private option).
1283 **
1284 ** See also: reconstruct, rebuild
1285 */
1286 void deconstruct_cmd(void){
1287 const char *zPrefixOpt;
1288 Stmt s;
1289 int privateFlag;
1290
--- src/rebuild.c
+++ src/rebuild.c
@@ -601,12 +601,10 @@
601 ** --quiet Only show output if there are errors
602 ** --randomize Scan artifacts in a random order
603 ** --stats Show artifact statistics after rebuilding
604 ** --vacuum Run VACUUM on the database after rebuilding
605 ** --wal Set Write-Ahead-Log journalling mode on the database
 
 
606 */
607 void rebuild_database(void){
608 int forceFlag;
609 int randomizeFlag;
610 int errCnt = 0;
@@ -1203,12 +1201,10 @@
1201 ** Options:
1202 ** -K|--keep-rid1 Read the filename of the artifact with RID=1 from the
1203 ** file .rid in DIRECTORY.
1204 ** -P|--keep-private Mark the artifacts listed in the file .private in
1205 ** DIRECTORY as private in the new Fossil repository.
 
 
1206 */
1207 void reconstruct_cmd(void) {
1208 char *zPassword;
1209 int fKeepPrivate;
1210 fKeepRid1 = find_option("keep-rid1","K",0)!=0;
@@ -1278,12 +1274,10 @@
1274 ** subdirectories to N.
1275 ** --private Include private artifacts.
1276 ** -P|--keep-private Save the list of private artifacts to the file
1277 ** .private in the DESTINATION directory (implies
1278 ** the --private option).
 
 
1279 */
1280 void deconstruct_cmd(void){
1281 const char *zPrefixOpt;
1282 Stmt s;
1283 int privateFlag;
1284
+9 -1
--- src/sbsdiff.js
+++ src/sbsdiff.js
@@ -22,12 +22,20 @@
2222
if( !len ) return;
2323
txtCols[0].scrollLeft += len;
2424
return false;
2525
};
2626
}
27
- document.querySelectorAll('.sbsdiffcols').forEach(initSbsDiff);
27
+ var i, diffs = document.querySelectorAll('.sbsdiffcols')
28
+ /* Maintenance reminder: using forEach() here breaks
29
+ MSIE<=11, and we need to keep those browsers working on
30
+ the /info page. */;
31
+ for(i=0; i<diffs.length; i++){
32
+ initSbsDiff(diffs[i]);
33
+ }
2834
if(window.fossil && fossil.page){
35
+ /* Here we can use forEach() because the pages which use
36
+ fossil.pages only work in HTML5-compliant browsers. */
2937
fossil.page.tweakSbsDiffs = function(){
3038
document.querySelectorAll('.sbsdiffcols').forEach(initSbsDiff);
3139
};
3240
}
3341
})();
3442
--- src/sbsdiff.js
+++ src/sbsdiff.js
@@ -22,12 +22,20 @@
22 if( !len ) return;
23 txtCols[0].scrollLeft += len;
24 return false;
25 };
26 }
27 document.querySelectorAll('.sbsdiffcols').forEach(initSbsDiff);
 
 
 
 
 
 
28 if(window.fossil && fossil.page){
 
 
29 fossil.page.tweakSbsDiffs = function(){
30 document.querySelectorAll('.sbsdiffcols').forEach(initSbsDiff);
31 };
32 }
33 })();
34
--- src/sbsdiff.js
+++ src/sbsdiff.js
@@ -22,12 +22,20 @@
22 if( !len ) return;
23 txtCols[0].scrollLeft += len;
24 return false;
25 };
26 }
27 var i, diffs = document.querySelectorAll('.sbsdiffcols')
28 /* Maintenance reminder: using forEach() here breaks
29 MSIE<=11, and we need to keep those browsers working on
30 the /info page. */;
31 for(i=0; i<diffs.length; i++){
32 initSbsDiff(diffs[i]);
33 }
34 if(window.fossil && fossil.page){
35 /* Here we can use forEach() because the pages which use
36 fossil.pages only work in HTML5-compliant browsers. */
37 fossil.page.tweakSbsDiffs = function(){
38 document.querySelectorAll('.sbsdiffcols').forEach(initSbsDiff);
39 };
40 }
41 })();
42
+1 -1
--- src/scroll.js
+++ src/scroll.js
@@ -1,2 +1,2 @@
11
/* Cause the page to scroll so that the #scrollToMe is visible */
2
-document.getElementById('scrollToMe').scrollIntoView(true);
2
+(document.getElementById('scrollToMe')||document.body).scrollIntoView(true);
33
--- src/scroll.js
+++ src/scroll.js
@@ -1,2 +1,2 @@
1 /* Cause the page to scroll so that the #scrollToMe is visible */
2 document.getElementById('scrollToMe').scrollIntoView(true);
3
--- src/scroll.js
+++ src/scroll.js
@@ -1,2 +1,2 @@
1 /* Cause the page to scroll so that the #scrollToMe is visible */
2 (document.getElementById('scrollToMe')||document.body).scrollIntoView(true);
3
+58 -12
--- src/setup.c
+++ src/setup.c
@@ -1077,24 +1077,14 @@
10771077
@ in forum posts, make this setting be "<b>btw</b>". The default is an
10781078
@ empty string which means that Fossil never allows Markdown documents
10791079
@ to generate unsafe HTML.
10801080
@ (Property: "safe-html")</p>
10811081
@ <hr />
1082
- @ <hr />
1083
- onoff_attribute("Enable WYSIWYG Wiki Editing",
1084
- "wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
1085
- @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
1086
- @ The WYSIWYG editor generates HTML instead of markup, which makes
1087
- @ subsequent manual editing more difficult.
1088
- @ (Property: "wysiwyg-wiki")</p>
1089
- @ <hr />
10901082
onoff_attribute("Use HTML as wiki markup language",
10911083
"wiki-use-html", "wiki-use-html", 0, 0);
10921084
@ <p>Use HTML as the wiki markup language. Wiki links will still be parsed
1093
- @ but all other wiki formatting will be ignored. This option is helpful
1094
- @ if you have chosen to use a rich HTML editor for wiki markup such as
1095
- @ TinyMCE.</p>
1085
+ @ but all other wiki formatting will be ignored.</p>
10961086
@ <p><strong>CAUTION:</strong> when
10971087
@ enabling, <i>all</i> HTML tags and attributes are accepted in the wiki.
10981088
@ No sanitization is done. This means that it is very possible for malicious
10991089
@ users to inject dangerous HTML, CSS and JavaScript code into your wiki.</p>
11001090
@ <p>This should <strong>only</strong> be enabled when wiki editing is limited
@@ -1235,11 +1225,11 @@
12351225
}
12361226
12371227
/*
12381228
** WEBPAGE: setup_logo
12391229
**
1240
-** Administrative page for changing the logo image.
1230
+** Administrative page for changing the logo, background, and icon images.
12411231
*/
12421232
void setup_logo(void){
12431233
const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
12441234
const char *zLogoMime = db_get("logo-mimetype","image/gif");
12451235
const char *aLogoImg = P("logoim");
@@ -1246,16 +1236,23 @@
12461236
int szLogoImg = atoi(PD("logoim:bytes","0"));
12471237
const char *zBgMtime = db_get_mtime("background-image", 0, 0);
12481238
const char *zBgMime = db_get("background-mimetype","image/gif");
12491239
const char *aBgImg = P("bgim");
12501240
int szBgImg = atoi(PD("bgim:bytes","0"));
1241
+ const char *zIconMtime = db_get_mtime("icon-image", 0, 0);
1242
+ const char *zIconMime = db_get("icon-mimetype","image/gif");
1243
+ const char *aIconImg = P("iconim");
1244
+ int szIconImg = atoi(PD("iconim:bytes","0"));
12511245
if( szLogoImg>0 ){
12521246
zLogoMime = PD("logoim:mimetype","image/gif");
12531247
}
12541248
if( szBgImg>0 ){
12551249
zBgMime = PD("bgim:mimetype","image/gif");
12561250
}
1251
+ if( szIconImg>0 ){
1252
+ zIconMime = PD("iconim:mimetype","image/gif");
1253
+ }
12571254
login_check_credentials();
12581255
if( !g.perm.Admin ){
12591256
login_needed(0);
12601257
return;
12611258
}
@@ -1309,10 +1306,35 @@
13091306
"DELETE FROM config WHERE name IN "
13101307
"('background-image','background-mimetype')"
13111308
);
13121309
db_end_transaction(0);
13131310
cgi_redirect("setup_logo");
1311
+ }else if( P("seticon")!=0 && zIconMime && zIconMime[0] && szIconImg>0 ){
1312
+ Blob img;
1313
+ Stmt ins;
1314
+ blob_init(&img, aIconImg, szIconImg);
1315
+ db_prepare(&ins,
1316
+ "REPLACE INTO config(name,value,mtime)"
1317
+ " VALUES('icon-image',:bytes,now())"
1318
+ );
1319
+ db_bind_blob(&ins, ":bytes", &img);
1320
+ db_step(&ins);
1321
+ db_finalize(&ins);
1322
+ db_multi_exec(
1323
+ "REPLACE INTO config(name,value,mtime)"
1324
+ " VALUES('icon-mimetype',%Q,now())",
1325
+ zIconMime
1326
+ );
1327
+ db_end_transaction(0);
1328
+ cgi_redirect("setup_logo");
1329
+ }else if( P("clricon")!=0 ){
1330
+ db_multi_exec(
1331
+ "DELETE FROM config WHERE name IN "
1332
+ "('icon-image','icon-mimetype')"
1333
+ );
1334
+ db_end_transaction(0);
1335
+ cgi_redirect("setup_logo");
13141336
}
13151337
style_header("Edit Project Logo And Background");
13161338
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
13171339
@ and looks like this:</p>
13181340
@ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" \
@@ -1358,10 +1380,34 @@
13581380
@ <input type="submit" name="setbg" value="Change Background" />
13591381
@ <input type="submit" name="clrbg" value="Revert To Default" /></p>
13601382
@ </div></form>
13611383
@ <p>(Properties: "background-image" and "background-mimetype")
13621384
@ <hr />
1385
+ @
1386
+ @ <p>The current icon image has a MIME-Type of <b>%h(zIconMime)</b>
1387
+ @ and looks like this:</p>
1388
+ @ <blockquote><p><img src="%s(g.zTop)/favicon.ico/%z(zIconMtime)" \
1389
+ @ alt="icon" border=1 />
1390
+ @ </p></blockquote>
1391
+ @
1392
+ @ <form action="%s(g.zTop)/setup_logo" method="post"
1393
+ @ enctype="multipart/form-data"><div>
1394
+ @ <p>The icon image is accessible to all users at this URL:
1395
+ @ <a href="%s(g.zBaseURL)/favicon.ico">%s(g.zBaseURL)/favicon.ico</a>.
1396
+ @ The icon image may or may not appear on each
1397
+ @ page depending on the web browser in use and the MIME-Types that it
1398
+ @ supports for icon images.
1399
+ @ To change the icon image, use the following form:</p>
1400
+ login_insert_csrf_secret();
1401
+ @ Icon image file:
1402
+ @ <input type="file" name="iconim" size="60" accept="image/*" />
1403
+ @ <p align="center">
1404
+ @ <input type="submit" name="seticon" value="Change Icon" />
1405
+ @ <input type="submit" name="clricon" value="Revert To Default" /></p>
1406
+ @ </div></form>
1407
+ @ <p>(Properties: "icon-image" and "icon-mimetype")
1408
+ @ <hr />
13631409
@
13641410
@ <p><span class="note">Note:</span> Your browser has probably cached these
13651411
@ images, so you may need to press the Reload button before changes will
13661412
@ take effect. </p>
13671413
style_footer();
13681414
--- src/setup.c
+++ src/setup.c
@@ -1077,24 +1077,14 @@
1077 @ in forum posts, make this setting be "<b>btw</b>". The default is an
1078 @ empty string which means that Fossil never allows Markdown documents
1079 @ to generate unsafe HTML.
1080 @ (Property: "safe-html")</p>
1081 @ <hr />
1082 @ <hr />
1083 onoff_attribute("Enable WYSIWYG Wiki Editing",
1084 "wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
1085 @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
1086 @ The WYSIWYG editor generates HTML instead of markup, which makes
1087 @ subsequent manual editing more difficult.
1088 @ (Property: "wysiwyg-wiki")</p>
1089 @ <hr />
1090 onoff_attribute("Use HTML as wiki markup language",
1091 "wiki-use-html", "wiki-use-html", 0, 0);
1092 @ <p>Use HTML as the wiki markup language. Wiki links will still be parsed
1093 @ but all other wiki formatting will be ignored. This option is helpful
1094 @ if you have chosen to use a rich HTML editor for wiki markup such as
1095 @ TinyMCE.</p>
1096 @ <p><strong>CAUTION:</strong> when
1097 @ enabling, <i>all</i> HTML tags and attributes are accepted in the wiki.
1098 @ No sanitization is done. This means that it is very possible for malicious
1099 @ users to inject dangerous HTML, CSS and JavaScript code into your wiki.</p>
1100 @ <p>This should <strong>only</strong> be enabled when wiki editing is limited
@@ -1235,11 +1225,11 @@
1235 }
1236
1237 /*
1238 ** WEBPAGE: setup_logo
1239 **
1240 ** Administrative page for changing the logo image.
1241 */
1242 void setup_logo(void){
1243 const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
1244 const char *zLogoMime = db_get("logo-mimetype","image/gif");
1245 const char *aLogoImg = P("logoim");
@@ -1246,16 +1236,23 @@
1246 int szLogoImg = atoi(PD("logoim:bytes","0"));
1247 const char *zBgMtime = db_get_mtime("background-image", 0, 0);
1248 const char *zBgMime = db_get("background-mimetype","image/gif");
1249 const char *aBgImg = P("bgim");
1250 int szBgImg = atoi(PD("bgim:bytes","0"));
 
 
 
 
1251 if( szLogoImg>0 ){
1252 zLogoMime = PD("logoim:mimetype","image/gif");
1253 }
1254 if( szBgImg>0 ){
1255 zBgMime = PD("bgim:mimetype","image/gif");
1256 }
 
 
 
1257 login_check_credentials();
1258 if( !g.perm.Admin ){
1259 login_needed(0);
1260 return;
1261 }
@@ -1309,10 +1306,35 @@
1309 "DELETE FROM config WHERE name IN "
1310 "('background-image','background-mimetype')"
1311 );
1312 db_end_transaction(0);
1313 cgi_redirect("setup_logo");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1314 }
1315 style_header("Edit Project Logo And Background");
1316 @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
1317 @ and looks like this:</p>
1318 @ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" \
@@ -1358,10 +1380,34 @@
1358 @ <input type="submit" name="setbg" value="Change Background" />
1359 @ <input type="submit" name="clrbg" value="Revert To Default" /></p>
1360 @ </div></form>
1361 @ <p>(Properties: "background-image" and "background-mimetype")
1362 @ <hr />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1363 @
1364 @ <p><span class="note">Note:</span> Your browser has probably cached these
1365 @ images, so you may need to press the Reload button before changes will
1366 @ take effect. </p>
1367 style_footer();
1368
--- src/setup.c
+++ src/setup.c
@@ -1077,24 +1077,14 @@
1077 @ in forum posts, make this setting be "<b>btw</b>". The default is an
1078 @ empty string which means that Fossil never allows Markdown documents
1079 @ to generate unsafe HTML.
1080 @ (Property: "safe-html")</p>
1081 @ <hr />
 
 
 
 
 
 
 
 
1082 onoff_attribute("Use HTML as wiki markup language",
1083 "wiki-use-html", "wiki-use-html", 0, 0);
1084 @ <p>Use HTML as the wiki markup language. Wiki links will still be parsed
1085 @ but all other wiki formatting will be ignored.</p>
 
 
1086 @ <p><strong>CAUTION:</strong> when
1087 @ enabling, <i>all</i> HTML tags and attributes are accepted in the wiki.
1088 @ No sanitization is done. This means that it is very possible for malicious
1089 @ users to inject dangerous HTML, CSS and JavaScript code into your wiki.</p>
1090 @ <p>This should <strong>only</strong> be enabled when wiki editing is limited
@@ -1235,11 +1225,11 @@
1225 }
1226
1227 /*
1228 ** WEBPAGE: setup_logo
1229 **
1230 ** Administrative page for changing the logo, background, and icon images.
1231 */
1232 void setup_logo(void){
1233 const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
1234 const char *zLogoMime = db_get("logo-mimetype","image/gif");
1235 const char *aLogoImg = P("logoim");
@@ -1246,16 +1236,23 @@
1236 int szLogoImg = atoi(PD("logoim:bytes","0"));
1237 const char *zBgMtime = db_get_mtime("background-image", 0, 0);
1238 const char *zBgMime = db_get("background-mimetype","image/gif");
1239 const char *aBgImg = P("bgim");
1240 int szBgImg = atoi(PD("bgim:bytes","0"));
1241 const char *zIconMtime = db_get_mtime("icon-image", 0, 0);
1242 const char *zIconMime = db_get("icon-mimetype","image/gif");
1243 const char *aIconImg = P("iconim");
1244 int szIconImg = atoi(PD("iconim:bytes","0"));
1245 if( szLogoImg>0 ){
1246 zLogoMime = PD("logoim:mimetype","image/gif");
1247 }
1248 if( szBgImg>0 ){
1249 zBgMime = PD("bgim:mimetype","image/gif");
1250 }
1251 if( szIconImg>0 ){
1252 zIconMime = PD("iconim:mimetype","image/gif");
1253 }
1254 login_check_credentials();
1255 if( !g.perm.Admin ){
1256 login_needed(0);
1257 return;
1258 }
@@ -1309,10 +1306,35 @@
1306 "DELETE FROM config WHERE name IN "
1307 "('background-image','background-mimetype')"
1308 );
1309 db_end_transaction(0);
1310 cgi_redirect("setup_logo");
1311 }else if( P("seticon")!=0 && zIconMime && zIconMime[0] && szIconImg>0 ){
1312 Blob img;
1313 Stmt ins;
1314 blob_init(&img, aIconImg, szIconImg);
1315 db_prepare(&ins,
1316 "REPLACE INTO config(name,value,mtime)"
1317 " VALUES('icon-image',:bytes,now())"
1318 );
1319 db_bind_blob(&ins, ":bytes", &img);
1320 db_step(&ins);
1321 db_finalize(&ins);
1322 db_multi_exec(
1323 "REPLACE INTO config(name,value,mtime)"
1324 " VALUES('icon-mimetype',%Q,now())",
1325 zIconMime
1326 );
1327 db_end_transaction(0);
1328 cgi_redirect("setup_logo");
1329 }else if( P("clricon")!=0 ){
1330 db_multi_exec(
1331 "DELETE FROM config WHERE name IN "
1332 "('icon-image','icon-mimetype')"
1333 );
1334 db_end_transaction(0);
1335 cgi_redirect("setup_logo");
1336 }
1337 style_header("Edit Project Logo And Background");
1338 @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
1339 @ and looks like this:</p>
1340 @ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" \
@@ -1358,10 +1380,34 @@
1380 @ <input type="submit" name="setbg" value="Change Background" />
1381 @ <input type="submit" name="clrbg" value="Revert To Default" /></p>
1382 @ </div></form>
1383 @ <p>(Properties: "background-image" and "background-mimetype")
1384 @ <hr />
1385 @
1386 @ <p>The current icon image has a MIME-Type of <b>%h(zIconMime)</b>
1387 @ and looks like this:</p>
1388 @ <blockquote><p><img src="%s(g.zTop)/favicon.ico/%z(zIconMtime)" \
1389 @ alt="icon" border=1 />
1390 @ </p></blockquote>
1391 @
1392 @ <form action="%s(g.zTop)/setup_logo" method="post"
1393 @ enctype="multipart/form-data"><div>
1394 @ <p>The icon image is accessible to all users at this URL:
1395 @ <a href="%s(g.zBaseURL)/favicon.ico">%s(g.zBaseURL)/favicon.ico</a>.
1396 @ The icon image may or may not appear on each
1397 @ page depending on the web browser in use and the MIME-Types that it
1398 @ supports for icon images.
1399 @ To change the icon image, use the following form:</p>
1400 login_insert_csrf_secret();
1401 @ Icon image file:
1402 @ <input type="file" name="iconim" size="60" accept="image/*" />
1403 @ <p align="center">
1404 @ <input type="submit" name="seticon" value="Change Icon" />
1405 @ <input type="submit" name="clricon" value="Revert To Default" /></p>
1406 @ </div></form>
1407 @ <p>(Properties: "icon-image" and "icon-mimetype")
1408 @ <hr />
1409 @
1410 @ <p><span class="note">Note:</span> Your browser has probably cached these
1411 @ images, so you may need to press the Reload button before changes will
1412 @ take effect. </p>
1413 style_footer();
1414
+1 -1
--- src/setupuser.c
+++ src/setupuser.c
@@ -702,11 +702,11 @@
702702
@ </tr>
703703
}
704704
@ </table>
705705
@ </div></form>
706706
@ </div>
707
- style_load_one_js_file("useredit.js");
707
+ builtin_request_js("useredit.js");
708708
@ <hr>
709709
@ <h1>Notes On Privileges And Capabilities:</h1>
710710
@ <ul>
711711
if( higherUser ){
712712
@ <li><p class="missingPriv">
713713
--- src/setupuser.c
+++ src/setupuser.c
@@ -702,11 +702,11 @@
702 @ </tr>
703 }
704 @ </table>
705 @ </div></form>
706 @ </div>
707 style_load_one_js_file("useredit.js");
708 @ <hr>
709 @ <h1>Notes On Privileges And Capabilities:</h1>
710 @ <ul>
711 if( higherUser ){
712 @ <li><p class="missingPriv">
713
--- src/setupuser.c
+++ src/setupuser.c
@@ -702,11 +702,11 @@
702 @ </tr>
703 }
704 @ </table>
705 @ </div></form>
706 @ </div>
707 builtin_request_js("useredit.js");
708 @ <hr>
709 @ <h1>Notes On Privileges And Capabilities:</h1>
710 @ <ul>
711 if( higherUser ){
712 @ <li><p class="missingPriv">
713
+2
--- src/sha1.c
+++ src/sha1.c
@@ -507,10 +507,12 @@
507507
**
508508
** -h, --dereference If FILE is a symbolic link, compute the hash
509509
** on the object that the link points to. Normally,
510510
** the hash is over the name of the object that
511511
** the link points to.
512
+**
513
+** See also: [[md5sum]], [[sha3sum]]
512514
*/
513515
void sha1sum_test(void){
514516
int i;
515517
Blob in;
516518
Blob cksum;
517519
--- src/sha1.c
+++ src/sha1.c
@@ -507,10 +507,12 @@
507 **
508 ** -h, --dereference If FILE is a symbolic link, compute the hash
509 ** on the object that the link points to. Normally,
510 ** the hash is over the name of the object that
511 ** the link points to.
 
 
512 */
513 void sha1sum_test(void){
514 int i;
515 Blob in;
516 Blob cksum;
517
--- src/sha1.c
+++ src/sha1.c
@@ -507,10 +507,12 @@
507 **
508 ** -h, --dereference If FILE is a symbolic link, compute the hash
509 ** on the object that the link points to. Normally,
510 ** the hash is over the name of the object that
511 ** the link points to.
512 **
513 ** See also: [[md5sum]], [[sha3sum]]
514 */
515 void sha1sum_test(void){
516 int i;
517 Blob in;
518 Blob cksum;
519
+2
--- src/sha3.c
+++ src/sha3.c
@@ -637,10 +637,12 @@
637637
** --512 Compute a SHA3-512 hash
638638
** --size N An N-bit hash. N must be a multiple of 32 between
639639
** 128 and 512.
640640
** -h, --dereference If FILE is a symbolic link, compute the hash on
641641
** the object pointed to, not on the link itself.
642
+**
643
+** See also: [[md5sum]], [[sha1sum]]
642644
*/
643645
void sha3sum_test(void){
644646
int i;
645647
Blob in;
646648
Blob cksum;
647649
--- src/sha3.c
+++ src/sha3.c
@@ -637,10 +637,12 @@
637 ** --512 Compute a SHA3-512 hash
638 ** --size N An N-bit hash. N must be a multiple of 32 between
639 ** 128 and 512.
640 ** -h, --dereference If FILE is a symbolic link, compute the hash on
641 ** the object pointed to, not on the link itself.
 
 
642 */
643 void sha3sum_test(void){
644 int i;
645 Blob in;
646 Blob cksum;
647
--- src/sha3.c
+++ src/sha3.c
@@ -637,10 +637,12 @@
637 ** --512 Compute a SHA3-512 hash
638 ** --size N An N-bit hash. N must be a multiple of 32 between
639 ** 128 and 512.
640 ** -h, --dereference If FILE is a symbolic link, compute the hash on
641 ** the object pointed to, not on the link itself.
642 **
643 ** See also: [[md5sum]], [[sha1sum]]
644 */
645 void sha3sum_test(void){
646 int i;
647 Blob in;
648 Blob cksum;
649
+54 -22
--- src/shell.c
+++ src/shell.c
@@ -639,10 +639,25 @@
639639
if( (0xc0&*(z++))!=0x80 ) n++;
640640
}
641641
return n;
642642
}
643643
644
+/*
645
+** Return true if zFile does not exist or if it is not an ordinary file.
646
+*/
647
+#ifdef _WIN32
648
+# define notNormalFile(X) 0
649
+#else
650
+static int notNormalFile(const char *zFile){
651
+ struct stat x;
652
+ int rc;
653
+ memset(&x, 0, sizeof(x));
654
+ rc = stat(zFile, &x);
655
+ return rc || !S_ISREG(x.st_mode);
656
+}
657
+#endif
658
+
644659
/*
645660
** This routine reads a line of text from FILE in, stores
646661
** the text in memory obtained from malloc() and returns a pointer
647662
** to the text. NULL is returned at end of file, or if malloc()
648663
** fails.
@@ -4045,11 +4060,11 @@
40454060
return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
40464061
}
40474062
p = (ApndFile*)pFile;
40484063
memset(p, 0, sizeof(*p));
40494064
pSubFile = ORIGFILE(pFile);
4050
- p->base.pMethods = &apnd_io_methods;
4065
+ pFile->pMethods = &apnd_io_methods;
40514066
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
40524067
if( rc ) goto apnd_open_done;
40534068
rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
40544069
if( rc ){
40554070
pSubFile->pMethods->xClose(pSubFile);
@@ -4979,11 +4994,10 @@
49794994
sqlite3 *db,
49804995
char **pzErrMsg,
49814996
const sqlite3_api_routines *pApi
49824997
){
49834998
int rc = SQLITE_OK;
4984
- SQLITE_EXTENSION_INIT2(pApi);
49854999
static const struct {
49865000
const char *zFuncName;
49875001
int nArg;
49885002
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
49895003
} aFunc[] = {
@@ -4993,10 +5007,12 @@
49935007
{ "decimal_sub", 2, decimalSubFunc },
49945008
{ "decimal_mul", 2, decimalMulFunc },
49955009
};
49965010
unsigned int i;
49975011
(void)pzErrMsg; /* Unused parameter */
5012
+
5013
+ SQLITE_EXTENSION_INIT2(pApi);
49985014
49995015
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
50005016
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
50015017
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
50025018
0, aFunc[i].xFunc, 0, 0);
@@ -12449,30 +12465,30 @@
1244912465
1245012466
/*
1245112467
** Disable and restore .wheretrace and .selecttrace settings.
1245212468
*/
1245312469
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12454
-extern int sqlite3SelectTrace;
12470
+extern unsigned int sqlite3_unsupported_selecttrace;
1245512471
static int savedSelectTrace;
1245612472
#endif
1245712473
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
1245812474
extern int sqlite3WhereTrace;
1245912475
static int savedWhereTrace;
1246012476
#endif
1246112477
static void disable_debug_trace_modes(void){
1246212478
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12463
- savedSelectTrace = sqlite3SelectTrace;
12464
- sqlite3SelectTrace = 0;
12479
+ savedSelectTrace = sqlite3_unsupported_selecttrace;
12480
+ sqlite3_unsupported_selecttrace = 0;
1246512481
#endif
1246612482
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
1246712483
savedWhereTrace = sqlite3WhereTrace;
1246812484
sqlite3WhereTrace = 0;
1246912485
#endif
1247012486
}
1247112487
static void restore_debug_trace_modes(void){
1247212488
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12473
- sqlite3SelectTrace = savedSelectTrace;
12489
+ sqlite3_unsupported_selecttrace = savedSelectTrace;
1247412490
#endif
1247512491
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
1247612492
sqlite3WhereTrace = savedWhereTrace;
1247712493
#endif
1247812494
}
@@ -12619,29 +12635,42 @@
1261912635
*/
1262012636
static void exec_prepared_stmt_columnar(
1262112637
ShellState *p, /* Pointer to ShellState */
1262212638
sqlite3_stmt *pStmt /* Statment to run */
1262312639
){
12624
- int nRow = 0;
12640
+ sqlite3_int64 nRow = 0;
1262512641
int nColumn = 0;
1262612642
char **azData = 0;
12627
- char *zMsg = 0;
12643
+ sqlite3_int64 nAlloc = 0;
1262812644
const char *z;
1262912645
int rc;
12630
- int i, j, nTotal, w, n;
12646
+ sqlite3_int64 i, nData;
12647
+ int j, nTotal, w, n;
1263112648
const char *colSep = 0;
1263212649
const char *rowSep = 0;
1263312650
12634
- rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt),
12635
- &azData, &nRow, &nColumn, &zMsg);
12636
- if( rc ){
12637
- utf8_printf(p->out, "ERROR: %s\n", zMsg);
12638
- sqlite3_free(zMsg);
12639
- sqlite3_free_table(azData);
12640
- return;
12641
- }
12642
- if( nRow==0 || nColumn==0 ) goto columnar_end;
12651
+ rc = sqlite3_step(pStmt);
12652
+ if( rc!=SQLITE_ROW ) return;
12653
+ nColumn = sqlite3_column_count(pStmt);
12654
+ nAlloc = nColumn*4;
12655
+ azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
12656
+ if( azData==0 ) shell_out_of_memory();
12657
+ for(i=0; i<nColumn; i++){
12658
+ azData[i] = strdup(sqlite3_column_name(pStmt,i));
12659
+ }
12660
+ do{
12661
+ if( (nRow+2)*nColumn >= nAlloc ){
12662
+ nAlloc *= 2;
12663
+ azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
12664
+ if( azData==0 ) shell_out_of_memory();
12665
+ }
12666
+ nRow++;
12667
+ for(i=0; i<nColumn; i++){
12668
+ z = (const char*)sqlite3_column_text(pStmt,i);
12669
+ azData[nRow*nColumn + i] = z ? strdup(z) : 0;
12670
+ }
12671
+ }while( (rc = sqlite3_step(pStmt))==SQLITE_ROW );
1264312672
if( nColumn>p->nWidth ){
1264412673
p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
1264512674
if( p->colWidth==0 ) shell_out_of_memory();
1264612675
for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
1264712676
p->nWidth = nColumn;
@@ -12747,11 +12776,13 @@
1274712776
}
1274812777
columnar_end:
1274912778
if( seenInterrupt ){
1275012779
utf8_printf(p->out, "Interrupt\n");
1275112780
}
12752
- sqlite3_free_table(azData);
12781
+ nData = (nRow+1)*nColumn;
12782
+ for(i=0; i<nData; i++) free(azData[i]);
12783
+ sqlite3_free(azData);
1275312784
}
1275412785
1275512786
/*
1275612787
** Run a prepared statement
1275712788
*/
@@ -18515,12 +18546,13 @@
1851518546
if( nArg!=2 ){
1851618547
raw_printf(stderr, "Usage: .read FILE\n");
1851718548
rc = 1;
1851818549
goto meta_command_exit;
1851918550
}
18520
- p->in = fopen(azArg[1], "rb");
18521
- if( p->in==0 ){
18551
+ if( notNormalFile(azArg[1])
18552
+ || (p->in = fopen(azArg[1], "rb"))==0
18553
+ ){
1852218554
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
1852318555
rc = 1;
1852418556
}else{
1852518557
rc = process_input(p);
1852618558
fclose(p->in);
@@ -18722,11 +18754,11 @@
1872218754
}
1872318755
}else
1872418756
1872518757
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
1872618758
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
18727
- sqlite3SelectTrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
18759
+ sqlite3_unsupported_selecttrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
1872818760
}else
1872918761
#endif
1873018762
1873118763
#if defined(SQLITE_ENABLE_SESSION)
1873218764
if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
1873318765
--- src/shell.c
+++ src/shell.c
@@ -639,10 +639,25 @@
639 if( (0xc0&*(z++))!=0x80 ) n++;
640 }
641 return n;
642 }
643
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644 /*
645 ** This routine reads a line of text from FILE in, stores
646 ** the text in memory obtained from malloc() and returns a pointer
647 ** to the text. NULL is returned at end of file, or if malloc()
648 ** fails.
@@ -4045,11 +4060,11 @@
4045 return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
4046 }
4047 p = (ApndFile*)pFile;
4048 memset(p, 0, sizeof(*p));
4049 pSubFile = ORIGFILE(pFile);
4050 p->base.pMethods = &apnd_io_methods;
4051 rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
4052 if( rc ) goto apnd_open_done;
4053 rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
4054 if( rc ){
4055 pSubFile->pMethods->xClose(pSubFile);
@@ -4979,11 +4994,10 @@
4979 sqlite3 *db,
4980 char **pzErrMsg,
4981 const sqlite3_api_routines *pApi
4982 ){
4983 int rc = SQLITE_OK;
4984 SQLITE_EXTENSION_INIT2(pApi);
4985 static const struct {
4986 const char *zFuncName;
4987 int nArg;
4988 void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
4989 } aFunc[] = {
@@ -4993,10 +5007,12 @@
4993 { "decimal_sub", 2, decimalSubFunc },
4994 { "decimal_mul", 2, decimalMulFunc },
4995 };
4996 unsigned int i;
4997 (void)pzErrMsg; /* Unused parameter */
 
 
4998
4999 for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
5000 rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
5001 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
5002 0, aFunc[i].xFunc, 0, 0);
@@ -12449,30 +12465,30 @@
12449
12450 /*
12451 ** Disable and restore .wheretrace and .selecttrace settings.
12452 */
12453 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12454 extern int sqlite3SelectTrace;
12455 static int savedSelectTrace;
12456 #endif
12457 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
12458 extern int sqlite3WhereTrace;
12459 static int savedWhereTrace;
12460 #endif
12461 static void disable_debug_trace_modes(void){
12462 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12463 savedSelectTrace = sqlite3SelectTrace;
12464 sqlite3SelectTrace = 0;
12465 #endif
12466 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
12467 savedWhereTrace = sqlite3WhereTrace;
12468 sqlite3WhereTrace = 0;
12469 #endif
12470 }
12471 static void restore_debug_trace_modes(void){
12472 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12473 sqlite3SelectTrace = savedSelectTrace;
12474 #endif
12475 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
12476 sqlite3WhereTrace = savedWhereTrace;
12477 #endif
12478 }
@@ -12619,29 +12635,42 @@
12619 */
12620 static void exec_prepared_stmt_columnar(
12621 ShellState *p, /* Pointer to ShellState */
12622 sqlite3_stmt *pStmt /* Statment to run */
12623 ){
12624 int nRow = 0;
12625 int nColumn = 0;
12626 char **azData = 0;
12627 char *zMsg = 0;
12628 const char *z;
12629 int rc;
12630 int i, j, nTotal, w, n;
 
12631 const char *colSep = 0;
12632 const char *rowSep = 0;
12633
12634 rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt),
12635 &azData, &nRow, &nColumn, &zMsg);
12636 if( rc ){
12637 utf8_printf(p->out, "ERROR: %s\n", zMsg);
12638 sqlite3_free(zMsg);
12639 sqlite3_free_table(azData);
12640 return;
12641 }
12642 if( nRow==0 || nColumn==0 ) goto columnar_end;
 
 
 
 
 
 
 
 
 
 
 
 
12643 if( nColumn>p->nWidth ){
12644 p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
12645 if( p->colWidth==0 ) shell_out_of_memory();
12646 for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
12647 p->nWidth = nColumn;
@@ -12747,11 +12776,13 @@
12747 }
12748 columnar_end:
12749 if( seenInterrupt ){
12750 utf8_printf(p->out, "Interrupt\n");
12751 }
12752 sqlite3_free_table(azData);
 
 
12753 }
12754
12755 /*
12756 ** Run a prepared statement
12757 */
@@ -18515,12 +18546,13 @@
18515 if( nArg!=2 ){
18516 raw_printf(stderr, "Usage: .read FILE\n");
18517 rc = 1;
18518 goto meta_command_exit;
18519 }
18520 p->in = fopen(azArg[1], "rb");
18521 if( p->in==0 ){
 
18522 utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
18523 rc = 1;
18524 }else{
18525 rc = process_input(p);
18526 fclose(p->in);
@@ -18722,11 +18754,11 @@
18722 }
18723 }else
18724
18725 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
18726 if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
18727 sqlite3SelectTrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
18728 }else
18729 #endif
18730
18731 #if defined(SQLITE_ENABLE_SESSION)
18732 if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
18733
--- src/shell.c
+++ src/shell.c
@@ -639,10 +639,25 @@
639 if( (0xc0&*(z++))!=0x80 ) n++;
640 }
641 return n;
642 }
643
644 /*
645 ** Return true if zFile does not exist or if it is not an ordinary file.
646 */
647 #ifdef _WIN32
648 # define notNormalFile(X) 0
649 #else
650 static int notNormalFile(const char *zFile){
651 struct stat x;
652 int rc;
653 memset(&x, 0, sizeof(x));
654 rc = stat(zFile, &x);
655 return rc || !S_ISREG(x.st_mode);
656 }
657 #endif
658
659 /*
660 ** This routine reads a line of text from FILE in, stores
661 ** the text in memory obtained from malloc() and returns a pointer
662 ** to the text. NULL is returned at end of file, or if malloc()
663 ** fails.
@@ -4045,11 +4060,11 @@
4060 return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
4061 }
4062 p = (ApndFile*)pFile;
4063 memset(p, 0, sizeof(*p));
4064 pSubFile = ORIGFILE(pFile);
4065 pFile->pMethods = &apnd_io_methods;
4066 rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
4067 if( rc ) goto apnd_open_done;
4068 rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
4069 if( rc ){
4070 pSubFile->pMethods->xClose(pSubFile);
@@ -4979,11 +4994,10 @@
4994 sqlite3 *db,
4995 char **pzErrMsg,
4996 const sqlite3_api_routines *pApi
4997 ){
4998 int rc = SQLITE_OK;
 
4999 static const struct {
5000 const char *zFuncName;
5001 int nArg;
5002 void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
5003 } aFunc[] = {
@@ -4993,10 +5007,12 @@
5007 { "decimal_sub", 2, decimalSubFunc },
5008 { "decimal_mul", 2, decimalMulFunc },
5009 };
5010 unsigned int i;
5011 (void)pzErrMsg; /* Unused parameter */
5012
5013 SQLITE_EXTENSION_INIT2(pApi);
5014
5015 for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
5016 rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
5017 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
5018 0, aFunc[i].xFunc, 0, 0);
@@ -12449,30 +12465,30 @@
12465
12466 /*
12467 ** Disable and restore .wheretrace and .selecttrace settings.
12468 */
12469 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12470 extern unsigned int sqlite3_unsupported_selecttrace;
12471 static int savedSelectTrace;
12472 #endif
12473 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
12474 extern int sqlite3WhereTrace;
12475 static int savedWhereTrace;
12476 #endif
12477 static void disable_debug_trace_modes(void){
12478 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12479 savedSelectTrace = sqlite3_unsupported_selecttrace;
12480 sqlite3_unsupported_selecttrace = 0;
12481 #endif
12482 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
12483 savedWhereTrace = sqlite3WhereTrace;
12484 sqlite3WhereTrace = 0;
12485 #endif
12486 }
12487 static void restore_debug_trace_modes(void){
12488 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
12489 sqlite3_unsupported_selecttrace = savedSelectTrace;
12490 #endif
12491 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
12492 sqlite3WhereTrace = savedWhereTrace;
12493 #endif
12494 }
@@ -12619,29 +12635,42 @@
12635 */
12636 static void exec_prepared_stmt_columnar(
12637 ShellState *p, /* Pointer to ShellState */
12638 sqlite3_stmt *pStmt /* Statment to run */
12639 ){
12640 sqlite3_int64 nRow = 0;
12641 int nColumn = 0;
12642 char **azData = 0;
12643 sqlite3_int64 nAlloc = 0;
12644 const char *z;
12645 int rc;
12646 sqlite3_int64 i, nData;
12647 int j, nTotal, w, n;
12648 const char *colSep = 0;
12649 const char *rowSep = 0;
12650
12651 rc = sqlite3_step(pStmt);
12652 if( rc!=SQLITE_ROW ) return;
12653 nColumn = sqlite3_column_count(pStmt);
12654 nAlloc = nColumn*4;
12655 azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
12656 if( azData==0 ) shell_out_of_memory();
12657 for(i=0; i<nColumn; i++){
12658 azData[i] = strdup(sqlite3_column_name(pStmt,i));
12659 }
12660 do{
12661 if( (nRow+2)*nColumn >= nAlloc ){
12662 nAlloc *= 2;
12663 azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
12664 if( azData==0 ) shell_out_of_memory();
12665 }
12666 nRow++;
12667 for(i=0; i<nColumn; i++){
12668 z = (const char*)sqlite3_column_text(pStmt,i);
12669 azData[nRow*nColumn + i] = z ? strdup(z) : 0;
12670 }
12671 }while( (rc = sqlite3_step(pStmt))==SQLITE_ROW );
12672 if( nColumn>p->nWidth ){
12673 p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
12674 if( p->colWidth==0 ) shell_out_of_memory();
12675 for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
12676 p->nWidth = nColumn;
@@ -12747,11 +12776,13 @@
12776 }
12777 columnar_end:
12778 if( seenInterrupt ){
12779 utf8_printf(p->out, "Interrupt\n");
12780 }
12781 nData = (nRow+1)*nColumn;
12782 for(i=0; i<nData; i++) free(azData[i]);
12783 sqlite3_free(azData);
12784 }
12785
12786 /*
12787 ** Run a prepared statement
12788 */
@@ -18515,12 +18546,13 @@
18546 if( nArg!=2 ){
18547 raw_printf(stderr, "Usage: .read FILE\n");
18548 rc = 1;
18549 goto meta_command_exit;
18550 }
18551 if( notNormalFile(azArg[1])
18552 || (p->in = fopen(azArg[1], "rb"))==0
18553 ){
18554 utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
18555 rc = 1;
18556 }else{
18557 rc = process_input(p);
18558 fclose(p->in);
@@ -18722,11 +18754,11 @@
18754 }
18755 }else
18756
18757 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
18758 if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
18759 sqlite3_unsupported_selecttrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
18760 }else
18761 #endif
18762
18763 #if defined(SQLITE_ENABLE_SESSION)
18764 if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
18765
+1 -1
--- src/skins.c
+++ src/skins.c
@@ -1101,8 +1101,8 @@
11011101
@ undo a prior publish.
11021102
}else{
11031103
@ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page
11041104
@ for cleanup and recovery actions.
11051105
}
1106
- style_load_one_js_file("skin.js");
1106
+ builtin_request_js("skin.js");
11071107
style_footer();
11081108
}
11091109
--- src/skins.c
+++ src/skins.c
@@ -1101,8 +1101,8 @@
1101 @ undo a prior publish.
1102 }else{
1103 @ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page
1104 @ for cleanup and recovery actions.
1105 }
1106 style_load_one_js_file("skin.js");
1107 style_footer();
1108 }
1109
--- src/skins.c
+++ src/skins.c
@@ -1101,8 +1101,8 @@
1101 @ undo a prior publish.
1102 }else{
1103 @ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page
1104 @ for cleanup and recovery actions.
1105 }
1106 builtin_request_js("skin.js");
1107 style_footer();
1108 }
1109
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -172,10 +172,11 @@
172172
re_add_sql_func(db);
173173
search_sql_setup(db);
174174
foci_register(db);
175175
deltafunc_init(db);
176176
helptext_vtab_register(db);
177
+ builtin_vtab_register(db);
177178
g.repositoryOpen = 1;
178179
g.db = db;
179180
sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "repository");
180181
db_maybe_set_encryption_key(db, g.zRepositoryName);
181182
if( g.zLocalDbName ){
@@ -291,10 +292,14 @@
291292
** All of the standard sqlite3 command-line shell options should also
292293
** work.
293294
**
294295
** The following SQL extensions are provided with this Fossil-enhanced
295296
** version of the sqlite3 command-line shell:
297
+**
298
+** builtin A virtual table that contains one row for
299
+** each datafile that is built into the Fossil
300
+** binary.
296301
**
297302
** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID)
298303
** found in check-in X (another BLOB.RID value).
299304
**
300305
** compress(X) Compress text X with the same algorithm used
@@ -323,10 +328,14 @@
323328
**
324329
** files_of_checkin(X) A table-valued function that returns info on
325330
** all files contained in check-in X. Example:
326331
**
327332
** SELECT * FROM files_of_checkin('trunk');
333
+**
334
+** helptext A virtual table with one row for each command,
335
+** webpage, and setting together with the built-in
336
+** help text.
328337
**
329338
** now() Return the number of seconds since 1970.
330339
**
331340
** obscure(T) Obfuscate the text password T so that its
332341
** original value is not readily visible. Fossil
333342
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -172,10 +172,11 @@
172 re_add_sql_func(db);
173 search_sql_setup(db);
174 foci_register(db);
175 deltafunc_init(db);
176 helptext_vtab_register(db);
 
177 g.repositoryOpen = 1;
178 g.db = db;
179 sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "repository");
180 db_maybe_set_encryption_key(db, g.zRepositoryName);
181 if( g.zLocalDbName ){
@@ -291,10 +292,14 @@
291 ** All of the standard sqlite3 command-line shell options should also
292 ** work.
293 **
294 ** The following SQL extensions are provided with this Fossil-enhanced
295 ** version of the sqlite3 command-line shell:
 
 
 
 
296 **
297 ** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID)
298 ** found in check-in X (another BLOB.RID value).
299 **
300 ** compress(X) Compress text X with the same algorithm used
@@ -323,10 +328,14 @@
323 **
324 ** files_of_checkin(X) A table-valued function that returns info on
325 ** all files contained in check-in X. Example:
326 **
327 ** SELECT * FROM files_of_checkin('trunk');
 
 
 
 
328 **
329 ** now() Return the number of seconds since 1970.
330 **
331 ** obscure(T) Obfuscate the text password T so that its
332 ** original value is not readily visible. Fossil
333
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -172,10 +172,11 @@
172 re_add_sql_func(db);
173 search_sql_setup(db);
174 foci_register(db);
175 deltafunc_init(db);
176 helptext_vtab_register(db);
177 builtin_vtab_register(db);
178 g.repositoryOpen = 1;
179 g.db = db;
180 sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "repository");
181 db_maybe_set_encryption_key(db, g.zRepositoryName);
182 if( g.zLocalDbName ){
@@ -291,10 +292,14 @@
292 ** All of the standard sqlite3 command-line shell options should also
293 ** work.
294 **
295 ** The following SQL extensions are provided with this Fossil-enhanced
296 ** version of the sqlite3 command-line shell:
297 **
298 ** builtin A virtual table that contains one row for
299 ** each datafile that is built into the Fossil
300 ** binary.
301 **
302 ** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID)
303 ** found in check-in X (another BLOB.RID value).
304 **
305 ** compress(X) Compress text X with the same algorithm used
@@ -323,10 +328,14 @@
328 **
329 ** files_of_checkin(X) A table-valued function that returns info on
330 ** all files contained in check-in X. Example:
331 **
332 ** SELECT * FROM files_of_checkin('trunk');
333 **
334 ** helptext A virtual table with one row for each command,
335 ** webpage, and setting together with the built-in
336 ** help text.
337 **
338 ** now() Return the number of seconds since 1970.
339 **
340 ** obscure(T) Obfuscate the text password T so that its
341 ** original value is not readily visible. Fossil
342
+772 -531
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -997,10 +997,19 @@
997997
998998
#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
999999
# define _BSD_SOURCE
10001000
#endif
10011001
1002
+/*
1003
+** Macro to disable warnings about missing "break" at the end of a "case".
1004
+*/
1005
+#if GCC_VERSION>=7000000
1006
+# define deliberate_fall_through __attribute__((fallthrough));
1007
+#else
1008
+# define deliberate_fall_through
1009
+#endif
1010
+
10021011
/*
10031012
** For MinGW, check to see if we can include the header file containing its
10041013
** version information, among other things. Normally, this internal MinGW
10051014
** header file would [only] be included automatically by other MinGW header
10061015
** files; however, the contained version information is now required by this
@@ -1162,11 +1171,11 @@
11621171
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
11631172
** [sqlite_version()] and [sqlite_source_id()].
11641173
*/
11651174
#define SQLITE_VERSION "3.33.0"
11661175
#define SQLITE_VERSION_NUMBER 3033000
1167
-#define SQLITE_SOURCE_ID "2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829b9c3"
1176
+#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f"
11681177
11691178
/*
11701179
** CAPI3REF: Run-Time Library Version Numbers
11711180
** KEYWORDS: sqlite3_version sqlite3_sourceid
11721181
**
@@ -14532,11 +14541,11 @@
1453214541
# define SELECTTRACE_ENABLED 0
1453314542
#endif
1453414543
#if defined(SQLITE_ENABLE_SELECTTRACE)
1453514544
# define SELECTTRACE_ENABLED 1
1453614545
# define SELECTTRACE(K,P,S,X) \
14537
- if(sqlite3SelectTrace&(K)) \
14546
+ if(sqlite3_unsupported_selecttrace&(K)) \
1453814547
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
1453914548
sqlite3DebugPrintf X
1454014549
#else
1454114550
# define SELECTTRACE(K,P,S,X)
1454214551
# define SELECTTRACE_ENABLED 0
@@ -14595,11 +14604,11 @@
1459514604
** one parameter that destructors normally want. So we have to introduce
1459614605
** this magic value that the code knows to handle differently. Any
1459714606
** pointer will work here as long as it is distinct from SQLITE_STATIC
1459814607
** and SQLITE_TRANSIENT.
1459914608
*/
14600
-#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
14609
+#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault)
1460114610
1460214611
/*
1460314612
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
1460414613
** not support Writable Static Data (WSD) such as global and static variables.
1460514614
** All variables must either be on the stack or dynamically allocated from
@@ -14735,10 +14744,257 @@
1473514744
/*
1473614745
** Defer sourcing vdbe.h and btree.h until after the "u8" and
1473714746
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
1473814747
** pointer types (i.e. FuncDef) defined above.
1473914748
*/
14749
+/************** Include pager.h in the middle of sqliteInt.h *****************/
14750
+/************** Begin file pager.h *******************************************/
14751
+/*
14752
+** 2001 September 15
14753
+**
14754
+** The author disclaims copyright to this source code. In place of
14755
+** a legal notice, here is a blessing:
14756
+**
14757
+** May you do good and not evil.
14758
+** May you find forgiveness for yourself and forgive others.
14759
+** May you share freely, never taking more than you give.
14760
+**
14761
+*************************************************************************
14762
+** This header file defines the interface that the sqlite page cache
14763
+** subsystem. The page cache subsystem reads and writes a file a page
14764
+** at a time and provides a journal for rollback.
14765
+*/
14766
+
14767
+#ifndef SQLITE_PAGER_H
14768
+#define SQLITE_PAGER_H
14769
+
14770
+/*
14771
+** Default maximum size for persistent journal files. A negative
14772
+** value means no limit. This value may be overridden using the
14773
+** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
14774
+*/
14775
+#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
14776
+ #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
14777
+#endif
14778
+
14779
+/*
14780
+** The type used to represent a page number. The first page in a file
14781
+** is called page 1. 0 is used to represent "not a page".
14782
+*/
14783
+typedef u32 Pgno;
14784
+
14785
+/*
14786
+** Each open file is managed by a separate instance of the "Pager" structure.
14787
+*/
14788
+typedef struct Pager Pager;
14789
+
14790
+/*
14791
+** Handle type for pages.
14792
+*/
14793
+typedef struct PgHdr DbPage;
14794
+
14795
+/*
14796
+** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
14797
+** reserved for working around a windows/posix incompatibility). It is
14798
+** used in the journal to signify that the remainder of the journal file
14799
+** is devoted to storing a super-journal name - there are no more pages to
14800
+** roll back. See comments for function writeSuperJournal() in pager.c
14801
+** for details.
14802
+*/
14803
+#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
14804
+
14805
+/*
14806
+** Allowed values for the flags parameter to sqlite3PagerOpen().
14807
+**
14808
+** NOTE: These values must match the corresponding BTREE_ values in btree.h.
14809
+*/
14810
+#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
14811
+#define PAGER_MEMORY 0x0002 /* In-memory database */
14812
+
14813
+/*
14814
+** Valid values for the second argument to sqlite3PagerLockingMode().
14815
+*/
14816
+#define PAGER_LOCKINGMODE_QUERY -1
14817
+#define PAGER_LOCKINGMODE_NORMAL 0
14818
+#define PAGER_LOCKINGMODE_EXCLUSIVE 1
14819
+
14820
+/*
14821
+** Numeric constants that encode the journalmode.
14822
+**
14823
+** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
14824
+** are exposed in the API via the "PRAGMA journal_mode" command and
14825
+** therefore cannot be changed without a compatibility break.
14826
+*/
14827
+#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
14828
+#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
14829
+#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
14830
+#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
14831
+#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
14832
+#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
14833
+#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
14834
+
14835
+/*
14836
+** Flags that make up the mask passed to sqlite3PagerGet().
14837
+*/
14838
+#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
14839
+#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
14840
+
14841
+/*
14842
+** Flags for sqlite3PagerSetFlags()
14843
+**
14844
+** Value constraints (enforced via assert()):
14845
+** PAGER_FULLFSYNC == SQLITE_FullFSync
14846
+** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
14847
+** PAGER_CACHE_SPILL == SQLITE_CacheSpill
14848
+*/
14849
+#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
14850
+#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
14851
+#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
14852
+#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
14853
+#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
14854
+#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
14855
+#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
14856
+#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
14857
+#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
14858
+
14859
+/*
14860
+** The remainder of this file contains the declarations of the functions
14861
+** that make up the Pager sub-system API. See source code comments for
14862
+** a detailed description of each routine.
14863
+*/
14864
+
14865
+/* Open and close a Pager connection. */
14866
+SQLITE_PRIVATE int sqlite3PagerOpen(
14867
+ sqlite3_vfs*,
14868
+ Pager **ppPager,
14869
+ const char*,
14870
+ int,
14871
+ int,
14872
+ int,
14873
+ void(*)(DbPage*)
14874
+);
14875
+SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
14876
+SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
14877
+
14878
+/* Functions used to configure a Pager object. */
14879
+SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
14880
+SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
14881
+SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
14882
+SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
14883
+SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
14884
+SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
14885
+SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
14886
+SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
14887
+SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
14888
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
14889
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
14890
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
14891
+SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
14892
+SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
14893
+SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
14894
+
14895
+/* Functions used to obtain and release page references. */
14896
+SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
14897
+SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
14898
+SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
14899
+SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
14900
+SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
14901
+SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
14902
+
14903
+/* Operations on page references. */
14904
+SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
14905
+SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
14906
+SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
14907
+SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
14908
+SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
14909
+SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
14910
+
14911
+/* Functions used to manage pager transactions and savepoints. */
14912
+SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
14913
+SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
14914
+SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
14915
+SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
14916
+SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper);
14917
+SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
14918
+SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
14919
+SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
14920
+SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
14921
+SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
14922
+
14923
+#ifndef SQLITE_OMIT_WAL
14924
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
14925
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
14926
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
14927
+SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
14928
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
14929
+# ifdef SQLITE_ENABLE_SNAPSHOT
14930
+SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
14931
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
14932
+SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
14933
+SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
14934
+SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
14935
+# endif
14936
+#endif
14937
+
14938
+#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
14939
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
14940
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
14941
+#else
14942
+# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
14943
+# define sqlite3PagerWalDb(x,y)
14944
+#endif
14945
+
14946
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
14947
+SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
14948
+#endif
14949
+
14950
+#ifdef SQLITE_ENABLE_ZIPVFS
14951
+SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
14952
+#endif
14953
+
14954
+/* Functions used to query pager state and configuration. */
14955
+SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
14956
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
14957
+#ifdef SQLITE_DEBUG
14958
+SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
14959
+#endif
14960
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
14961
+SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
14962
+SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
14963
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
14964
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
14965
+SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
14966
+SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
14967
+SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
14968
+SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
14969
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
14970
+SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
14971
+
14972
+/* Functions used to truncate the database file. */
14973
+SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
14974
+
14975
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
14976
+
14977
+/* Functions to support testing and debugging. */
14978
+#if !defined(NDEBUG) || defined(SQLITE_TEST)
14979
+SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
14980
+SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
14981
+#endif
14982
+#ifdef SQLITE_TEST
14983
+SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
14984
+SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
14985
+ void disable_simulated_io_errors(void);
14986
+ void enable_simulated_io_errors(void);
14987
+#else
14988
+# define disable_simulated_io_errors()
14989
+# define enable_simulated_io_errors()
14990
+#endif
14991
+
14992
+#endif /* SQLITE_PAGER_H */
14993
+
14994
+/************** End of pager.h ***********************************************/
14995
+/************** Continuing where we left off in sqliteInt.h ******************/
1474014996
/************** Include btree.h in the middle of sqliteInt.h *****************/
1474114997
/************** Begin file btree.h *******************************************/
1474214998
/*
1474314999
** 2001 September 15
1474415000
**
@@ -14810,12 +15066,12 @@
1481015066
SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
1481115067
#endif
1481215068
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
1481315069
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
1481415070
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
14815
-SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
14816
-SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
15071
+SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
15072
+SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree*);
1481715073
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
1481815074
SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*);
1481915075
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
1482015076
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
1482115077
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
@@ -14823,11 +15079,11 @@
1482315079
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
1482415080
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
1482515081
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
1482615082
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
1482715083
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
14828
-SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
15084
+SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
1482915085
SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
1483015086
SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
1483115087
SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
1483215088
SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
1483315089
SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
@@ -14964,11 +15220,11 @@
1496415220
#define BTREE_WRCSR 0x00000004 /* read-write cursor */
1496515221
#define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */
1496615222
1496715223
SQLITE_PRIVATE int sqlite3BtreeCursor(
1496815224
Btree*, /* BTree containing table to open */
14969
- int iTable, /* Index of root page */
15225
+ Pgno iTable, /* Index of root page */
1497015226
int wrFlag, /* 1 for writing. 0 for read-only */
1497115227
struct KeyInfo*, /* First argument to compare function */
1497215228
BtCursor *pCursor /* Space to write cursor structure */
1497315229
);
1497415230
SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
@@ -15055,11 +15311,11 @@
1505515311
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
1505615312
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
1505715313
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
1505815314
SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
1505915315
15060
-SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,int*aRoot,int nRoot,int,int*);
15316
+SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
1506115317
SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
1506215318
SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
1506315319
1506415320
#ifndef SQLITE_OMIT_INCRBLOB
1506515321
SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
@@ -15192,11 +15448,11 @@
1519215448
sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */
1519315449
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
1519415450
Mem *pMem; /* Used when p4type is P4_MEM */
1519515451
VTable *pVtab; /* Used when p4type is P4_VTAB */
1519615452
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
15197
- int *ai; /* Used when p4type is P4_INTARRAY */
15453
+ u32 *ai; /* Used when p4type is P4_INTARRAY */
1519815454
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
1519915455
Table *pTab; /* Used when p4type is P4_TABLE */
1520015456
#ifdef SQLITE_ENABLE_CURSOR_HINTS
1520115457
Expr *pExpr; /* Used when p4type is P4_EXPR */
1520215458
#endif
@@ -15756,257 +16012,10 @@
1575616012
#endif
1575716013
1575816014
#endif /* SQLITE_VDBE_H */
1575916015
1576016016
/************** End of vdbe.h ************************************************/
15761
-/************** Continuing where we left off in sqliteInt.h ******************/
15762
-/************** Include pager.h in the middle of sqliteInt.h *****************/
15763
-/************** Begin file pager.h *******************************************/
15764
-/*
15765
-** 2001 September 15
15766
-**
15767
-** The author disclaims copyright to this source code. In place of
15768
-** a legal notice, here is a blessing:
15769
-**
15770
-** May you do good and not evil.
15771
-** May you find forgiveness for yourself and forgive others.
15772
-** May you share freely, never taking more than you give.
15773
-**
15774
-*************************************************************************
15775
-** This header file defines the interface that the sqlite page cache
15776
-** subsystem. The page cache subsystem reads and writes a file a page
15777
-** at a time and provides a journal for rollback.
15778
-*/
15779
-
15780
-#ifndef SQLITE_PAGER_H
15781
-#define SQLITE_PAGER_H
15782
-
15783
-/*
15784
-** Default maximum size for persistent journal files. A negative
15785
-** value means no limit. This value may be overridden using the
15786
-** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
15787
-*/
15788
-#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
15789
- #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
15790
-#endif
15791
-
15792
-/*
15793
-** The type used to represent a page number. The first page in a file
15794
-** is called page 1. 0 is used to represent "not a page".
15795
-*/
15796
-typedef u32 Pgno;
15797
-
15798
-/*
15799
-** Each open file is managed by a separate instance of the "Pager" structure.
15800
-*/
15801
-typedef struct Pager Pager;
15802
-
15803
-/*
15804
-** Handle type for pages.
15805
-*/
15806
-typedef struct PgHdr DbPage;
15807
-
15808
-/*
15809
-** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
15810
-** reserved for working around a windows/posix incompatibility). It is
15811
-** used in the journal to signify that the remainder of the journal file
15812
-** is devoted to storing a super-journal name - there are no more pages to
15813
-** roll back. See comments for function writeSuperJournal() in pager.c
15814
-** for details.
15815
-*/
15816
-#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
15817
-
15818
-/*
15819
-** Allowed values for the flags parameter to sqlite3PagerOpen().
15820
-**
15821
-** NOTE: These values must match the corresponding BTREE_ values in btree.h.
15822
-*/
15823
-#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
15824
-#define PAGER_MEMORY 0x0002 /* In-memory database */
15825
-
15826
-/*
15827
-** Valid values for the second argument to sqlite3PagerLockingMode().
15828
-*/
15829
-#define PAGER_LOCKINGMODE_QUERY -1
15830
-#define PAGER_LOCKINGMODE_NORMAL 0
15831
-#define PAGER_LOCKINGMODE_EXCLUSIVE 1
15832
-
15833
-/*
15834
-** Numeric constants that encode the journalmode.
15835
-**
15836
-** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
15837
-** are exposed in the API via the "PRAGMA journal_mode" command and
15838
-** therefore cannot be changed without a compatibility break.
15839
-*/
15840
-#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
15841
-#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
15842
-#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
15843
-#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
15844
-#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
15845
-#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
15846
-#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
15847
-
15848
-/*
15849
-** Flags that make up the mask passed to sqlite3PagerGet().
15850
-*/
15851
-#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
15852
-#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
15853
-
15854
-/*
15855
-** Flags for sqlite3PagerSetFlags()
15856
-**
15857
-** Value constraints (enforced via assert()):
15858
-** PAGER_FULLFSYNC == SQLITE_FullFSync
15859
-** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
15860
-** PAGER_CACHE_SPILL == SQLITE_CacheSpill
15861
-*/
15862
-#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
15863
-#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
15864
-#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
15865
-#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
15866
-#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
15867
-#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
15868
-#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
15869
-#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
15870
-#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
15871
-
15872
-/*
15873
-** The remainder of this file contains the declarations of the functions
15874
-** that make up the Pager sub-system API. See source code comments for
15875
-** a detailed description of each routine.
15876
-*/
15877
-
15878
-/* Open and close a Pager connection. */
15879
-SQLITE_PRIVATE int sqlite3PagerOpen(
15880
- sqlite3_vfs*,
15881
- Pager **ppPager,
15882
- const char*,
15883
- int,
15884
- int,
15885
- int,
15886
- void(*)(DbPage*)
15887
-);
15888
-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
15889
-SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
15890
-
15891
-/* Functions used to configure a Pager object. */
15892
-SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
15893
-SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
15894
-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
15895
-SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
15896
-SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
15897
-SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
15898
-SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
15899
-SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
15900
-SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
15901
-SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
15902
-SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
15903
-SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
15904
-SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
15905
-SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
15906
-SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
15907
-
15908
-/* Functions used to obtain and release page references. */
15909
-SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
15910
-SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
15911
-SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
15912
-SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
15913
-SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
15914
-SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
15915
-
15916
-/* Operations on page references. */
15917
-SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
15918
-SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
15919
-SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
15920
-SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
15921
-SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
15922
-SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
15923
-
15924
-/* Functions used to manage pager transactions and savepoints. */
15925
-SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
15926
-SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
15927
-SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
15928
-SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
15929
-SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper);
15930
-SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
15931
-SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
15932
-SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
15933
-SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
15934
-SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
15935
-
15936
-#ifndef SQLITE_OMIT_WAL
15937
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
15938
-SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
15939
-SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
15940
-SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
15941
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
15942
-# ifdef SQLITE_ENABLE_SNAPSHOT
15943
-SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
15944
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
15945
-SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
15946
-SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
15947
-SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
15948
-# endif
15949
-#endif
15950
-
15951
-#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
15952
-SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
15953
-SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
15954
-#else
15955
-# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
15956
-# define sqlite3PagerWalDb(x,y)
15957
-#endif
15958
-
15959
-#ifdef SQLITE_DIRECT_OVERFLOW_READ
15960
-SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
15961
-#endif
15962
-
15963
-#ifdef SQLITE_ENABLE_ZIPVFS
15964
-SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
15965
-#endif
15966
-
15967
-/* Functions used to query pager state and configuration. */
15968
-SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
15969
-SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
15970
-#ifdef SQLITE_DEBUG
15971
-SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
15972
-#endif
15973
-SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
15974
-SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
15975
-SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
15976
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
15977
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
15978
-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
15979
-SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
15980
-SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
15981
-SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
15982
-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
15983
-SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
15984
-
15985
-/* Functions used to truncate the database file. */
15986
-SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
15987
-
15988
-SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
15989
-
15990
-/* Functions to support testing and debugging. */
15991
-#if !defined(NDEBUG) || defined(SQLITE_TEST)
15992
-SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
15993
-SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
15994
-#endif
15995
-#ifdef SQLITE_TEST
15996
-SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
15997
-SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
15998
- void disable_simulated_io_errors(void);
15999
- void enable_simulated_io_errors(void);
16000
-#else
16001
-# define disable_simulated_io_errors()
16002
-# define enable_simulated_io_errors()
16003
-#endif
16004
-
16005
-#endif /* SQLITE_PAGER_H */
16006
-
16007
-/************** End of pager.h ***********************************************/
1600816017
/************** Continuing where we left off in sqliteInt.h ******************/
1600916018
/************** Include pcache.h in the middle of sqliteInt.h ****************/
1601016019
/************** Begin file pcache.h ******************************************/
1601116020
/*
1601216021
** 2008 August 05
@@ -16843,11 +16852,11 @@
1684316852
int nChange; /* Value returned by sqlite3_changes() */
1684416853
int nTotalChange; /* Value returned by sqlite3_total_changes() */
1684516854
int aLimit[SQLITE_N_LIMIT]; /* Limits */
1684616855
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
1684716856
struct sqlite3InitInfo { /* Information used during initialization */
16848
- int newTnum; /* Rootpage of table being initialized */
16857
+ Pgno newTnum; /* Rootpage of table being initialized */
1684916858
u8 iDb; /* Which db file is being initialized */
1685016859
u8 busy; /* TRUE if currently initializing */
1685116860
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
1685216861
unsigned imposterTable : 1; /* Building an imposter table */
1685316862
unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
@@ -16858,11 +16867,14 @@
1685816867
int nVdbeWrite; /* Number of active VDBEs that read and write */
1685916868
int nVdbeExec; /* Number of nested calls to VdbeExec() */
1686016869
int nVDestroy; /* Number of active OP_VDestroy operations */
1686116870
int nExtension; /* Number of loaded extensions */
1686216871
void **aExtension; /* Array of shared library handles */
16863
- int (*xTrace)(u32,void*,void*,void*); /* Trace function */
16872
+ union {
16873
+ void (*xLegacy)(void*,const char*); /* Legacy trace function */
16874
+ int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */
16875
+ } trace;
1686416876
void *pTraceArg; /* Argument to the trace function */
1686516877
#ifndef SQLITE_OMIT_DEPRECATED
1686616878
void (*xProfile)(void*,const char*,u64); /* Profiling function */
1686716879
void *pProfileArg; /* Argument to profile function */
1686816880
#endif
@@ -17482,11 +17494,11 @@
1748217494
Select *pSelect; /* NULL for tables. Points to definition if a view. */
1748317495
FKey *pFKey; /* Linked list of all foreign keys in this table */
1748417496
char *zColAff; /* String defining the affinity of each column */
1748517497
ExprList *pCheck; /* All CHECK constraints */
1748617498
/* ... also used as column name list in a VIEW */
17487
- int tnum; /* Root BTree page for this table */
17499
+ Pgno tnum; /* Root BTree page for this table */
1748817500
u32 nTabRef; /* Number of pointers to this Table */
1748917501
u32 tabFlags; /* Mask of TF_* values */
1749017502
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
1749117503
i16 nCol; /* Number of columns in this table */
1749217504
i16 nNVCol; /* Number of columns that are not VIRTUAL */
@@ -17775,11 +17787,11 @@
1777517787
Schema *pSchema; /* Schema containing this index */
1777617788
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
1777717789
const char **azColl; /* Array of collation sequence names for index */
1777817790
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
1777917791
ExprList *aColExpr; /* Column expressions */
17780
- int tnum; /* DB Page containing root of this index */
17792
+ Pgno tnum; /* DB Page containing root of this index */
1778117793
LogEst szIdxRow; /* Estimated average row size in bytes */
1778217794
u16 nKeyCol; /* Number of columns forming the key */
1778317795
u16 nColumn; /* Number of columns stored in the index */
1778417796
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
1778517797
unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
@@ -17901,15 +17913,10 @@
1790117913
int nFunc; /* Number of entries in aFunc[] */
1790217914
u32 selId; /* Select to which this AggInfo belongs */
1790317915
AggInfo *pNext; /* Next in list of them all */
1790417916
};
1790517917
17906
-/*
17907
-** Value for AggInfo.iAggMagic when the structure is valid
17908
-*/
17909
-#define AggInfoMagic 0x2059e99e
17910
-
1791117918
/*
1791217919
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
1791317920
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
1791417921
** than 32767 we have to make it 32-bit. 16-bit is preferred because
1791517922
** it uses less memory in the Expr object, which is a big memory user
@@ -18744,13 +18751,11 @@
1874418751
1874518752
Token sLastToken; /* The last token parsed */
1874618753
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
1874718754
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
1874818755
u8 explain; /* True if the EXPLAIN flag is found on the query */
18749
-#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
1875018756
u8 eParseMode; /* PARSE_MODE_XXX constant */
18751
-#endif
1875218757
#ifndef SQLITE_OMIT_VIRTUALTABLE
1875318758
int nVtabLock; /* Number of virtual tables to lock */
1875418759
#endif
1875518760
int nHeight; /* Expression tree height of current sub-select */
1875618761
#ifndef SQLITE_OMIT_EXPLAIN
@@ -18990,10 +18995,11 @@
1899018995
char **pzErrMsg; /* Error message stored here */
1899118996
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
1899218997
int rc; /* Result code stored here */
1899318998
u32 mInitFlags; /* Flags controlling error messages */
1899418999
u32 nInitRow; /* Number of rows processed */
19000
+ Pgno mxPage; /* Maximum page number. 0 for no limit. */
1899519001
} InitData;
1899619002
1899719003
/*
1899819004
** Allowed values for mInitFlags
1899919005
*/
@@ -19823,12 +19829,14 @@
1982319829
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
1982419830
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
1982519831
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
1982619832
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
1982719833
SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
19834
+SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*);
1982819835
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
1982919836
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
19837
+SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
1983019838
SQLITE_PRIVATE int sqlite3Atoi(const char*);
1983119839
#ifndef SQLITE_OMIT_UTF16
1983219840
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
1983319841
#endif
1983419842
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
@@ -19944,19 +19952,19 @@
1994419952
SQLITE_PRIVATE const char sqlite3StrBINARY[];
1994519953
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
1994619954
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
1994719955
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
1994819956
SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
19949
-SQLITE_PRIVATE u32 sqlite3SelectTrace;
19957
+SQLITE_API extern u32 sqlite3_unsupported_selecttrace;
1995019958
#ifndef SQLITE_OMIT_WSD
1995119959
SQLITE_PRIVATE int sqlite3PendingByte;
1995219960
#endif
1995319961
#endif /* SQLITE_AMALGAMATION */
1995419962
#ifdef VDBE_PROFILE
1995519963
SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt;
1995619964
#endif
19957
-SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int);
19965
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno);
1995819966
SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
1995919967
SQLITE_PRIVATE void sqlite3AlterFunctions(void);
1996019968
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
1996119969
SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
1996219970
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
@@ -20066,11 +20074,11 @@
2006620074
#else
2006720075
# define sqlite3CloseExtensions(X)
2006820076
#endif
2006920077
2007020078
#ifndef SQLITE_OMIT_SHARED_CACHE
20071
-SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *);
20079
+SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *);
2007220080
#else
2007320081
#define sqlite3TableLock(v,w,x,y,z)
2007420082
#endif
2007520083
2007620084
#ifdef SQLITE_TEST
@@ -20661,11 +20669,11 @@
2066120669
#endif
2066220670
2066320671
/*
2066420672
** Flags for select tracing and the ".selecttrace" macro of the CLI
2066520673
*/
20666
-/**/ u32 sqlite3SelectTrace = 0;
20674
+SQLITE_API u32 sqlite3_unsupported_selecttrace = 0;
2066720675
2066820676
/* #include "opcodes.h" */
2066920677
/*
2067020678
** Properties of opcodes. The OPFLG_INITIALIZER macro is
2067120679
** created by mkopcodeh.awk during compilation. Data is obtained
@@ -20788,11 +20796,11 @@
2078820796
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
2078920797
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
2079020798
Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
2079120799
Btree *pBtx; /* Separate file holding temporary table */
2079220800
i64 seqCount; /* Sequence counter */
20793
- int *aAltMap; /* Mapping from table to index column numbers */
20801
+ u32 *aAltMap; /* Mapping from table to index column numbers */
2079420802
2079520803
/* Cached OP_Column parse information is only valid if cacheStatus matches
2079620804
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
2079720805
** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
2079820806
** the cache is out of date. */
@@ -21184,11 +21192,11 @@
2118421192
*/
2118521193
SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
2118621194
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
2118721195
void sqliteVdbePopStack(Vdbe*,int);
2118821196
SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
21189
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
21197
+SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*);
2119021198
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
2119121199
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
2119221200
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
2119321201
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
2119421202
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
@@ -21660,11 +21668,11 @@
2166021668
** pagers the database handle is connected to. *pHighwater is always set
2166121669
** to zero.
2166221670
*/
2166321671
case SQLITE_DBSTATUS_CACHE_SPILL:
2166421672
op = SQLITE_DBSTATUS_CACHE_WRITE+1;
21665
- /* Fall through into the next case */
21673
+ /* no break */ deliberate_fall_through
2166621674
case SQLITE_DBSTATUS_CACHE_HIT:
2166721675
case SQLITE_DBSTATUS_CACHE_MISS:
2166821676
case SQLITE_DBSTATUS_CACHE_WRITE:{
2166921677
int i;
2167021678
int nRet = 0;
@@ -22816,12 +22824,12 @@
2281622824
break;
2281722825
}
2281822826
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
2281922827
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
2282022828
case 's': {
22821
- sqlite3_snprintf(30,&z[j],"%lld",
22822
- (i64)(x.iJD/1000 - 21086676*(i64)10000));
22829
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
22830
+ sqlite3Int64ToText(iS, &z[j]);
2282322831
j += sqlite3Strlen30(&z[j]);
2282422832
break;
2282522833
}
2282622834
case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
2282722835
case 'w': {
@@ -28537,15 +28545,15 @@
2853728545
assert( precision>=(-1) );
2853828546
switch( xtype ){
2853928547
case etPOINTER:
2854028548
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
2854128549
sizeof(char*)==sizeof(long int) ? 1 : 0;
28542
- /* Fall through into the next case */
28550
+ /* no break */ deliberate_fall_through
2854328551
case etORDINAL:
2854428552
case etRADIX:
2854528553
cThousand = 0;
28546
- /* Fall through into the next case */
28554
+ /* no break */ deliberate_fall_through
2854728555
case etDECIMAL:
2854828556
if( infop->flags & FLAG_SIGNED ){
2854928557
i64 v;
2855028558
if( bArgList ){
2855128559
v = getIntArg(pArgList);
@@ -31770,10 +31778,34 @@
3177031778
#endif /* SQLITE_OMIT_FLOATING_POINT */
3177131779
}
3177231780
#if defined(_MSC_VER)
3177331781
#pragma warning(default : 4756)
3177431782
#endif
31783
+
31784
+/*
31785
+** Render an signed 64-bit integer as text. Store the result in zOut[].
31786
+**
31787
+** The caller must ensure that zOut[] is at least 21 bytes in size.
31788
+*/
31789
+SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){
31790
+ int i;
31791
+ u64 x;
31792
+ char zTemp[22];
31793
+ if( v<0 ){
31794
+ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
31795
+ }else{
31796
+ x = v;
31797
+ }
31798
+ i = sizeof(zTemp)-2;
31799
+ zTemp[sizeof(zTemp)-1] = 0;
31800
+ do{
31801
+ zTemp[i--] = (x%10) + '0';
31802
+ x = x/10;
31803
+ }while( x );
31804
+ if( v<0 ) zTemp[i--] = '-';
31805
+ memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
31806
+}
3177531807
3177631808
/*
3177731809
** Compare the 19-character string zNum against the text representation
3177831810
** value 2^63: 9223372036854775808. Return negative, zero, or positive
3177931811
** if zNum is less than, equal to, or greater than the string.
@@ -32011,13 +32043,31 @@
3201132043
** Return a 32-bit integer value extracted from a string. If the
3201232044
** string is not an integer, just return 0.
3201332045
*/
3201432046
SQLITE_PRIVATE int sqlite3Atoi(const char *z){
3201532047
int x = 0;
32016
- if( z ) sqlite3GetInt32(z, &x);
32048
+ sqlite3GetInt32(z, &x);
3201732049
return x;
3201832050
}
32051
+
32052
+/*
32053
+** Try to convert z into an unsigned 32-bit integer. Return true on
32054
+** success and false if there is an error.
32055
+**
32056
+** Only decimal notation is accepted.
32057
+*/
32058
+SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){
32059
+ u64 v = 0;
32060
+ int i;
32061
+ for(i=0; sqlite3Isdigit(z[i]); i++){
32062
+ v = v*10 + z[i] - '0';
32063
+ if( v>4294967296LL ){ *pI = 0; return 0; }
32064
+ }
32065
+ if( i==0 || z[i]!=0 ){ *pI = 0; return 0; }
32066
+ *pI = (u32)v;
32067
+ return 1;
32068
+}
3201932069
3202032070
/*
3202132071
** The variable-length integer encoding is as follows:
3202232072
**
3202332073
** KEY:
@@ -39188,11 +39238,11 @@
3918839238
}
3918939239
#endif
3919039240
if( rc!=SQLITE_OK ){
3919139241
if( h>=0 ) robust_close(pNew, h, __LINE__);
3919239242
}else{
39193
- pNew->pMethod = pLockingStyle;
39243
+ pId->pMethods = pLockingStyle;
3919439244
OpenCounter(+1);
3919539245
verifyDbFile(pNew);
3919639246
}
3919739247
return rc;
3919839248
}
@@ -46899,11 +46949,11 @@
4689946949
{
4690046950
sqlite3_free(zConverted);
4690146951
}
4690246952
4690346953
sqlite3_free(zTmpname);
46904
- pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
46954
+ id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
4690546955
pFile->pVfs = pVfs;
4690646956
pFile->h = h;
4690746957
if( isReadonly ){
4690846958
pFile->ctrlFlags |= WINFILE_RDONLY;
4690946959
}
@@ -48125,11 +48175,11 @@
4812548175
}
4812648176
memset(p, 0, sizeof(*p));
4812748177
p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
4812848178
assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
4812948179
*pOutFlags = flags | SQLITE_OPEN_MEMORY;
48130
- p->base.pMethods = &memdb_io_methods;
48180
+ pFile->pMethods = &memdb_io_methods;
4813148181
p->szMax = sqlite3GlobalConfig.mxMemdbSize;
4813248182
return SQLITE_OK;
4813348183
}
4813448184
4813548185
#if 0 /* Only used to delete rollback journals, super-journals, and WAL
@@ -52442,15 +52492,10 @@
5244252492
# define USEFETCH(x) ((x)->bUseFetch)
5244352493
#else
5244452494
# define USEFETCH(x) 0
5244552495
#endif
5244652496
52447
-/*
52448
-** The maximum legal page number is (2^31 - 1).
52449
-*/
52450
-#define PAGER_MAX_PGNO 2147483647
52451
-
5245252497
/*
5245352498
** The argument to this macro is a file descriptor (type sqlite3_file*).
5245452499
** Return 0 if it is not open, or non-zero (but not 1) if it is.
5245552500
**
5245652501
** This is so that expressions can be written as:
@@ -54153,16 +54198,17 @@
5415354198
5415454199
/* Allocate space for both the pJournal and pSuper file descriptors.
5415554200
** If successful, open the super-journal file for reading.
5415654201
*/
5415754202
pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
54158
- pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
5415954203
if( !pSuper ){
5416054204
rc = SQLITE_NOMEM_BKPT;
54205
+ pJournal = 0;
5416154206
}else{
5416254207
const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
5416354208
rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
54209
+ pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
5416454210
}
5416554211
if( rc!=SQLITE_OK ) goto delsuper_out;
5416654212
5416754213
/* Load the entire super-journal file into space obtained from
5416854214
** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
@@ -55419,11 +55465,11 @@
5541955465
** Make no changes if mxPage is zero or negative. And never reduce the
5542055466
** maximum page count below the current size of the database.
5542155467
**
5542255468
** Regardless of mxPage, return the current maximum page count.
5542355469
*/
55424
-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
55470
+SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){
5542555471
if( mxPage>0 ){
5542655472
pPager->mxPgno = mxPage;
5542755473
}
5542855474
assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
5542955475
/* assert( pPager->mxPgno>=pPager->dbSize ); */
@@ -57146,22 +57192,22 @@
5714657192
5714757193
noContent = (flags & PAGER_GET_NOCONTENT)!=0;
5714857194
if( pPg->pPager && !noContent ){
5714957195
/* In this case the pcache already contains an initialized copy of
5715057196
** the page. Return without further ado. */
57151
- assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
57197
+ assert( pgno!=PAGER_MJ_PGNO(pPager) );
5715257198
pPager->aStat[PAGER_STAT_HIT]++;
5715357199
return SQLITE_OK;
5715457200
5715557201
}else{
5715657202
/* The pager cache has created a new page. Its content needs to
5715757203
** be initialized. But first some error checks:
5715857204
**
57159
- ** (1) The maximum page number is 2^31
57205
+ ** (*) obsolete. Was: maximum page number is 2^31
5716057206
** (2) Never try to fetch the locking page
5716157207
*/
57162
- if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
57208
+ if( pgno==PAGER_MJ_PGNO(pPager) ){
5716357209
rc = SQLITE_CORRUPT_BKPT;
5716457210
goto pager_acquire_err;
5716557211
}
5716657212
5716757213
pPg->pPager = pPager;
@@ -59863,11 +59909,11 @@
5986359909
** walIteratorFree() - Free an iterator.
5986459910
**
5986559911
** This functionality is used by the checkpoint code (see walCheckpoint()).
5986659912
*/
5986759913
struct WalIterator {
59868
- int iPrior; /* Last result returned from the iterator */
59914
+ u32 iPrior; /* Last result returned from the iterator */
5986959915
int nSegment; /* Number of entries in aSegment[] */
5987059916
struct WalSegment {
5987159917
int iNext; /* Next slot in aIndex[] not yet returned */
5987259918
ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
5987359919
u32 *aPgno; /* Array of page numbers. */
@@ -59945,11 +59991,13 @@
5994559991
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
5994659992
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
5994759993
);
5994859994
assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
5994959995
testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
59950
- if( (rc&0xff)==SQLITE_READONLY ){
59996
+ if( rc==SQLITE_OK ){
59997
+ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;
59998
+ }else if( (rc&0xff)==SQLITE_READONLY ){
5995159999
pWal->readOnly |= WAL_SHM_RDONLY;
5995260000
if( rc==SQLITE_READONLY ){
5995360001
rc = SQLITE_OK;
5995460002
}
5995560003
}
@@ -60320,10 +60368,11 @@
6032060368
&& (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
6032160369
&& (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
6032260370
&& (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
6032360371
&& (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
6032460372
);
60373
+ assert( iHash>=0 );
6032560374
return iHash;
6032660375
}
6032760376
6032860377
/*
6032960378
** Return the page number associated with frame iFrame in this WAL.
@@ -60516,16 +60565,10 @@
6051660565
assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
6051760566
assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
6051860567
assert( pWal->writeLock );
6051960568
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
6052060569
rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
60521
- if( rc==SQLITE_OK ){
60522
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
60523
- if( rc!=SQLITE_OK ){
60524
- walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
60525
- }
60526
- }
6052760570
if( rc ){
6052860571
return rc;
6052960572
}
6053060573
6053160574
WALTRACE(("WAL%p: recovery begin...\n", pWal));
@@ -60537,19 +60580,20 @@
6053760580
goto recovery_error;
6053860581
}
6053960582
6054060583
if( nSize>WAL_HDRSIZE ){
6054160584
u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
60585
+ u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */
6054260586
u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
6054360587
int szFrame; /* Number of bytes in buffer aFrame[] */
6054460588
u8 *aData; /* Pointer to data part of aFrame buffer */
60545
- int iFrame; /* Index of last frame read */
60546
- i64 iOffset; /* Next offset to read from log file */
6054760589
int szPage; /* Page size according to the log */
6054860590
u32 magic; /* Magic value read from WAL header */
6054960591
u32 version; /* Magic value read from WAL header */
6055060592
int isValid; /* True if this frame is valid */
60593
+ u32 iPg; /* Current 32KB wal-index page */
60594
+ u32 iLastFrame; /* Last frame in wal, based on nSize alone */
6055160595
6055260596
/* Read in the WAL header. */
6055360597
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
6055460598
if( rc!=SQLITE_OK ){
6055560599
goto recovery_error;
@@ -60592,42 +60636,86 @@
6059260636
goto finished;
6059360637
}
6059460638
6059560639
/* Malloc a buffer to read frames into. */
6059660640
szFrame = szPage + WAL_FRAME_HDRSIZE;
60597
- aFrame = (u8 *)sqlite3_malloc64(szFrame);
60641
+ aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
6059860642
if( !aFrame ){
6059960643
rc = SQLITE_NOMEM_BKPT;
6060060644
goto recovery_error;
6060160645
}
6060260646
aData = &aFrame[WAL_FRAME_HDRSIZE];
60647
+ aPrivate = (u32*)&aData[szPage];
6060360648
6060460649
/* Read all frames from the log file. */
60605
- iFrame = 0;
60606
- for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
60607
- u32 pgno; /* Database page number for frame */
60608
- u32 nTruncate; /* dbsize field from frame header */
60609
-
60610
- /* Read and decode the next log frame. */
60611
- iFrame++;
60612
- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
60613
- if( rc!=SQLITE_OK ) break;
60614
- isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
60615
- if( !isValid ) break;
60616
- rc = walIndexAppend(pWal, iFrame, pgno);
60617
- if( rc!=SQLITE_OK ) break;
60618
-
60619
- /* If nTruncate is non-zero, this is a commit record. */
60620
- if( nTruncate ){
60621
- pWal->hdr.mxFrame = iFrame;
60622
- pWal->hdr.nPage = nTruncate;
60623
- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
60624
- testcase( szPage<=32768 );
60625
- testcase( szPage>=65536 );
60626
- aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
60627
- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
60628
- }
60650
+ iLastFrame = (nSize - WAL_HDRSIZE) / szFrame;
60651
+ for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){
60652
+ u32 *aShare;
60653
+ u32 iFrame; /* Index of last frame read */
60654
+ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
60655
+ u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE);
60656
+ u32 nHdr, nHdr32;
60657
+ rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
60658
+ if( rc ) break;
60659
+ pWal->apWiData[iPg] = aPrivate;
60660
+
60661
+ for(iFrame=iFirst; iFrame<=iLast; iFrame++){
60662
+ i64 iOffset = walFrameOffset(iFrame, szPage);
60663
+ u32 pgno; /* Database page number for frame */
60664
+ u32 nTruncate; /* dbsize field from frame header */
60665
+
60666
+ /* Read and decode the next log frame. */
60667
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
60668
+ if( rc!=SQLITE_OK ) break;
60669
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
60670
+ if( !isValid ) break;
60671
+ rc = walIndexAppend(pWal, iFrame, pgno);
60672
+ if( NEVER(rc!=SQLITE_OK) ) break;
60673
+
60674
+ /* If nTruncate is non-zero, this is a commit record. */
60675
+ if( nTruncate ){
60676
+ pWal->hdr.mxFrame = iFrame;
60677
+ pWal->hdr.nPage = nTruncate;
60678
+ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
60679
+ testcase( szPage<=32768 );
60680
+ testcase( szPage>=65536 );
60681
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
60682
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
60683
+ }
60684
+ }
60685
+ pWal->apWiData[iPg] = aShare;
60686
+ nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
60687
+ nHdr32 = nHdr / sizeof(u32);
60688
+#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
60689
+ /* Memcpy() should work fine here, on all reasonable implementations.
60690
+ ** Technically, memcpy() might change the destination to some
60691
+ ** intermediate value before setting to the final value, and that might
60692
+ ** cause a concurrent reader to malfunction. Memcpy() is allowed to
60693
+ ** do that, according to the spec, but no memcpy() implementation that
60694
+ ** we know of actually does that, which is why we say that memcpy()
60695
+ ** is safe for this. Memcpy() is certainly a lot faster.
60696
+ */
60697
+ memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr);
60698
+#else
60699
+ /* In the event that some platform is found for which memcpy()
60700
+ ** changes the destination to some intermediate value before
60701
+ ** setting the final value, this alternative copy routine is
60702
+ ** provided.
60703
+ */
60704
+ {
60705
+ int i;
60706
+ for(i=nHdr32; i<WALINDEX_PGSZ/sizeof(u32); i++){
60707
+ if( aShare[i]!=aPrivate[i] ){
60708
+ /* Atomic memory operations are not required here because if
60709
+ ** the value needs to be changed, that means it is not being
60710
+ ** accessed concurrently. */
60711
+ aShare[i] = aPrivate[i];
60712
+ }
60713
+ }
60714
+ }
60715
+#endif
60716
+ if( iFrame<=iLast ) break;
6062960717
}
6063060718
6063160719
sqlite3_free(aFrame);
6063260720
}
6063360721
@@ -60638,19 +60726,30 @@
6063860726
pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
6063960727
pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
6064060728
walIndexWriteHdr(pWal);
6064160729
6064260730
/* Reset the checkpoint-header. This is safe because this thread is
60643
- ** currently holding locks that exclude all other readers, writers and
60644
- ** checkpointers.
60731
+ ** currently holding locks that exclude all other writers and
60732
+ ** checkpointers. Then set the values of read-mark slots 1 through N.
6064560733
*/
6064660734
pInfo = walCkptInfo(pWal);
6064760735
pInfo->nBackfill = 0;
6064860736
pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
6064960737
pInfo->aReadMark[0] = 0;
60650
- for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
60651
- if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
60738
+ for(i=1; i<WAL_NREADER; i++){
60739
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
60740
+ if( rc==SQLITE_OK ){
60741
+ if( i==1 && pWal->hdr.mxFrame ){
60742
+ pInfo->aReadMark[i] = pWal->hdr.mxFrame;
60743
+ }else{
60744
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
60745
+ }
60746
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
60747
+ }else if( rc!=SQLITE_BUSY ){
60748
+ goto recovery_error;
60749
+ }
60750
+ }
6065260751
6065360752
/* If more than one frame was recovered from the log file, report an
6065460753
** event via sqlite3_log(). This is to help with identifying performance
6065560754
** problems caused by applications routinely shutting down without
6065660755
** checkpointing the log file.
@@ -60664,11 +60763,10 @@
6066460763
}
6066560764
6066660765
recovery_error:
6066760766
WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
6066860767
walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
60669
- walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
6067060768
return rc;
6067160769
}
6067260770
6067360771
/*
6067460772
** Close an open wal-index.
@@ -61312,14 +61410,22 @@
6131261410
i64 nReq = ((i64)mxPage * szPage);
6131361411
i64 nSize; /* Current size of database file */
6131461412
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
6131561413
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
6131661414
if( rc==SQLITE_OK && nSize<nReq ){
61317
- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
61415
+ if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)<nReq ){
61416
+ /* If the size of the final database is larger than the current
61417
+ ** database plus the amount of data in the wal file, plus the
61418
+ ** maximum size of the pending-byte page (65536 bytes), then
61419
+ ** must be corruption somewhere. */
61420
+ rc = SQLITE_CORRUPT_BKPT;
61421
+ }else{
61422
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
61423
+ }
6131861424
}
61425
+
6131961426
}
61320
-
6132161427
6132261428
/* Iterate through the contents of the WAL, copying data to the db file */
6132361429
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
6132461430
i64 iOffset;
6132561431
assert( walFramePgno(pWal, iFrame)==iDbpage );
@@ -64048,11 +64154,12 @@
6404864154
Pgno nPage; /* Number of pages in the database */
6404964155
int mxErr; /* Stop accumulating errors when this reaches zero */
6405064156
int nErr; /* Number of messages written to zErrMsg so far */
6405164157
int bOomFault; /* A memory allocation error has occurred */
6405264158
const char *zPfx; /* Error message prefix */
64053
- int v1, v2; /* Values for up to two %d fields in zPfx */
64159
+ Pgno v1; /* Value for first %u substitution in zPfx */
64160
+ int v2; /* Value for second %d substitution in zPfx */
6405464161
StrAccum errMsg; /* Accumulate the error message text here */
6405564162
u32 *heap; /* Min-heap used for analyzing cell coverage */
6405664163
sqlite3 *db; /* Database connection running the check */
6405764164
};
6405864165
@@ -66513,16 +66620,15 @@
6651366620
/*
6651466621
** Return the size of the database file in pages. If there is any kind of
6651566622
** error, return ((unsigned int)-1).
6651666623
*/
6651766624
static Pgno btreePagecount(BtShared *pBt){
66518
- assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
6651966625
return pBt->nPage;
6652066626
}
66521
-SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
66627
+SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){
6652266628
assert( sqlite3BtreeHoldsMutex(p) );
66523
- return btreePagecount(p->pBt) & 0x7fffffff;
66629
+ return btreePagecount(p->pBt);
6652466630
}
6652566631
6652666632
/*
6652766633
** Get a page from the pager and initialize it.
6652866634
**
@@ -67306,12 +67412,12 @@
6730667412
/*
6730767413
** Set the maximum page count for a database if mxPage is positive.
6730867414
** No changes are made if mxPage is 0 or negative.
6730967415
** Regardless of the value of mxPage, return the maximum page count.
6731067416
*/
67311
-SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
67312
- int n;
67417
+SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){
67418
+ Pgno n;
6731367419
sqlite3BtreeEnter(p);
6731467420
n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
6731567421
sqlite3BtreeLeave(p);
6731667422
return n;
6731767423
}
@@ -68746,11 +68852,11 @@
6874668852
** It is assumed that the sqlite3BtreeCursorZero() has been called
6874768853
** on pCur to initialize the memory space prior to invoking this routine.
6874868854
*/
6874968855
static int btreeCursor(
6875068856
Btree *p, /* The btree */
68751
- int iTable, /* Root page of table to open */
68857
+ Pgno iTable, /* Root page of table to open */
6875268858
int wrFlag, /* 1 to write. 0 read-only */
6875368859
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
6875468860
BtCursor *pCur /* Space for new cursor */
6875568861
){
6875668862
BtShared *pBt = p->pBt; /* Shared b-tree handle */
@@ -68789,21 +68895,21 @@
6878968895
}
6879068896
}
6879168897
6879268898
/* Now that no other errors can occur, finish filling in the BtCursor
6879368899
** variables and link the cursor into the BtShared list. */
68794
- pCur->pgnoRoot = (Pgno)iTable;
68900
+ pCur->pgnoRoot = iTable;
6879568901
pCur->iPage = -1;
6879668902
pCur->pKeyInfo = pKeyInfo;
6879768903
pCur->pBtree = p;
6879868904
pCur->pBt = pBt;
6879968905
pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
6880068906
pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
6880168907
/* If there are two or more cursors on the same btree, then all such
6880268908
** cursors *must* have the BTCF_Multiple flag set. */
6880368909
for(pX=pBt->pCursor; pX; pX=pX->pNext){
68804
- if( pX->pgnoRoot==(Pgno)iTable ){
68910
+ if( pX->pgnoRoot==iTable ){
6880568911
pX->curFlags |= BTCF_Multiple;
6880668912
pCur->curFlags |= BTCF_Multiple;
6880768913
}
6880868914
}
6880968915
pCur->pNext = pBt->pCursor;
@@ -68811,11 +68917,11 @@
6881168917
pCur->eState = CURSOR_INVALID;
6881268918
return SQLITE_OK;
6881368919
}
6881468920
static int btreeCursorWithLock(
6881568921
Btree *p, /* The btree */
68816
- int iTable, /* Root page of table to open */
68922
+ Pgno iTable, /* Root page of table to open */
6881768923
int wrFlag, /* 1 to write. 0 read-only */
6881868924
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
6881968925
BtCursor *pCur /* Space for new cursor */
6882068926
){
6882168927
int rc;
@@ -68824,11 +68930,11 @@
6882468930
sqlite3BtreeLeave(p);
6882568931
return rc;
6882668932
}
6882768933
SQLITE_PRIVATE int sqlite3BtreeCursor(
6882868934
Btree *p, /* The btree */
68829
- int iTable, /* Root page of table to open */
68935
+ Pgno iTable, /* Root page of table to open */
6883068936
int wrFlag, /* 1 to write. 0 read-only */
6883168937
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
6883268938
BtCursor *pCur /* Write new cursor here */
6883368939
){
6883468940
if( p->sharable ){
@@ -69249,10 +69355,11 @@
6924969355
}
6925069356
6925169357
assert( rc==SQLITE_OK && amt>0 );
6925269358
while( nextPage ){
6925369359
/* If required, populate the overflow page-list cache. */
69360
+ if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
6925469361
assert( pCur->aOverflow[iIdx]==0
6925569362
|| pCur->aOverflow[iIdx]==nextPage
6925669363
|| CORRUPT_DB );
6925769364
pCur->aOverflow[iIdx] = nextPage;
6925869365
@@ -70664,10 +70771,14 @@
7066470771
*/
7066570772
if( nFree!=0 ){
7066670773
u32 nLeaf; /* Initial number of leaf cells on trunk page */
7066770774
7066870775
iTrunk = get4byte(&pPage1->aData[32]);
70776
+ if( iTrunk>btreePagecount(pBt) ){
70777
+ rc = SQLITE_CORRUPT_BKPT;
70778
+ goto freepage_out;
70779
+ }
7066970780
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
7067070781
if( rc!=SQLITE_OK ){
7067170782
goto freepage_out;
7067270783
}
7067370784
@@ -73468,11 +73579,11 @@
7346873579
** flags might not work:
7346973580
**
7347073581
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
7347173582
** BTREE_ZERODATA Used for SQL indices
7347273583
*/
73473
-static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
73584
+static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
7347473585
BtShared *pBt = p->pBt;
7347573586
MemPage *pRoot;
7347673587
Pgno pgnoRoot;
7347773588
int rc;
7347873589
int ptfFlags; /* Page-type flage for the root page of new table */
@@ -73501,21 +73612,23 @@
7350173612
/* Read the value of meta[3] from the database to determine where the
7350273613
** root page of the new table should go. meta[3] is the largest root-page
7350373614
** created so far, so the new root-page is (meta[3]+1).
7350473615
*/
7350573616
sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
73617
+ if( pgnoRoot>btreePagecount(pBt) ){
73618
+ return SQLITE_CORRUPT_BKPT;
73619
+ }
7350673620
pgnoRoot++;
7350773621
7350873622
/* The new root-page may not be allocated on a pointer-map page, or the
7350973623
** PENDING_BYTE page.
7351073624
*/
7351173625
while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
7351273626
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
7351373627
pgnoRoot++;
7351473628
}
73515
- assert( pgnoRoot>=3 || CORRUPT_DB );
73516
- testcase( pgnoRoot<3 );
73629
+ assert( pgnoRoot>=3 );
7351773630
7351873631
/* Allocate a page. The page that currently resides at pgnoRoot will
7351973632
** be moved to the allocated page (unless the allocated page happens
7352073633
** to reside at pgnoRoot).
7352173634
*/
@@ -73608,14 +73721,14 @@
7360873721
ptfFlags = PTF_ZERODATA | PTF_LEAF;
7360973722
}
7361073723
zeroPage(pRoot, ptfFlags);
7361173724
sqlite3PagerUnref(pRoot->pDbPage);
7361273725
assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
73613
- *piTable = (int)pgnoRoot;
73726
+ *piTable = pgnoRoot;
7361473727
return SQLITE_OK;
7361573728
}
73616
-SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
73729
+SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){
7361773730
int rc;
7361873731
sqlite3BtreeEnter(p);
7361973732
rc = btreeCreateTable(p, piTable, flags);
7362073733
sqlite3BtreeLeave(p);
7362173734
return rc;
@@ -74095,11 +74208,11 @@
7409574208
** Verify that the number of pages on the list is N.
7409674209
*/
7409774210
static void checkList(
7409874211
IntegrityCk *pCheck, /* Integrity checking context */
7409974212
int isFreeList, /* True for a freelist. False for overflow page list */
74100
- int iPage, /* Page number for first page in the list */
74213
+ Pgno iPage, /* Page number for first page in the list */
7410174214
u32 N /* Expected number of pages in the list */
7410274215
){
7410374216
int i;
7410474217
u32 expected = N;
7410574218
int nErrAtStart = pCheck->nErr;
@@ -74227,11 +74340,11 @@
7422774340
** 4. Recursively call checkTreePage on all children.
7422874341
** 5. Verify that the depth of all children is the same.
7422974342
*/
7423074343
static int checkTreePage(
7423174344
IntegrityCk *pCheck, /* Context for the sanity check */
74232
- int iPage, /* Page number of the page to check */
74345
+ Pgno iPage, /* Page number of the page to check */
7423374346
i64 *piMinKey, /* Write minimum integer primary key here */
7423474347
i64 maxKey /* Error if integer primary key greater than this */
7423574348
){
7423674349
MemPage *pPage = 0; /* The page being analyzed */
7423774350
int i; /* Loop counter */
@@ -74263,13 +74376,13 @@
7426374376
*/
7426474377
pBt = pCheck->pBt;
7426574378
usableSize = pBt->usableSize;
7426674379
if( iPage==0 ) return 0;
7426774380
if( checkRef(pCheck, iPage) ) return 0;
74268
- pCheck->zPfx = "Page %d: ";
74381
+ pCheck->zPfx = "Page %u: ";
7426974382
pCheck->v1 = iPage;
74270
- if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
74383
+ if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
7427174384
checkAppendMsg(pCheck,
7427274385
"unable to get the page. error code=%d", rc);
7427374386
goto end_of_check;
7427474387
}
7427574388
@@ -74290,11 +74403,11 @@
7429074403
}
7429174404
data = pPage->aData;
7429274405
hdr = pPage->hdrOffset;
7429374406
7429474407
/* Set up for cell analysis */
74295
- pCheck->zPfx = "On tree page %d cell %d: ";
74408
+ pCheck->zPfx = "On tree page %u cell %d: ";
7429674409
contentOffset = get2byteNotZero(&data[hdr+5]);
7429774410
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
7429874411
7429974412
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
7430074413
** number of cells on the page. */
@@ -74310,11 +74423,11 @@
7431074423
if( !pPage->leaf ){
7431174424
/* Analyze the right-child page of internal pages */
7431274425
pgno = get4byte(&data[hdr+8]);
7431374426
#ifndef SQLITE_OMIT_AUTOVACUUM
7431474427
if( pBt->autoVacuum ){
74315
- pCheck->zPfx = "On page %d at right child: ";
74428
+ pCheck->zPfx = "On page %u at right child: ";
7431674429
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
7431774430
}
7431874431
#endif
7431974432
depth = checkTreePage(pCheck, pgno, &maxKey, maxKey);
7432074433
keyCanBeEqual = 0;
@@ -74451,11 +74564,11 @@
7445174564
nFrag = 0;
7445274565
prev = contentOffset - 1; /* Implied first min-heap entry */
7445374566
while( btreeHeapPull(heap,&x) ){
7445474567
if( (prev&0xffff)>=(x>>16) ){
7445574568
checkAppendMsg(pCheck,
74456
- "Multiple uses for byte %u of page %d", x>>16, iPage);
74569
+ "Multiple uses for byte %u of page %u", x>>16, iPage);
7445774570
break;
7445874571
}else{
7445974572
nFrag += (x>>16) - (prev&0xffff) - 1;
7446074573
prev = x;
7446174574
}
@@ -74466,11 +74579,11 @@
7446674579
** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
7446774580
** number of fragmented free bytes within the cell content area.
7446874581
*/
7446974582
if( heap[0]==0 && nFrag!=data[hdr+7] ){
7447074583
checkAppendMsg(pCheck,
74471
- "Fragmentation of %d bytes reported as %d on page %d",
74584
+ "Fragmentation of %d bytes reported as %d on page %u",
7447274585
nFrag, data[hdr+7], iPage);
7447374586
}
7447474587
}
7447574588
7447674589
end_of_check:
@@ -74494,25 +74607,44 @@
7449474607
**
7449574608
** Write the number of error seen in *pnErr. Except for some memory
7449674609
** allocation errors, an error message held in memory obtained from
7449774610
** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
7449874611
** returned. If a memory allocation error occurs, NULL is returned.
74612
+**
74613
+** If the first entry in aRoot[] is 0, that indicates that the list of
74614
+** root pages is incomplete. This is a "partial integrity-check". This
74615
+** happens when performing an integrity check on a single table. The
74616
+** zero is skipped, of course. But in addition, the freelist checks
74617
+** and the checks to make sure every page is referenced are also skipped,
74618
+** since obviously it is not possible to know which pages are covered by
74619
+** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
74620
+** checks are still performed.
7449974621
*/
7450074622
SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
7450174623
sqlite3 *db, /* Database connection that is running the check */
7450274624
Btree *p, /* The btree to be checked */
74503
- int *aRoot, /* An array of root pages numbers for individual trees */
74625
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
7450474626
int nRoot, /* Number of entries in aRoot[] */
7450574627
int mxErr, /* Stop reporting errors after this many */
7450674628
int *pnErr /* Write number of errors seen to this variable */
7450774629
){
7450874630
Pgno i;
7450974631
IntegrityCk sCheck;
7451074632
BtShared *pBt = p->pBt;
7451174633
u64 savedDbFlags = pBt->db->flags;
7451274634
char zErr[100];
74635
+ int bPartial = 0; /* True if not checking all btrees */
74636
+ int bCkFreelist = 1; /* True to scan the freelist */
7451374637
VVA_ONLY( int nRef );
74638
+ assert( nRoot>0 );
74639
+
74640
+ /* aRoot[0]==0 means this is a partial check */
74641
+ if( aRoot[0]==0 ){
74642
+ assert( nRoot>1 );
74643
+ bPartial = 1;
74644
+ if( aRoot[1]!=1 ) bCkFreelist = 0;
74645
+ }
7451474646
7451574647
sqlite3BtreeEnter(p);
7451674648
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
7451774649
VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
7451874650
assert( nRef>=0 );
@@ -74548,69 +74680,75 @@
7454874680
i = PENDING_BYTE_PAGE(pBt);
7454974681
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
7455074682
7455174683
/* Check the integrity of the freelist
7455274684
*/
74553
- sCheck.zPfx = "Main freelist: ";
74554
- checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
74555
- get4byte(&pBt->pPage1->aData[36]));
74556
- sCheck.zPfx = 0;
74685
+ if( bCkFreelist ){
74686
+ sCheck.zPfx = "Main freelist: ";
74687
+ checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
74688
+ get4byte(&pBt->pPage1->aData[36]));
74689
+ sCheck.zPfx = 0;
74690
+ }
7455774691
7455874692
/* Check all the tables.
7455974693
*/
7456074694
#ifndef SQLITE_OMIT_AUTOVACUUM
74561
- if( pBt->autoVacuum ){
74562
- int mx = 0;
74563
- int mxInHdr;
74564
- for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
74565
- mxInHdr = get4byte(&pBt->pPage1->aData[52]);
74566
- if( mx!=mxInHdr ){
74567
- checkAppendMsg(&sCheck,
74568
- "max rootpage (%d) disagrees with header (%d)",
74569
- mx, mxInHdr
74570
- );
74571
- }
74572
- }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
74573
- checkAppendMsg(&sCheck,
74574
- "incremental_vacuum enabled with a max rootpage of zero"
74575
- );
74695
+ if( !bPartial ){
74696
+ if( pBt->autoVacuum ){
74697
+ Pgno mx = 0;
74698
+ Pgno mxInHdr;
74699
+ for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
74700
+ mxInHdr = get4byte(&pBt->pPage1->aData[52]);
74701
+ if( mx!=mxInHdr ){
74702
+ checkAppendMsg(&sCheck,
74703
+ "max rootpage (%d) disagrees with header (%d)",
74704
+ mx, mxInHdr
74705
+ );
74706
+ }
74707
+ }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
74708
+ checkAppendMsg(&sCheck,
74709
+ "incremental_vacuum enabled with a max rootpage of zero"
74710
+ );
74711
+ }
7457674712
}
7457774713
#endif
7457874714
testcase( pBt->db->flags & SQLITE_CellSizeCk );
7457974715
pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
7458074716
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
7458174717
i64 notUsed;
7458274718
if( aRoot[i]==0 ) continue;
7458374719
#ifndef SQLITE_OMIT_AUTOVACUUM
74584
- if( pBt->autoVacuum && aRoot[i]>1 ){
74720
+ if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
7458574721
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
7458674722
}
7458774723
#endif
7458874724
checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
7458974725
}
7459074726
pBt->db->flags = savedDbFlags;
7459174727
7459274728
/* Make sure every page in the file is referenced
7459374729
*/
74594
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
74730
+ if( !bPartial ){
74731
+ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
7459574732
#ifdef SQLITE_OMIT_AUTOVACUUM
74596
- if( getPageReferenced(&sCheck, i)==0 ){
74597
- checkAppendMsg(&sCheck, "Page %d is never used", i);
74598
- }
74599
-#else
74600
- /* If the database supports auto-vacuum, make sure no tables contain
74601
- ** references to pointer-map pages.
74602
- */
74603
- if( getPageReferenced(&sCheck, i)==0 &&
74604
- (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
74605
- checkAppendMsg(&sCheck, "Page %d is never used", i);
74606
- }
74607
- if( getPageReferenced(&sCheck, i)!=0 &&
74608
- (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
74609
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
74610
- }
74611
-#endif
74733
+ if( getPageReferenced(&sCheck, i)==0 ){
74734
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
74735
+ }
74736
+#else
74737
+ /* If the database supports auto-vacuum, make sure no tables contain
74738
+ ** references to pointer-map pages.
74739
+ */
74740
+ if( getPageReferenced(&sCheck, i)==0 &&
74741
+ (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
74742
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
74743
+ }
74744
+ if( getPageReferenced(&sCheck, i)!=0 &&
74745
+ (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
74746
+ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
74747
+ }
74748
+#endif
74749
+ }
7461274750
}
7461374751
7461474752
/* Clean up and report errors.
7461574753
*/
7461674754
integrity_ck_cleanup:
@@ -75794,20 +75932,29 @@
7579475932
** into a buffer.
7579575933
*/
7579675934
static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
7579775935
StrAccum acc;
7579875936
assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
75799
- sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
75937
+ assert( sz>22 );
7580075938
if( p->flags & MEM_Int ){
75801
- sqlite3_str_appendf(&acc, "%lld", p->u.i);
75802
- }else if( p->flags & MEM_IntReal ){
75803
- sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
75939
+#if GCC_VERSION>=7000000
75940
+ /* Work-around for GCC bug
75941
+ ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
75942
+ i64 x;
75943
+ assert( (p->flags&MEM_Int)*2==sizeof(x) );
75944
+ memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
75945
+ sqlite3Int64ToText(x, zBuf);
75946
+#else
75947
+ sqlite3Int64ToText(p->u.i, zBuf);
75948
+#endif
7580475949
}else{
75805
- sqlite3_str_appendf(&acc, "%!.15g", p->u.r);
75950
+ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
75951
+ sqlite3_str_appendf(&acc, "%!.15g",
75952
+ (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
75953
+ assert( acc.zText==zBuf && acc.mxAlloc<=0 );
75954
+ zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
7580675955
}
75807
- assert( acc.zText==zBuf && acc.mxAlloc<=0 );
75808
- zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
7580975956
}
7581075957
7581175958
#ifdef SQLITE_DEBUG
7581275959
/*
7581375960
** Validity checks on pMem. pMem holds a string.
@@ -78397,11 +78544,11 @@
7839778544
/* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
7839878545
** cases from this switch! */
7839978546
switch( pOp->opcode ){
7840078547
case OP_Transaction: {
7840178548
if( pOp->p2!=0 ) p->readOnly = 0;
78402
- /* fall thru */
78549
+ /* no break */ deliberate_fall_through
7840378550
}
7840478551
case OP_AutoCommit:
7840578552
case OP_Savepoint: {
7840678553
p->bIsReader = 1;
7840778554
break;
@@ -78444,10 +78591,11 @@
7844478591
assert( (pOp - p->aOp) >= 3 );
7844578592
assert( pOp[-1].opcode==OP_Integer );
7844678593
n = pOp[-1].p1;
7844778594
if( n>nMaxArgs ) nMaxArgs = n;
7844878595
/* Fall through into the default case */
78596
+ /* no break */ deliberate_fall_through
7844978597
}
7845078598
#endif
7845178599
default: {
7845278600
if( pOp->p2<0 ){
7845378601
/* The mkopcodeh.tcl script has so arranged things that the only
@@ -79301,16 +79449,16 @@
7930179449
sqlite3_str_appendf(&x, "vtab:%p", pVtab);
7930279450
break;
7930379451
}
7930479452
#endif
7930579453
case P4_INTARRAY: {
79306
- int i;
79307
- int *ai = pOp->p4.ai;
79308
- int n = ai[0]; /* The first element of an INTARRAY is always the
79454
+ u32 i;
79455
+ u32 *ai = pOp->p4.ai;
79456
+ u32 n = ai[0]; /* The first element of an INTARRAY is always the
7930979457
** count of the number of elements to follow */
7931079458
for(i=1; i<=n; i++){
79311
- sqlite3_str_appendf(&x, "%c%d", (i==1 ? '[' : ','), ai[i]);
79459
+ sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]);
7931279460
}
7931379461
sqlite3_str_append(&x, "]", 1);
7931479462
break;
7931579463
}
7931679464
case P4_SUBPROGRAM: {
@@ -81150,15 +81298,15 @@
8115081298
** a NULL row.
8115181299
**
8115281300
** If the cursor is already pointing to the correct row and that row has
8115381301
** not been deleted out from under the cursor, then this routine is a no-op.
8115481302
*/
81155
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
81303
+SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
8115681304
VdbeCursor *p = *pp;
8115781305
assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
8115881306
if( p->deferredMoveto ){
81159
- int iMap;
81307
+ u32 iMap;
8116081308
if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
8116181309
*pp = p->pAltCursor;
8116281310
*piCol = iMap - 1;
8116381311
return SQLITE_OK;
8116481312
}
@@ -82910,11 +83058,11 @@
8291083058
if( db->xProfile ){
8291183059
db->xProfile(db->pProfileArg, p->zSql, iElapse);
8291283060
}
8291383061
#endif
8291483062
if( db->mTrace & SQLITE_TRACE_PROFILE ){
82915
- db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
83063
+ db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
8291683064
}
8291783065
p->startTime = 0;
8291883066
}
8291983067
/*
8292083068
** The checkProfileCallback(DB,P) macro checks to see if a profile callback
@@ -86210,10 +86358,11 @@
8621086358
#ifdef SQLITE_DEBUG
8621186359
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
8621286360
#endif
8621386361
if( (pIn3->flags & MEM_Null)==0 ) break;
8621486362
/* Fall through into OP_Halt */
86363
+ /* no break */ deliberate_fall_through
8621586364
}
8621686365
8621786366
/* Opcode: Halt P1 P2 * P4 P5
8621886367
**
8621986368
** Exit immediately. All open cursors, etc are closed
@@ -86380,10 +86529,11 @@
8638086529
goto too_big;
8638186530
}
8638286531
pOp->opcode = OP_String;
8638386532
assert( rc==SQLITE_OK );
8638486533
/* Fall through to the next case, OP_String */
86534
+ /* no break */ deliberate_fall_through
8638586535
}
8638686536
8638786537
/* Opcode: String P1 P2 P3 P4 P5
8638886538
** Synopsis: r[P2]='P4' (len=P1)
8638986539
**
@@ -86691,11 +86841,11 @@
8669186841
#endif
8669286842
}
8669386843
if( db->mallocFailed ) goto no_mem;
8669486844
8669586845
if( db->mTrace & SQLITE_TRACE_ROW ){
86696
- db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
86846
+ db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
8669786847
}
8669886848
8669986849
8670086850
/* Return SQLITE_ROW
8670186851
*/
@@ -87427,14 +87577,14 @@
8742787577
int n;
8742887578
int i;
8742987579
int p1;
8743087580
int p2;
8743187581
const KeyInfo *pKeyInfo;
87432
- int idx;
87582
+ u32 idx;
8743387583
CollSeq *pColl; /* Collating sequence to use on this term */
8743487584
int bRev; /* True for DESCENDING sort order */
87435
- int *aPermute; /* The permutation */
87585
+ u32 *aPermute; /* The permutation */
8743687586
8743787587
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
8743887588
aPermute = 0;
8743987589
}else{
8744087590
assert( pOp>aOp );
@@ -87450,20 +87600,20 @@
8745087600
p1 = pOp->p1;
8745187601
p2 = pOp->p2;
8745287602
#ifdef SQLITE_DEBUG
8745387603
if( aPermute ){
8745487604
int k, mx = 0;
87455
- for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
87605
+ for(k=0; k<n; k++) if( aPermute[k]>(u32)mx ) mx = aPermute[k];
8745687606
assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
8745787607
assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
8745887608
}else{
8745987609
assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
8746087610
assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
8746187611
}
8746287612
#endif /* SQLITE_DEBUG */
8746387613
for(i=0; i<n; i++){
87464
- idx = aPermute ? aPermute[i] : i;
87614
+ idx = aPermute ? aPermute[i] : (u32)i;
8746587615
assert( memIsValid(&aMem[p1+idx]) );
8746687616
assert( memIsValid(&aMem[p2+idx]) );
8746787617
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
8746887618
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
8746987619
assert( i<pKeyInfo->nKeyField );
@@ -87770,11 +87920,11 @@
8777087920
** the result is guaranteed to only be used as the argument of a length()
8777187921
** or typeof() function, respectively. The loading of large blobs can be
8777287922
** skipped for length() and all content loading can be skipped for typeof().
8777387923
*/
8777487924
case OP_Column: {
87775
- int p2; /* column number to retrieve */
87925
+ u32 p2; /* column number to retrieve */
8777687926
VdbeCursor *pC; /* The VDBE cursor */
8777787927
BtCursor *pCrsr; /* The BTree cursor */
8777887928
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
8777987929
int len; /* The length of the serialized data for the column */
8778087930
int i; /* Loop counter */
@@ -87788,11 +87938,11 @@
8778887938
Mem *pReg; /* PseudoTable input register */
8778987939
8779087940
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
8779187941
pC = p->apCsr[pOp->p1];
8779287942
assert( pC!=0 );
87793
- p2 = pOp->p2;
87943
+ p2 = (u32)pOp->p2;
8779487944
8779587945
/* If the cursor cache is stale (meaning it is not currently point at
8779687946
** the correct row) then bring it up-to-date by doing the necessary
8779787947
** B-Tree seek. */
8779887948
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
@@ -87800,11 +87950,11 @@
8780087950
8780187951
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
8780287952
pDest = &aMem[pOp->p3];
8780387953
memAboutToChange(p, pDest);
8780487954
assert( pC!=0 );
87805
- assert( p2<pC->nField );
87955
+ assert( p2<(u32)pC->nField );
8780687956
aOffset = pC->aOffset;
8780787957
assert( pC->eCurType!=CURTYPE_VTAB );
8780887958
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
8780987959
assert( pC->eCurType!=CURTYPE_SORTER );
8781087960
@@ -87915,11 +88065,11 @@
8791588065
zHdr += sqlite3GetVarint32(zHdr, &t);
8791688066
pC->aType[i] = t;
8791788067
offset64 += sqlite3VdbeSerialTypeLen(t);
8791888068
}
8791988069
aOffset[++i] = (u32)(offset64 & 0xffffffff);
87920
- }while( i<=p2 && zHdr<zEndHdr );
88070
+ }while( (u32)i<=p2 && zHdr<zEndHdr );
8792188071
8792288072
/* The record is corrupt if any of the following are true:
8792388073
** (1) the bytes of the header extend past the declared header size
8792488074
** (2) the entire header was used but not all data was used
8792588075
** (3) the end of the data extends beyond the end of the record.
@@ -88939,11 +89089,11 @@
8893989089
** See also: OP_OpenRead, OP_ReopenIdx
8894089090
*/
8894189091
case OP_ReopenIdx: {
8894289092
int nField;
8894389093
KeyInfo *pKeyInfo;
88944
- int p2;
89094
+ u32 p2;
8894589095
int iDb;
8894689096
int wrFlag;
8894789097
Btree *pX;
8894889098
VdbeCursor *pCur;
8894989099
Db *pDb;
@@ -88970,11 +89120,11 @@
8897089120
goto abort_due_to_error;
8897189121
}
8897289122
8897389123
nField = 0;
8897489124
pKeyInfo = 0;
88975
- p2 = pOp->p2;
89125
+ p2 = (u32)pOp->p2;
8897689126
iDb = pOp->p3;
8897789127
assert( iDb>=0 && iDb<db->nDb );
8897889128
assert( DbMaskTest(p->btreeMask, iDb) );
8897989129
pDb = &db->aDb[iDb];
8898089130
pX = pDb->pBt;
@@ -88989,11 +89139,11 @@
8898989139
}else{
8899089140
wrFlag = 0;
8899189141
}
8899289142
if( pOp->p5 & OPFLAG_P2ISREG ){
8899389143
assert( p2>0 );
88994
- assert( p2<=(p->nMem+1 - p->nCursor) );
89144
+ assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
8899589145
assert( pOp->opcode==OP_OpenWrite );
8899689146
pIn2 = &aMem[p2];
8899789147
assert( memIsValid(pIn2) );
8899889148
assert( (pIn2->flags & MEM_Int)!=0 );
8899989149
sqlite3VdbeMemIntegerify(pIn2);
@@ -89142,11 +89292,11 @@
8914289292
** opening it. If a transient table is required, just use the
8914389293
** automatically created table with root-page 1 (an BLOB_INTKEY table).
8914489294
*/
8914589295
if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
8914689296
assert( pOp->p4type==P4_KEYINFO );
89147
- rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot,
89297
+ rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
8914889298
BTREE_BLOBKEY | pOp->p5);
8914989299
if( rc==SQLITE_OK ){
8915089300
assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
8915189301
assert( pKeyInfo->db==db );
8915289302
assert( pKeyInfo->enc==ENC(db) );
@@ -89684,10 +89834,11 @@
8968489834
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
8968589835
pC = p->apCsr[pOp->p1];
8968689836
assert( pC!=0 );
8968789837
if( pC->seekHit ) break;
8968889838
/* Fall through into OP_NotFound */
89839
+ /* no break */ deliberate_fall_through
8968989840
}
8969089841
case OP_NoConflict: /* jump, in3 */
8969189842
case OP_NotFound: /* jump, in3 */
8969289843
case OP_Found: { /* jump, in3 */
8969389844
int alreadyExists;
@@ -89838,10 +89989,11 @@
8983889989
if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
8983989990
iKey = x.u.i;
8984089991
goto notExistsWithKey;
8984189992
}
8984289993
/* Fall through into OP_NotExists */
89994
+ /* no break */ deliberate_fall_through
8984389995
case OP_NotExists: /* jump, in3 */
8984489996
pIn3 = &aMem[pOp->p3];
8984589997
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
8984689998
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
8984789999
iKey = pIn3->u.i;
@@ -90406,14 +90558,10 @@
9040690558
** generator) then the fix would be to insert a call to
9040790559
** sqlite3VdbeCursorMoveto().
9040890560
*/
9040990561
assert( pC->deferredMoveto==0 );
9041090562
assert( sqlite3BtreeCursorIsValid(pCrsr) );
90411
-#if 0 /* Not required due to the previous to assert() statements */
90412
- rc = sqlite3VdbeCursorMoveto(pC);
90413
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
90414
-#endif
9041590563
9041690564
n = sqlite3BtreePayloadSize(pCrsr);
9041790565
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
9041890566
goto too_big;
9041990567
}
@@ -90613,10 +90761,11 @@
9061390761
sqlite3_sort_count++;
9061490762
sqlite3_search_count--;
9061590763
#endif
9061690764
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
9061790765
/* Fall through into OP_Rewind */
90766
+ /* no break */ deliberate_fall_through
9061890767
}
9061990768
/* Opcode: Rewind P1 P2 * * *
9062090769
**
9062190770
** The next use of the Rowid or Column or Next instruction for P1
9062290771
** will refer to the first entry in the database table or index.
@@ -91179,11 +91328,11 @@
9117991328
sqlite3VdbeIncrWriteCounter(p, 0);
9118091329
nChange = 0;
9118191330
assert( p->readOnly==0 );
9118291331
assert( DbMaskTest(p->btreeMask, pOp->p2) );
9118391332
rc = sqlite3BtreeClearTable(
91184
- db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
91333
+ db->aDb[pOp->p2].pBt, (u32)pOp->p1, (pOp->p3 ? &nChange : 0)
9118591334
);
9118691335
if( pOp->p3 ){
9118791336
p->nChange += nChange;
9118891337
if( pOp->p3>0 ){
9118991338
assert( memIsValid(&aMem[pOp->p3]) );
@@ -91228,11 +91377,11 @@
9122891377
** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
9122991378
** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table.
9123091379
** The root page number of the new b-tree is stored in register P2.
9123191380
*/
9123291381
case OP_CreateBtree: { /* out2 */
91233
- int pgno;
91382
+ Pgno pgno;
9123491383
Db *pDb;
9123591384
9123691385
sqlite3VdbeIncrWriteCounter(p, 0);
9123791386
pOut = out2Prerelease(p, pOp);
9123891387
pgno = 0;
@@ -91303,10 +91452,11 @@
9130391452
zSchema = DFLT_SCHEMA_TABLE;
9130491453
initData.db = db;
9130591454
initData.iDb = iDb;
9130691455
initData.pzErrMsg = &p->zErrMsg;
9130791456
initData.mInitFlags = 0;
91457
+ initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt);
9130891458
zSql = sqlite3MPrintf(db,
9130991459
"SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
9131091460
db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
9131191461
if( zSql==0 ){
9131291462
rc = SQLITE_NOMEM_BKPT;
@@ -91416,20 +91566,20 @@
9141691566
**
9141791567
** This opcode is used to implement the integrity_check pragma.
9141891568
*/
9141991569
case OP_IntegrityCk: {
9142091570
int nRoot; /* Number of tables to check. (Number of root pages.) */
91421
- int *aRoot; /* Array of rootpage numbers for tables to be checked */
91571
+ Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */
9142291572
int nErr; /* Number of errors reported */
9142391573
char *z; /* Text of the error report */
9142491574
Mem *pnErr; /* Register keeping track of errors remaining */
9142591575
9142691576
assert( p->bIsReader );
9142791577
nRoot = pOp->p2;
9142891578
aRoot = pOp->p4.ai;
9142991579
assert( nRoot>0 );
91430
- assert( aRoot[0]==nRoot );
91580
+ assert( aRoot[0]==(Pgno)nRoot );
9143191581
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
9143291582
pnErr = &aMem[pOp->p3];
9143391583
assert( (pnErr->flags & MEM_Int)!=0 );
9143491584
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
9143591585
pIn1 = &aMem[pOp->p1];
@@ -91965,10 +92115,11 @@
9196592115
/* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
9196692116
assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
9196792117
9196892118
pOp->opcode = OP_AggStep1;
9196992119
/* Fall through into OP_AggStep */
92120
+ /* no break */ deliberate_fall_through
9197092121
}
9197192122
case OP_AggStep1: {
9197292123
int i;
9197392124
sqlite3_context *pCtx;
9197492125
Mem *pMem;
@@ -92954,22 +93105,21 @@
9295493105
&& !p->doingRerun
9295593106
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
9295693107
){
9295793108
#ifndef SQLITE_OMIT_DEPRECATED
9295893109
if( db->mTrace & SQLITE_TRACE_LEGACY ){
92959
- void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
9296093110
char *z = sqlite3VdbeExpandSql(p, zTrace);
92961
- x(db->pTraceArg, z);
93111
+ db->trace.xLegacy(db->pTraceArg, z);
9296293112
sqlite3_free(z);
9296393113
}else
9296493114
#endif
9296593115
if( db->nVdbeExec>1 ){
9296693116
char *z = sqlite3MPrintf(db, "-- %s", zTrace);
92967
- (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
93117
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
9296893118
sqlite3DbFree(db, z);
9296993119
}else{
92970
- (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
93120
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
9297193121
}
9297293122
}
9297393123
#ifdef SQLITE_USE_FCNTL_TRACE
9297493124
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
9297593125
if( zTrace ){
@@ -96701,11 +96851,11 @@
9670196851
}else{
9670296852
if( i<=2 && pCur->zType==0 ){
9670396853
Schema *pSchema;
9670496854
HashElem *k;
9670596855
int iDb = pOp->p3;
96706
- int iRoot = pOp->p2;
96856
+ Pgno iRoot = (Pgno)pOp->p2;
9670796857
sqlite3 *db = pVTab->db;
9670896858
pSchema = db->aDb[iDb].pSchema;
9670996859
pCur->zSchema = db->aDb[iDb].zDbSName;
9671096860
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
9671196861
Table *pTab = (Table*)sqliteHashData(k);
@@ -97288,11 +97438,11 @@
9728897438
}else{
9728997439
p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
9729097440
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
9729197441
}
9729297442
97293
- p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
97443
+ pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
9729497444
p->nSpill = nSpill;
9729597445
p->flags = flags;
9729697446
p->zJournal = zName;
9729797447
p->pVfs = pVfs;
9729897448
return SQLITE_OK;
@@ -97314,11 +97464,11 @@
9731497464
** file has not yet been created, create it now.
9731597465
*/
9731697466
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
9731797467
int rc = SQLITE_OK;
9731897468
MemJournal *p = (MemJournal*)pJfd;
97319
- if( p->pMethod==&MemJournalMethods && (
97469
+ if( pJfd->pMethods==&MemJournalMethods && (
9732097470
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
9732197471
p->nSpill>0
9732297472
#else
9732397473
/* While this appears to not be possible without ATOMIC_WRITE, the
9732497474
** paths are complex, so it seems prudent to leave the test in as
@@ -98687,11 +98837,11 @@
9868798837
pExpr->op2 = pExpr->op;
9868898838
pExpr->op = TK_TRUTH;
9868998839
return WRC_Continue;
9869098840
}
9869198841
}
98692
- /* Fall thru */
98842
+ /* no break */ deliberate_fall_through
9869398843
}
9869498844
case TK_BETWEEN:
9869598845
case TK_EQ:
9869698846
case TK_NE:
9869798847
case TK_LT:
@@ -101591,11 +101741,11 @@
101591101741
/* Convert "true" or "false" in a DEFAULT clause into the
101592101742
** appropriate TK_TRUEFALSE operator */
101593101743
if( sqlite3ExprIdToTrueFalse(pExpr) ){
101594101744
return WRC_Prune;
101595101745
}
101596
- /* Fall thru */
101746
+ /* no break */ deliberate_fall_through
101597101747
case TK_COLUMN:
101598101748
case TK_AGG_FUNCTION:
101599101749
case TK_AGG_COLUMN:
101600101750
testcase( pExpr->op==TK_ID );
101601101751
testcase( pExpr->op==TK_COLUMN );
@@ -101605,11 +101755,11 @@
101605101755
return WRC_Continue;
101606101756
}
101607101757
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
101608101758
return WRC_Continue;
101609101759
}
101610
- /* Fall through */
101760
+ /* no break */ deliberate_fall_through
101611101761
case TK_IF_NULL_ROW:
101612101762
case TK_REGISTER:
101613101763
case TK_DOT:
101614101764
testcase( pExpr->op==TK_REGISTER );
101615101765
testcase( pExpr->op==TK_IF_NULL_ROW );
@@ -101626,11 +101776,11 @@
101626101776
/* A bound parameter in a CREATE statement that originates from
101627101777
** sqlite3_prepare() causes an error */
101628101778
pWalker->eCode = 0;
101629101779
return WRC_Abort;
101630101780
}
101631
- /* Fall through */
101781
+ /* no break */ deliberate_fall_through
101632101782
default:
101633101783
testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
101634101784
testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
101635101785
return WRC_Continue;
101636101786
}
@@ -103398,10 +103548,11 @@
103398103548
}
103399103549
}
103400103550
return target;
103401103551
}
103402103552
/* Otherwise, fall thru into the TK_COLUMN case */
103553
+ /* no break */ deliberate_fall_through
103403103554
}
103404103555
case TK_COLUMN: {
103405103556
int iTab = pExpr->iTable;
103406103557
int iReg;
103407103558
if( ExprHasProperty(pExpr, EP_FixedCol) ){
@@ -104463,11 +104614,11 @@
104463104614
case TK_ISNOT:
104464104615
testcase( op==TK_IS );
104465104616
testcase( op==TK_ISNOT );
104466104617
op = (op==TK_IS) ? TK_EQ : TK_NE;
104467104618
jumpIfNull = SQLITE_NULLEQ;
104468
- /* Fall thru */
104619
+ /* no break */ deliberate_fall_through
104469104620
case TK_LT:
104470104621
case TK_LE:
104471104622
case TK_GT:
104472104623
case TK_GE:
104473104624
case TK_NE:
@@ -104639,11 +104790,11 @@
104639104790
case TK_ISNOT:
104640104791
testcase( pExpr->op==TK_IS );
104641104792
testcase( pExpr->op==TK_ISNOT );
104642104793
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
104643104794
jumpIfNull = SQLITE_NULLEQ;
104644
- /* Fall thru */
104795
+ /* no break */ deliberate_fall_through
104645104796
case TK_LT:
104646104797
case TK_LE:
104647104798
case TK_GT:
104648104799
case TK_GE:
104649104800
case TK_NE:
@@ -104951,17 +105102,17 @@
104951105102
case TK_BITOR:
104952105103
case TK_LSHIFT:
104953105104
case TK_RSHIFT:
104954105105
case TK_CONCAT:
104955105106
seenNot = 1;
104956
- /* Fall thru */
105107
+ /* no break */ deliberate_fall_through
104957105108
case TK_STAR:
104958105109
case TK_REM:
104959105110
case TK_BITAND:
104960105111
case TK_SLASH: {
104961105112
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
104962
- /* Fall thru into the next case */
105113
+ /* no break */ deliberate_fall_through
104963105114
}
104964105115
case TK_SPAN:
104965105116
case TK_COLLATE:
104966105117
case TK_UPLUS:
104967105118
case TK_UMINUS: {
@@ -105106,10 +105257,11 @@
105106105257
|| (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0)
105107105258
&& IsVirtual(pRight->y.pTab))
105108105259
){
105109105260
return WRC_Prune;
105110105261
}
105262
+ /* no break */ deliberate_fall_through
105111105263
}
105112105264
default:
105113105265
return WRC_Continue;
105114105266
}
105115105267
}
@@ -106839,11 +106991,11 @@
106839106991
}
106840106992
if( rc==SQLITE_OK && pStep->zTarget ){
106841106993
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
106842106994
if( pSrc ){
106843106995
int i;
106844
- for(i=0; i<pSrc->nSrc; i++){
106996
+ for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
106845106997
struct SrcList_item *p = &pSrc->a[i];
106846106998
p->pTab = sqlite3LocateTableItem(pParse, 0, p);
106847106999
p->iCursor = pParse->nTab++;
106848107000
if( p->pTab==0 ){
106849107001
rc = SQLITE_ERROR;
@@ -107581,11 +107733,11 @@
107581107733
};
107582107734
int i;
107583107735
sqlite3 *db = pParse->db;
107584107736
Db *pDb;
107585107737
Vdbe *v = sqlite3GetVdbe(pParse);
107586
- int aRoot[ArraySize(aTable)];
107738
+ u32 aRoot[ArraySize(aTable)];
107587107739
u8 aCreateTbl[ArraySize(aTable)];
107588107740
#ifdef SQLITE_ENABLE_STAT4
107589107741
const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
107590107742
#else
107591107743
const int nToOpen = 1;
@@ -107610,11 +107762,11 @@
107610107762
** of the new table in register pParse->regRoot. This is important
107611107763
** because the OpenWrite opcode below will be needing it. */
107612107764
sqlite3NestedParse(pParse,
107613107765
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
107614107766
);
107615
- aRoot[i] = pParse->regRoot;
107767
+ aRoot[i] = (u32)pParse->regRoot;
107616107768
aCreateTbl[i] = OPFLAG_P2ISREG;
107617107769
}
107618107770
}else{
107619107771
/* The table already exists. If zWhere is not NULL, delete all entries
107620107772
** associated with the table zWhere. If zWhere is NULL, delete the
@@ -107630,19 +107782,19 @@
107630107782
}else if( db->xPreUpdateCallback ){
107631107783
sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
107632107784
#endif
107633107785
}else{
107634107786
/* The sqlite_stat[134] table already exists. Delete all rows. */
107635
- sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
107787
+ sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
107636107788
}
107637107789
}
107638107790
}
107639107791
107640107792
/* Open the sqlite_stat[134] tables for writing. */
107641107793
for(i=0; i<nToOpen; i++){
107642107794
assert( i<ArraySize(aTable) );
107643
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
107795
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
107644107796
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
107645107797
VdbeComment((v, aTable[i].zName));
107646107798
}
107647107799
}
107648107800
@@ -110271,11 +110423,11 @@
110271110423
** The TableLock structure is only used by the sqlite3TableLock() and
110272110424
** codeTableLocks() functions.
110273110425
*/
110274110426
struct TableLock {
110275110427
int iDb; /* The database containing the table to be locked */
110276
- int iTab; /* The root page of the table to be locked */
110428
+ Pgno iTab; /* The root page of the table to be locked */
110277110429
u8 isWriteLock; /* True for write lock. False for a read lock */
110278110430
const char *zLockName; /* Name of the table */
110279110431
};
110280110432
110281110433
/*
@@ -110289,11 +110441,11 @@
110289110441
** codeTableLocks() which occurs during sqlite3FinishCoding().
110290110442
*/
110291110443
SQLITE_PRIVATE void sqlite3TableLock(
110292110444
Parse *pParse, /* Parsing context */
110293110445
int iDb, /* Index of the database containing the table to lock */
110294
- int iTab, /* Root page number of the table to be locked */
110446
+ Pgno iTab, /* Root page number of the table to be locked */
110295110447
u8 isWriteLock, /* True for a write lock */
110296110448
const char *zName /* Name of the table to be locked */
110297110449
){
110298110450
Parse *pToplevel = sqlite3ParseToplevel(pParse);
110299110451
int i;
@@ -111128,23 +111280,24 @@
111128111280
const char *zName, /* Name of the object to check */
111129111281
const char *zType, /* Type of this object */
111130111282
const char *zTblName /* Parent table name for triggers and indexes */
111131111283
){
111132111284
sqlite3 *db = pParse->db;
111133
- if( sqlite3WritableSchema(db) || db->init.imposterTable ){
111285
+ if( sqlite3WritableSchema(db)
111286
+ || db->init.imposterTable
111287
+ || !sqlite3Config.bExtraSchemaChecks
111288
+ ){
111134111289
/* Skip these error checks for writable_schema=ON */
111135111290
return SQLITE_OK;
111136111291
}
111137111292
if( db->init.busy ){
111138111293
if( sqlite3_stricmp(zType, db->init.azInit[0])
111139111294
|| sqlite3_stricmp(zName, db->init.azInit[1])
111140111295
|| sqlite3_stricmp(zTblName, db->init.azInit[2])
111141111296
){
111142
- if( sqlite3Config.bExtraSchemaChecks ){
111143
- sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
111144
- return SQLITE_ERROR;
111145
- }
111297
+ sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
111298
+ return SQLITE_ERROR;
111146111299
}
111147111300
}else{
111148111301
if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
111149111302
|| (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
111150111303
){
@@ -112354,11 +112507,11 @@
112354112507
** table entry. This is only required if currently generating VDBE
112355112508
** code for a CREATE TABLE (not when parsing one as part of reading
112356112509
** a database schema). */
112357112510
if( v && pPk->tnum>0 ){
112358112511
assert( db->init.busy==0 );
112359
- sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
112512
+ sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto);
112360112513
}
112361112514
112362112515
/* The root page of the PRIMARY KEY is the table root page */
112363112516
pPk->tnum = pTab->tnum;
112364112517
@@ -112942,14 +113095,12 @@
112942113095
** statement that defines the view.
112943113096
*/
112944113097
assert( pTable->pSelect );
112945113098
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
112946113099
if( pSel ){
112947
-#ifndef SQLITE_OMIT_ALTERTABLE
112948113100
u8 eParseMode = pParse->eParseMode;
112949113101
pParse->eParseMode = PARSE_MODE_NORMAL;
112950
-#endif
112951113102
n = pParse->nTab;
112952113103
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
112953113104
pTable->nCol = -1;
112954113105
DisableLookaside;
112955113106
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -112993,13 +113144,11 @@
112993113144
}
112994113145
pTable->nNVCol = pTable->nCol;
112995113146
sqlite3DeleteTable(db, pSelTab);
112996113147
sqlite3SelectDelete(db, pSel);
112997113148
EnableLookaside;
112998
-#ifndef SQLITE_OMIT_ALTERTABLE
112999113149
pParse->eParseMode = eParseMode;
113000
-#endif
113001113150
} else {
113002113151
nErr++;
113003113152
}
113004113153
pTable->pSchema->schemaFlags |= DB_UnresetViews;
113005113154
if( db->mallocFailed ){
@@ -113050,11 +113199,11 @@
113050113199
** We must continue looping until all tables and indices with
113051113200
** rootpage==iFrom have been converted to have a rootpage of iTo
113052113201
** in order to be certain that we got the right one.
113053113202
*/
113054113203
#ifndef SQLITE_OMIT_AUTOVACUUM
113055
-SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
113204
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
113056113205
HashElem *pElem;
113057113206
Hash *pHash;
113058113207
Db *pDb;
113059113208
113060113209
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
@@ -113127,22 +113276,22 @@
113127113276
** and root page 5 happened to be the largest root-page number in the
113128113277
** database, then root page 5 would be moved to page 4 by the
113129113278
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
113130113279
** a free-list page.
113131113280
*/
113132
- int iTab = pTab->tnum;
113133
- int iDestroyed = 0;
113281
+ Pgno iTab = pTab->tnum;
113282
+ Pgno iDestroyed = 0;
113134113283
113135113284
while( 1 ){
113136113285
Index *pIdx;
113137
- int iLargest = 0;
113286
+ Pgno iLargest = 0;
113138113287
113139113288
if( iDestroyed==0 || iTab<iDestroyed ){
113140113289
iLargest = iTab;
113141113290
}
113142113291
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
113143
- int iIdx = pIdx->tnum;
113292
+ Pgno iIdx = pIdx->tnum;
113144113293
assert( pIdx->pSchema==pTab->pSchema );
113145113294
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
113146113295
iLargest = iIdx;
113147113296
}
113148113297
}
@@ -113561,11 +113710,11 @@
113561113710
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
113562113711
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
113563113712
int iSorter; /* Cursor opened by OpenSorter (if in use) */
113564113713
int addr1; /* Address of top of loop */
113565113714
int addr2; /* Address to jump to for next iteration */
113566
- int tnum; /* Root page of index */
113715
+ Pgno tnum; /* Root page of index */
113567113716
int iPartIdxLabel; /* Jump to this label to skip a row */
113568113717
Vdbe *v; /* Generate code into this virtual machine */
113569113718
KeyInfo *pKey; /* KeyInfo for index */
113570113719
int regRecord; /* Register holding assembled index record */
113571113720
sqlite3 *db = pParse->db; /* The database connection */
@@ -113582,11 +113731,11 @@
113582113731
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
113583113732
113584113733
v = sqlite3GetVdbe(pParse);
113585113734
if( v==0 ) return;
113586113735
if( memRootPage>=0 ){
113587
- tnum = memRootPage;
113736
+ tnum = (Pgno)memRootPage;
113588113737
}else{
113589113738
tnum = pIndex->tnum;
113590113739
}
113591113740
pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
113592113741
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
@@ -113607,11 +113756,11 @@
113607113756
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
113608113757
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
113609113758
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
113610113759
sqlite3VdbeJumpHere(v, addr1);
113611113760
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
113612
- sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
113761
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb,
113613113762
(char *)pKey, P4_KEYINFO);
113614113763
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
113615113764
113616113765
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
113617113766
if( IsUniqueIndex(pIndex) ){
@@ -114216,11 +114365,11 @@
114216114365
** doing so, code a Noop instruction and store its address in
114217114366
** Index.tnum. This is required in case this index is actually a
114218114367
** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
114219114368
** that case the convertToWithoutRowidTable() routine will replace
114220114369
** the Noop with a Goto to jump over the VDBE code generated below. */
114221
- pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
114370
+ pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop);
114222114371
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
114223114372
114224114373
/* Gather the complete text of the CREATE INDEX statement into
114225114374
** the zStmt variable
114226114375
*/
@@ -114258,11 +114407,11 @@
114258114407
sqlite3VdbeAddParseSchemaOp(v, iDb,
114259114408
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
114260114409
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
114261114410
}
114262114411
114263
- sqlite3VdbeJumpHere(v, pIndex->tnum);
114412
+ sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
114264114413
}
114265114414
}
114266114415
if( db->init.busy || pTblName==0 ){
114267114416
pIndex->pNext = pTab->pIndex;
114268114417
pTab->pIndex = pIndex;
@@ -114333,11 +114482,11 @@
114333114482
**
114334114483
** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
114335114484
** table but other parts we are having to guess at, then do not let the
114336114485
** estimated number of rows in the table be less than 1000 (LogEst 99).
114337114486
** Failure to do this can cause the indexes for which we do not have
114338
- ** stat1 data to be ignored by the query planner. tag-20200527-1
114487
+ ** stat1 data to be ignored by the query planner.
114339114488
*/
114340114489
x = pIdx->pTable->nRowLogEst;
114341114490
assert( 99==sqlite3LogEst(1000) );
114342114491
if( x<99 ){
114343114492
pIdx->pTable->nRowLogEst = x = 99;
@@ -120309,10 +120458,11 @@
120309120458
case OE_Cascade:
120310120459
if( !pChanges ){
120311120460
pStep->op = TK_DELETE;
120312120461
break;
120313120462
}
120463
+ /* no break */ deliberate_fall_through
120314120464
default:
120315120465
pStep->op = TK_UPDATE;
120316120466
}
120317120467
pStep->pTrig = pTrigger;
120318120468
pTrigger->pSchema = pTab->pSchema;
@@ -120581,11 +120731,11 @@
120581120731
for(i=1; i<iEnd; i++){
120582120732
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
120583120733
assert( pOp!=0 );
120584120734
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
120585120735
Index *pIndex;
120586
- int tnum = pOp->p2;
120736
+ Pgno tnum = pOp->p2;
120587120737
if( tnum==pTab->tnum ){
120588120738
return 1;
120589120739
}
120590120740
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
120591120741
if( tnum==pIndex->tnum ){
@@ -122013,11 +122163,11 @@
122013122163
sqlite3VdbeJumpHere(v, addr1);
122014122164
break;
122015122165
}
122016122166
case OE_Abort:
122017122167
sqlite3MayAbort(pParse);
122018
- /* Fall through */
122168
+ /* no break */ deliberate_fall_through
122019122169
case OE_Rollback:
122020122170
case OE_Fail: {
122021122171
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
122022122172
pCol->zName);
122023122173
sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
@@ -122241,11 +122391,11 @@
122241122391
VdbeCoverage(v);
122242122392
122243122393
switch( onError ){
122244122394
default: {
122245122395
onError = OE_Abort;
122246
- /* Fall thru into the next case */
122396
+ /* no break */ deliberate_fall_through
122247122397
}
122248122398
case OE_Rollback:
122249122399
case OE_Abort:
122250122400
case OE_Fail: {
122251122401
testcase( onError==OE_Rollback );
@@ -122302,11 +122452,11 @@
122302122452
break;
122303122453
}
122304122454
#ifndef SQLITE_OMIT_UPSERT
122305122455
case OE_Update: {
122306122456
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
122307
- /* Fall through */
122457
+ /* no break */ deliberate_fall_through
122308122458
}
122309122459
#endif
122310122460
case OE_Ignore: {
122311122461
testcase( onError==OE_Ignore );
122312122462
sqlite3VdbeGoto(v, ignoreDest);
@@ -122523,11 +122673,11 @@
122523122673
break;
122524122674
}
122525122675
#ifndef SQLITE_OMIT_UPSERT
122526122676
case OE_Update: {
122527122677
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
122528
- /* Fall through */
122678
+ /* no break */ deliberate_fall_through
122529122679
}
122530122680
#endif
122531122681
case OE_Ignore: {
122532122682
testcase( onError==OE_Ignore );
122533122683
sqlite3VdbeGoto(v, ignoreDest);
@@ -126204,17 +126354,23 @@
126204126354
**
126205126355
** Return the number of pages in the specified database.
126206126356
*/
126207126357
case PragTyp_PAGE_COUNT: {
126208126358
int iReg;
126359
+ i64 x = 0;
126209126360
sqlite3CodeVerifySchema(pParse, iDb);
126210126361
iReg = ++pParse->nMem;
126211126362
if( sqlite3Tolower(zLeft[0])=='p' ){
126212126363
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
126213126364
}else{
126214
- sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
126215
- sqlite3AbsInt32(sqlite3Atoi(zRight)));
126365
+ if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){
126366
+ if( x<0 ) x = 0;
126367
+ else if( x>0xfffffffe ) x = 0xfffffffe;
126368
+ }else{
126369
+ x = 0;
126370
+ }
126371
+ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x);
126216126372
}
126217126373
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
126218126374
break;
126219126375
}
126220126376
@@ -127113,13 +127269,26 @@
127113127269
**
127114127270
** The "quick_check" is reduced version of
127115127271
** integrity_check designed to detect most database corruption
127116127272
** without the overhead of cross-checking indexes. Quick_check
127117127273
** is linear time wherease integrity_check is O(NlogN).
127274
+ **
127275
+ ** The maximum nubmer of errors is 100 by default. A different default
127276
+ ** can be specified using a numeric parameter N.
127277
+ **
127278
+ ** Or, the parameter N can be the name of a table. In that case, only
127279
+ ** the one table named is verified. The freelist is only verified if
127280
+ ** the named table is "sqlite_schema" (or one of its aliases).
127281
+ **
127282
+ ** All schemas are checked by default. To check just a single
127283
+ ** schema, use the form:
127284
+ **
127285
+ ** PRAGMA schema.integrity_check;
127118127286
*/
127119127287
case PragTyp_INTEGRITY_CHECK: {
127120127288
int i, j, addr, mxErr;
127289
+ Table *pObjTab = 0; /* Check only this one table, if not NULL */
127121127290
127122127291
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
127123127292
127124127293
/* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
127125127294
** then iDb is set to the index of the database identified by <db>.
@@ -127138,13 +127307,17 @@
127138127307
pParse->nMem = 6;
127139127308
127140127309
/* Set the maximum error count */
127141127310
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
127142127311
if( zRight ){
127143
- sqlite3GetInt32(zRight, &mxErr);
127144
- if( mxErr<=0 ){
127145
- mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
127312
+ if( sqlite3GetInt32(zRight, &mxErr) ){
127313
+ if( mxErr<=0 ){
127314
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
127315
+ }
127316
+ }else{
127317
+ pObjTab = sqlite3LocateTable(pParse, 0, zRight,
127318
+ iDb>=0 ? db->aDb[iDb].zDbSName : 0);
127146127319
}
127147127320
}
127148127321
sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
127149127322
127150127323
/* Do an integrity check on each database file */
@@ -127169,19 +127342,25 @@
127169127342
pTbls = &db->aDb[i].pSchema->tblHash;
127170127343
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
127171127344
Table *pTab = sqliteHashData(x); /* Current table */
127172127345
Index *pIdx; /* An index on pTab */
127173127346
int nIdx; /* Number of indexes on pTab */
127347
+ if( pObjTab && pObjTab!=pTab ) continue;
127174127348
if( HasRowid(pTab) ) cnt++;
127175127349
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
127176127350
if( nIdx>mxIdx ) mxIdx = nIdx;
127177127351
}
127352
+ if( cnt==0 ) continue;
127353
+ if( pObjTab ) cnt++;
127178127354
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
127179127355
if( aRoot==0 ) break;
127180
- for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
127356
+ cnt = 0;
127357
+ if( pObjTab ) aRoot[++cnt] = 0;
127358
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
127181127359
Table *pTab = sqliteHashData(x);
127182127360
Index *pIdx;
127361
+ if( pObjTab && pObjTab!=pTab ) continue;
127183127362
if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
127184127363
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
127185127364
aRoot[++cnt] = pIdx->tnum;
127186127365
}
127187127366
}
@@ -127211,10 +127390,11 @@
127211127390
int loopTop;
127212127391
int iDataCur, iIdxCur;
127213127392
int r1 = -1;
127214127393
127215127394
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
127395
+ if( pObjTab && pObjTab!=pTab ) continue;
127216127396
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
127217127397
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
127218127398
1, 0, &iDataCur, &iIdxCur);
127219127399
/* reg[7] counts the number of entries in the table.
127220127400
** reg[8+i] counts the number of entries in the i-th index
@@ -128272,11 +128452,17 @@
128272128452
sqlite3_stmt *pStmt;
128273128453
TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
128274128454
128275128455
assert( db->init.busy );
128276128456
db->init.iDb = iDb;
128277
- db->init.newTnum = sqlite3Atoi(argv[3]);
128457
+ if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0
128458
+ || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
128459
+ ){
128460
+ if( sqlite3Config.bExtraSchemaChecks ){
128461
+ corruptSchema(pData, argv[1], "invalid rootpage");
128462
+ }
128463
+ }
128278128464
db->init.orphanTrigger = 0;
128279128465
db->init.azInit = argv;
128280128466
pStmt = 0;
128281128467
TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
128282128468
rc = db->errCode;
@@ -128305,16 +128491,21 @@
128305128491
** been created when we processed the CREATE TABLE. All we have
128306128492
** to do here is record the root page number for that index.
128307128493
*/
128308128494
Index *pIndex;
128309128495
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
128310
- if( pIndex==0
128311
- || sqlite3GetInt32(argv[3],&pIndex->tnum)==0
128496
+ if( pIndex==0 ){
128497
+ corruptSchema(pData, argv[1], "orphan index");
128498
+ }else
128499
+ if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
128312128500
|| pIndex->tnum<2
128501
+ || pIndex->tnum>pData->mxPage
128313128502
|| sqlite3IndexHasDuplicateRootPage(pIndex)
128314128503
){
128315
- corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
128504
+ if( sqlite3Config.bExtraSchemaChecks ){
128505
+ corruptSchema(pData, argv[1], "invalid rootpage");
128506
+ }
128316128507
}
128317128508
}
128318128509
return 0;
128319128510
}
128320128511
@@ -128364,10 +128555,11 @@
128364128555
initData.iDb = iDb;
128365128556
initData.rc = SQLITE_OK;
128366128557
initData.pzErrMsg = pzErrMsg;
128367128558
initData.mInitFlags = mFlags;
128368128559
initData.nInitRow = 0;
128560
+ initData.mxPage = 0;
128369128561
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
128370128562
db->mDbFlags &= mask;
128371128563
if( initData.rc ){
128372128564
rc = initData.rc;
128373128565
goto error_out;
@@ -128486,10 +128678,11 @@
128486128678
}
128487128679
128488128680
/* Read the schema information out of the schema tables
128489128681
*/
128490128682
assert( db->init.busy );
128683
+ initData.mxPage = sqlite3BtreeLastPage(pDb->pBt);
128491128684
{
128492128685
char *zSql;
128493128686
zSql = sqlite3MPrintf(db,
128494128687
"SELECT*FROM\"%w\".%s ORDER BY rowid",
128495128688
db->aDb[iDb].zDbSName, zSchemaTabName);
@@ -129368,12 +129561,14 @@
129368129561
** Return the index of a column in a table. Return -1 if the column
129369129562
** is not contained in the table.
129370129563
*/
129371129564
static int columnIndex(Table *pTab, const char *zCol){
129372129565
int i;
129373
- for(i=0; i<pTab->nCol; i++){
129374
- if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
129566
+ u8 h = sqlite3StrIHash(zCol);
129567
+ Column *pCol;
129568
+ for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
129569
+ if( pCol->hName==h && sqlite3StrICmp(pCol->zName, zCol)==0 ) return i;
129375129570
}
129376129571
return -1;
129377129572
}
129378129573
129379129574
/*
@@ -130231,20 +130426,24 @@
130231130426
sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
130232130427
break;
130233130428
}
130234130429
130235130430
case SRT_Upfrom: {
130236
-#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
130237130431
if( pSort ){
130238130432
pushOntoSorter(
130239130433
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
130240
- }else
130241
-#endif
130242
- {
130434
+ }else{
130243130435
int i2 = pDest->iSDParm2;
130244130436
int r1 = sqlite3GetTempReg(pParse);
130245
- sqlite3VdbeAddOp3(v, OP_MakeRecord,regResult+(i2<0),nResultCol-(i2<0),r1);
130437
+
130438
+ /* If the UPDATE FROM join is an aggregate that matches no rows, it
130439
+ ** might still be trying to return one row, because that is what
130440
+ ** aggregates do. Don't record that empty row in the output table. */
130441
+ sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v);
130442
+
130443
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,
130444
+ regResult+(i2<0), nResultCol-(i2<0), r1);
130246130445
if( i2<0 ){
130247130446
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
130248130447
}else{
130249130448
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
130250130449
}
@@ -130682,11 +130881,10 @@
130682130881
case SRT_Mem: {
130683130882
/* The LIMIT clause will terminate the loop for us */
130684130883
break;
130685130884
}
130686130885
#endif
130687
-#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
130688130886
case SRT_Upfrom: {
130689130887
int i2 = pDest->iSDParm2;
130690130888
int r1 = sqlite3GetTempReg(pParse);
130691130889
sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
130692130890
if( i2<0 ){
@@ -130694,11 +130892,10 @@
130694130892
}else{
130695130893
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
130696130894
}
130697130895
break;
130698130896
}
130699
-#endif
130700130897
default: {
130701130898
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
130702130899
testcase( eDest==SRT_Output );
130703130900
testcase( eDest==SRT_Coroutine );
130704130901
if( eDest==SRT_Output ){
@@ -132281,11 +132478,11 @@
132281132478
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
132282132479
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
132283132480
sqlite3 *db; /* Database connection */
132284132481
ExprList *pOrderBy; /* The ORDER BY clause */
132285132482
int nOrderBy; /* Number of terms in the ORDER BY clause */
132286
- int *aPermute; /* Mapping from ORDER BY terms to result set columns */
132483
+ u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */
132287132484
132288132485
assert( p->pOrderBy!=0 );
132289132486
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
132290132487
db = pParse->db;
132291132488
v = pParse->pVdbe;
@@ -132330,11 +132527,11 @@
132330132527
** row of results comes from selectA or selectB. Also add explicit
132331132528
** collations to the ORDER BY clause terms so that when the subqueries
132332132529
** to the right and the left are evaluated, they use the correct
132333132530
** collation.
132334132531
*/
132335
- aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
132532
+ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
132336132533
if( aPermute ){
132337132534
struct ExprList_item *pItem;
132338132535
aPermute[0] = nOrderBy;
132339132536
for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
132340132537
assert( pItem->u.x.iOrderByCol>0 );
@@ -133286,11 +133483,11 @@
133286133483
sqlite3AggInfoPersistWalkerInit(&w, pParse);
133287133484
sqlite3WalkSelect(&w,pSub1);
133288133485
sqlite3SelectDelete(db, pSub1);
133289133486
133290133487
#if SELECTTRACE_ENABLED
133291
- if( sqlite3SelectTrace & 0x100 ){
133488
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
133292133489
SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
133293133490
sqlite3TreeViewSelect(0, p, 0);
133294133491
}
133295133492
#endif
133296133493
@@ -134724,11 +134921,11 @@
134724134921
sWalker.pParse = pParse;
134725134922
sWalker.xExprCallback = havingToWhereExprCb;
134726134923
sWalker.u.pSelect = p;
134727134924
sqlite3WalkExpr(&sWalker, p->pHaving);
134728134925
#if SELECTTRACE_ENABLED
134729
- if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){
134926
+ if( sWalker.eCode && (sqlite3_unsupported_selecttrace & 0x100)!=0 ){
134730134927
SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
134731134928
sqlite3TreeViewSelect(0, p, 0);
134732134929
}
134733134930
#endif
134734134931
}
@@ -134846,11 +135043,11 @@
134846135043
}
134847135044
p->pEList->a[0].pExpr = pExpr;
134848135045
p->selFlags &= ~SF_Aggregate;
134849135046
134850135047
#if SELECTTRACE_ENABLED
134851
- if( sqlite3SelectTrace & 0x400 ){
135048
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
134852135049
SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
134853135050
sqlite3TreeViewSelect(0, p, 0);
134854135051
}
134855135052
#endif
134856135053
return 1;
@@ -134899,11 +135096,11 @@
134899135096
return 1;
134900135097
}
134901135098
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
134902135099
#if SELECTTRACE_ENABLED
134903135100
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
134904
- if( sqlite3SelectTrace & 0x100 ){
135101
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
134905135102
sqlite3TreeViewSelect(0, p, 0);
134906135103
}
134907135104
#endif
134908135105
134909135106
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
@@ -134926,11 +135123,11 @@
134926135123
if( pParse->nErr || db->mallocFailed ){
134927135124
goto select_end;
134928135125
}
134929135126
assert( p->pEList!=0 );
134930135127
#if SELECTTRACE_ENABLED
134931
- if( sqlite3SelectTrace & 0x104 ){
135128
+ if( sqlite3_unsupported_selecttrace & 0x104 ){
134932135129
SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
134933135130
sqlite3TreeViewSelect(0, p, 0);
134934135131
}
134935135132
#endif
134936135133
@@ -134961,11 +135158,11 @@
134961135158
if( rc ){
134962135159
assert( db->mallocFailed || pParse->nErr>0 );
134963135160
goto select_end;
134964135161
}
134965135162
#if SELECTTRACE_ENABLED
134966
- if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
135163
+ if( p->pWin && (sqlite3_unsupported_selecttrace & 0x108)!=0 ){
134967135164
SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
134968135165
sqlite3TreeViewSelect(0, p, 0);
134969135166
}
134970135167
#endif
134971135168
#endif /* SQLITE_OMIT_WINDOWFUNC */
@@ -135068,11 +135265,11 @@
135068135265
*/
135069135266
if( p->pPrior ){
135070135267
rc = multiSelect(pParse, p, pDest);
135071135268
#if SELECTTRACE_ENABLED
135072135269
SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
135073
- if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
135270
+ if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
135074135271
sqlite3TreeViewSelect(0, p, 0);
135075135272
}
135076135273
#endif
135077135274
if( p->pNext==0 ) ExplainQueryPlanPop(pParse);
135078135275
return rc;
@@ -135087,11 +135284,11 @@
135087135284
if( pTabList->nSrc>1
135088135285
&& OptimizationEnabled(db, SQLITE_PropagateConst)
135089135286
&& propagateConstants(pParse, p)
135090135287
){
135091135288
#if SELECTTRACE_ENABLED
135092
- if( sqlite3SelectTrace & 0x100 ){
135289
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
135093135290
SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
135094135291
sqlite3TreeViewSelect(0, p, 0);
135095135292
}
135096135293
#endif
135097135294
}else{
@@ -135175,11 +135372,11 @@
135175135372
if( OptimizationEnabled(db, SQLITE_PushDown)
135176135373
&& pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
135177135374
(pItem->fg.jointype & JT_OUTER)!=0)
135178135375
){
135179135376
#if SELECTTRACE_ENABLED
135180
- if( sqlite3SelectTrace & 0x100 ){
135377
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
135181135378
SELECTTRACE(0x100,pParse,p,
135182135379
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
135183135380
sqlite3TreeViewSelect(0, p, 0);
135184135381
}
135185135382
#endif
@@ -135275,11 +135472,11 @@
135275135472
pGroupBy = p->pGroupBy;
135276135473
pHaving = p->pHaving;
135277135474
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
135278135475
135279135476
#if SELECTTRACE_ENABLED
135280
- if( sqlite3SelectTrace & 0x400 ){
135477
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
135281135478
SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
135282135479
sqlite3TreeViewSelect(0, p, 0);
135283135480
}
135284135481
#endif
135285135482
@@ -135311,11 +135508,11 @@
135311135508
** the sDistinct.isTnct is still set. Hence, isTnct represents the
135312135509
** original setting of the SF_Distinct flag, not the current setting */
135313135510
assert( sDistinct.isTnct );
135314135511
135315135512
#if SELECTTRACE_ENABLED
135316
- if( sqlite3SelectTrace & 0x400 ){
135513
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
135317135514
SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
135318135515
sqlite3TreeViewSelect(0, p, 0);
135319135516
}
135320135517
#endif
135321135518
}
@@ -135559,11 +135756,11 @@
135559135756
sNC.ncFlags &= ~NC_InAggFunc;
135560135757
}
135561135758
pAggInfo->mxReg = pParse->nMem;
135562135759
if( db->mallocFailed ) goto select_end;
135563135760
#if SELECTTRACE_ENABLED
135564
- if( sqlite3SelectTrace & 0x400 ){
135761
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
135565135762
int ii;
135566135763
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
135567135764
sqlite3TreeViewSelect(0, p, 0);
135568135765
for(ii=0; ii<pAggInfo->nColumn; ii++){
135569135766
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
@@ -135823,11 +136020,11 @@
135823136020
const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
135824136021
const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
135825136022
Index *pIdx; /* Iterator variable */
135826136023
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
135827136024
Index *pBest = 0; /* Best index found so far */
135828
- int iRoot = pTab->tnum; /* Root page of scanned b-tree */
136025
+ Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */
135829136026
135830136027
sqlite3CodeVerifySchema(pParse, iDb);
135831136028
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
135832136029
135833136030
/* Search for the index that has the lowest scan cost.
@@ -135855,11 +136052,11 @@
135855136052
iRoot = pBest->tnum;
135856136053
pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
135857136054
}
135858136055
135859136056
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
135860
- sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
136057
+ sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1);
135861136058
if( pKeyInfo ){
135862136059
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
135863136060
}
135864136061
sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
135865136062
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
@@ -135978,11 +136175,11 @@
135978136175
}
135979136176
#endif
135980136177
135981136178
#if SELECTTRACE_ENABLED
135982136179
SELECTTRACE(0x1,pParse,p,("end processing\n"));
135983
- if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
136180
+ if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
135984136181
sqlite3TreeViewSelect(0, p, 0);
135985136182
}
135986136183
#endif
135987136184
ExplainQueryPlanPop(pParse);
135988136185
return rc;
@@ -142375,11 +142572,11 @@
142375142572
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
142376142573
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
142377142574
){
142378142575
int i;
142379142576
Table *pTab = pIdx->pTable;
142380
- int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
142577
+ u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
142381142578
if( ai ){
142382142579
ai[0] = pTab->nCol;
142383142580
for(i=0; i<pIdx->nColumn-1; i++){
142384142581
int x1, x2;
142385142582
assert( pIdx->aiColumn[i]<pTab->nCol );
@@ -151749,11 +151946,11 @@
151749151946
assert( pWin->pOwner==pExpr );
151750151947
return WRC_Prune;
151751151948
}
151752151949
}
151753151950
}
151754
- /* Fall through. */
151951
+ /* no break */ deliberate_fall_through
151755151952
151756151953
case TK_AGG_FUNCTION:
151757151954
case TK_COLUMN: {
151758151955
int iCol = -1;
151759151956
if( p->pSub ){
@@ -159966,10 +160163,11 @@
159966160163
*tokenType = TK_DOT;
159967160164
return 1;
159968160165
}
159969160166
/* If the next character is a digit, this is a floating point
159970160167
** number that begins with ".". Fall thru into the next case */
160168
+ /* no break */ deliberate_fall_through
159971160169
}
159972160170
case CC_DIGIT: {
159973160171
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
159974160172
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
159975160173
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
@@ -160070,10 +160268,11 @@
160070160268
return i;
160071160269
}
160072160270
#endif
160073160271
/* If it is not a BLOB literal, then it must be an ID, since no
160074160272
** SQL keywords start with the letter 'x'. Fall through */
160273
+ /* no break */ deliberate_fall_through
160075160274
}
160076160275
case CC_ID: {
160077160276
i = 1;
160078160277
break;
160079160278
}
@@ -162000,11 +162199,11 @@
162000162199
if( !sqlite3SafetyCheckSickOrOk(db) ){
162001162200
return SQLITE_MISUSE_BKPT;
162002162201
}
162003162202
sqlite3_mutex_enter(db->mutex);
162004162203
if( db->mTrace & SQLITE_TRACE_CLOSE ){
162005
- db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
162204
+ db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
162006162205
}
162007162206
162008162207
/* Force xDisconnect calls on all virtual tables */
162009162208
disconnectAllVtab(db);
162010162209
@@ -162889,11 +163088,11 @@
162889163088
}
162890163089
#endif
162891163090
sqlite3_mutex_enter(db->mutex);
162892163091
pOld = db->pTraceArg;
162893163092
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
162894
- db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
163093
+ db->trace.xLegacy = xTrace;
162895163094
db->pTraceArg = pArg;
162896163095
sqlite3_mutex_leave(db->mutex);
162897163096
return pOld;
162898163097
}
162899163098
#endif /* SQLITE_OMIT_DEPRECATED */
@@ -162913,11 +163112,11 @@
162913163112
#endif
162914163113
sqlite3_mutex_enter(db->mutex);
162915163114
if( mTrace==0 ) xTrace = 0;
162916163115
if( xTrace==0 ) mTrace = 0;
162917163116
db->mTrace = mTrace;
162918
- db->xTrace = xTrace;
163117
+ db->trace.xV2 = xTrace;
162919163118
db->pTraceArg = pArg;
162920163119
sqlite3_mutex_leave(db->mutex);
162921163120
return SQLITE_OK;
162922163121
}
162923163122
@@ -164889,10 +165088,16 @@
164889165088
/* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
164890165089
**
164891165090
** Set or clear a flag that causes SQLite to verify that type, name,
164892165091
** and tbl_name fields of the sqlite_schema table. This is normally
164893165092
** on, but it is sometimes useful to turn it off for testing.
165093
+ **
165094
+ ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
165095
+ ** verification of rootpage numbers when parsing the schema. This
165096
+ ** is useful to make it easier to reach strange internal error states
165097
+ ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
165098
+ ** in production.
164894165099
*/
164895165100
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
164896165101
sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
164897165102
break;
164898165103
}
@@ -166503,10 +166708,12 @@
166503166708
# define TESTONLY(X)
166504166709
#endif
166505166710
166506166711
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
166507166712
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
166713
+
166714
+#define deliberate_fall_through
166508166715
166509166716
#endif /* SQLITE_AMALGAMATION */
166510166717
166511166718
#ifdef SQLITE_DEBUG
166512166719
SQLITE_PRIVATE int sqlite3Fts3Corrupt(void);
@@ -170146,11 +170353,11 @@
170146170353
}else if( p->zLanguageid==0 ){
170147170354
sqlite3_result_int(pCtx, 0);
170148170355
break;
170149170356
}else{
170150170357
iCol = p->nColumn;
170151
- /* fall-through */
170358
+ /* no break */ deliberate_fall_through
170152170359
}
170153170360
170154170361
default:
170155170362
/* A user column. Or, if this is a full-table scan, possibly the
170156170363
** language-id column. Seek the cursor. */
@@ -170389,13 +170596,17 @@
170389170596
}
170390170597
if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return;
170391170598
170392170599
switch( nVal ){
170393170600
case 6: nToken = sqlite3_value_int(apVal[5]);
170601
+ /* no break */ deliberate_fall_through
170394170602
case 5: iCol = sqlite3_value_int(apVal[4]);
170603
+ /* no break */ deliberate_fall_through
170395170604
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
170605
+ /* no break */ deliberate_fall_through
170396170606
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
170607
+ /* no break */ deliberate_fall_through
170397170608
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
170398170609
}
170399170610
if( !zEllipsis || !zEnd || !zStart ){
170400170611
sqlite3_result_error_nomem(pContext);
170401170612
}else if( nToken==0 ){
@@ -172498,11 +172709,12 @@
172498172709
** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK );
172499172710
*/
172500172711
fts3EvalRestart(pCsr, pRoot, &rc);
172501172712
do {
172502172713
fts3EvalNextRow(pCsr, pRoot, &rc);
172503
- assert( pRoot->bEof==0 );
172714
+ assert_fts3_nc( pRoot->bEof==0 );
172715
+ if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
172504172716
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
172505172717
}
172506172718
}
172507172719
return rc;
172508172720
}
@@ -176607,11 +176819,12 @@
176607176819
rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr);
176608176820
}
176609176821
176610176822
assert( (rc==SQLITE_OK)==(pMod!=0) );
176611176823
if( rc==SQLITE_OK ){
176612
- const char * const *azArg = (const char * const *)&azDequote[1];
176824
+ const char * const *azArg = 0;
176825
+ if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
176613176826
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
176614176827
}
176615176828
176616176829
if( rc==SQLITE_OK ){
176617176830
pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable));
@@ -185252,10 +185465,14 @@
185252185465
#ifndef LARGEST_INT64
185253185466
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
185254185467
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
185255185468
#endif
185256185469
185470
+#ifndef deliberate_fall_through
185471
+# define deliberate_fall_through
185472
+#endif
185473
+
185257185474
/*
185258185475
** Versions of isspace(), isalnum() and isdigit() to which it is safe
185259185476
** to pass signed char values.
185260185477
*/
185261185478
#ifdef sqlite3Isdigit
@@ -185670,11 +185887,11 @@
185670185887
case JSON_STRING: {
185671185888
if( pNode->jnFlags & JNODE_RAW ){
185672185889
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
185673185890
break;
185674185891
}
185675
- /* Fall through into the next case */
185892
+ /* no break */ deliberate_fall_through
185676185893
}
185677185894
case JSON_REAL:
185678185895
case JSON_INT: {
185679185896
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
185680185897
break;
@@ -185811,11 +186028,11 @@
185811186028
}
185812186029
if( pNode->u.zJContent[0]=='-' ){ i = -i; }
185813186030
sqlite3_result_int64(pCtx, i);
185814186031
int_done:
185815186032
break;
185816
- int_as_real: /* fall through to real */;
186033
+ int_as_real: i=0; /* no break */ deliberate_fall_through
185817186034
}
185818186035
case JSON_REAL: {
185819186036
double r;
185820186037
#ifdef SQLITE_AMALGAMATION
185821186038
const char *z = pNode->u.zJContent;
@@ -187514,10 +187731,11 @@
187514187731
jsonResult(&x);
187515187732
break;
187516187733
}
187517187734
/* For json_each() path and root are the same so fall through
187518187735
** into the root case */
187736
+ /* no break */ deliberate_fall_through
187519187737
}
187520187738
default: {
187521187739
const char *zRoot = p->zRoot;
187522187740
if( zRoot==0 ) zRoot = "$";
187523187741
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
@@ -187921,10 +188139,11 @@
187921188139
#endif
187922188140
187923188141
/* #include <string.h> */
187924188142
/* #include <stdio.h> */
187925188143
/* #include <assert.h> */
188144
+/* #include <stdlib.h> */
187926188145
187927188146
/* The following macro is used to suppress compiler warnings.
187928188147
*/
187929188148
#ifndef UNUSED_PARAMETER
187930188149
# define UNUSED_PARAMETER(x) (void)(x)
@@ -188258,10 +188477,27 @@
188258188477
*/
188259188478
#ifndef SQLITE_AMALGAMATION
188260188479
# define testcase(X)
188261188480
#endif
188262188481
188482
+/*
188483
+** Make sure that the compiler intrinsics we desire are enabled when
188484
+** compiling with an appropriate version of MSVC unless prevented by
188485
+** the SQLITE_DISABLE_INTRINSIC define.
188486
+*/
188487
+#if !defined(SQLITE_DISABLE_INTRINSIC)
188488
+# if defined(_MSC_VER) && _MSC_VER>=1400
188489
+# if !defined(_WIN32_WCE)
188490
+/* # include <intrin.h> */
188491
+# pragma intrinsic(_byteswap_ulong)
188492
+# pragma intrinsic(_byteswap_uint64)
188493
+# else
188494
+/* # include <cmnintrin.h> */
188495
+# endif
188496
+# endif
188497
+#endif
188498
+
188263188499
/*
188264188500
** Macros to determine whether the machine is big or little endian,
188265188501
** and whether or not that determination is run-time or compile-time.
188266188502
**
188267188503
** For best performance, an attempt is made to guess at the byte-order
@@ -205152,12 +205388,17 @@
205152205388
memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
205153205389
p->in.iNext += nCopy;
205154205390
}
205155205391
205156205392
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
205157
- p->abPK = (u8*)&p->apValue[p->nCol*2];
205158
- p->zTab = (char*)&p->abPK[p->nCol];
205393
+ if( p->apValue==0 ){
205394
+ p->abPK = 0;
205395
+ p->zTab = 0;
205396
+ }else{
205397
+ p->abPK = (u8*)&p->apValue[p->nCol*2];
205398
+ p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
205399
+ }
205159205400
return (p->rc = rc);
205160205401
}
205161205402
205162205403
/*
205163205404
** Advance the changeset iterator to the next change.
@@ -225482,11 +225723,11 @@
225482225723
int nArg, /* Number of args */
225483225724
sqlite3_value **apUnused /* Function arguments */
225484225725
){
225485225726
assert( nArg==0 );
225486225727
UNUSED_PARAM2(nArg, apUnused);
225487
- sqlite3_result_text(pCtx, "fts5: 2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829b9c3", -1, SQLITE_TRANSIENT);
225728
+ sqlite3_result_text(pCtx, "fts5: 2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f", -1, SQLITE_TRANSIENT);
225488225729
}
225489225730
225490225731
/*
225491225732
** Return true if zName is the extension on one of the shadow tables used
225492225733
** by this module.
@@ -230265,12 +230506,12 @@
230265230506
}
230266230507
#endif /* SQLITE_CORE */
230267230508
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
230268230509
230269230510
/************** End of stmt.c ************************************************/
230270
-#if __LINE__!=230270
230511
+#if __LINE__!=230511
230271230512
#undef SQLITE_SOURCE_ID
230272
-#define SQLITE_SOURCE_ID "2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829alt2"
230513
+#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0alt2"
230273230514
#endif
230274230515
/* Return the source-id for this library */
230275230516
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
230276230517
/************************** End of sqlite3.c ******************************/
230277230518
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -997,10 +997,19 @@
997
998 #if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
999 # define _BSD_SOURCE
1000 #endif
1001
 
 
 
 
 
 
 
 
 
1002 /*
1003 ** For MinGW, check to see if we can include the header file containing its
1004 ** version information, among other things. Normally, this internal MinGW
1005 ** header file would [only] be included automatically by other MinGW header
1006 ** files; however, the contained version information is now required by this
@@ -1162,11 +1171,11 @@
1162 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1163 ** [sqlite_version()] and [sqlite_source_id()].
1164 */
1165 #define SQLITE_VERSION "3.33.0"
1166 #define SQLITE_VERSION_NUMBER 3033000
1167 #define SQLITE_SOURCE_ID "2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829b9c3"
1168
1169 /*
1170 ** CAPI3REF: Run-Time Library Version Numbers
1171 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1172 **
@@ -14532,11 +14541,11 @@
14532 # define SELECTTRACE_ENABLED 0
14533 #endif
14534 #if defined(SQLITE_ENABLE_SELECTTRACE)
14535 # define SELECTTRACE_ENABLED 1
14536 # define SELECTTRACE(K,P,S,X) \
14537 if(sqlite3SelectTrace&(K)) \
14538 sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
14539 sqlite3DebugPrintf X
14540 #else
14541 # define SELECTTRACE(K,P,S,X)
14542 # define SELECTTRACE_ENABLED 0
@@ -14595,11 +14604,11 @@
14595 ** one parameter that destructors normally want. So we have to introduce
14596 ** this magic value that the code knows to handle differently. Any
14597 ** pointer will work here as long as it is distinct from SQLITE_STATIC
14598 ** and SQLITE_TRANSIENT.
14599 */
14600 #define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
14601
14602 /*
14603 ** When SQLITE_OMIT_WSD is defined, it means that the target platform does
14604 ** not support Writable Static Data (WSD) such as global and static variables.
14605 ** All variables must either be on the stack or dynamically allocated from
@@ -14735,10 +14744,257 @@
14735 /*
14736 ** Defer sourcing vdbe.h and btree.h until after the "u8" and
14737 ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
14738 ** pointer types (i.e. FuncDef) defined above.
14739 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14740 /************** Include btree.h in the middle of sqliteInt.h *****************/
14741 /************** Begin file btree.h *******************************************/
14742 /*
14743 ** 2001 September 15
14744 **
@@ -14810,12 +15066,12 @@
14810 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
14811 #endif
14812 SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
14813 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
14814 SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
14815 SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
14816 SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
14817 SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
14818 SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*);
14819 SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
14820 SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
14821 SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
@@ -14823,11 +15079,11 @@
14823 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
14824 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
14825 SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
14826 SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
14827 SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
14828 SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
14829 SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
14830 SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
14831 SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
14832 SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
14833 SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
@@ -14964,11 +15220,11 @@
14964 #define BTREE_WRCSR 0x00000004 /* read-write cursor */
14965 #define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */
14966
14967 SQLITE_PRIVATE int sqlite3BtreeCursor(
14968 Btree*, /* BTree containing table to open */
14969 int iTable, /* Index of root page */
14970 int wrFlag, /* 1 for writing. 0 for read-only */
14971 struct KeyInfo*, /* First argument to compare function */
14972 BtCursor *pCursor /* Space to write cursor structure */
14973 );
14974 SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
@@ -15055,11 +15311,11 @@
15055 SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
15056 SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
15057 SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
15058 SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
15059
15060 SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,int*aRoot,int nRoot,int,int*);
15061 SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
15062 SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
15063
15064 #ifndef SQLITE_OMIT_INCRBLOB
15065 SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
@@ -15192,11 +15448,11 @@
15192 sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */
15193 CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
15194 Mem *pMem; /* Used when p4type is P4_MEM */
15195 VTable *pVtab; /* Used when p4type is P4_VTAB */
15196 KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
15197 int *ai; /* Used when p4type is P4_INTARRAY */
15198 SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
15199 Table *pTab; /* Used when p4type is P4_TABLE */
15200 #ifdef SQLITE_ENABLE_CURSOR_HINTS
15201 Expr *pExpr; /* Used when p4type is P4_EXPR */
15202 #endif
@@ -15756,257 +16012,10 @@
15756 #endif
15757
15758 #endif /* SQLITE_VDBE_H */
15759
15760 /************** End of vdbe.h ************************************************/
15761 /************** Continuing where we left off in sqliteInt.h ******************/
15762 /************** Include pager.h in the middle of sqliteInt.h *****************/
15763 /************** Begin file pager.h *******************************************/
15764 /*
15765 ** 2001 September 15
15766 **
15767 ** The author disclaims copyright to this source code. In place of
15768 ** a legal notice, here is a blessing:
15769 **
15770 ** May you do good and not evil.
15771 ** May you find forgiveness for yourself and forgive others.
15772 ** May you share freely, never taking more than you give.
15773 **
15774 *************************************************************************
15775 ** This header file defines the interface that the sqlite page cache
15776 ** subsystem. The page cache subsystem reads and writes a file a page
15777 ** at a time and provides a journal for rollback.
15778 */
15779
15780 #ifndef SQLITE_PAGER_H
15781 #define SQLITE_PAGER_H
15782
15783 /*
15784 ** Default maximum size for persistent journal files. A negative
15785 ** value means no limit. This value may be overridden using the
15786 ** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
15787 */
15788 #ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
15789 #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
15790 #endif
15791
15792 /*
15793 ** The type used to represent a page number. The first page in a file
15794 ** is called page 1. 0 is used to represent "not a page".
15795 */
15796 typedef u32 Pgno;
15797
15798 /*
15799 ** Each open file is managed by a separate instance of the "Pager" structure.
15800 */
15801 typedef struct Pager Pager;
15802
15803 /*
15804 ** Handle type for pages.
15805 */
15806 typedef struct PgHdr DbPage;
15807
15808 /*
15809 ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
15810 ** reserved for working around a windows/posix incompatibility). It is
15811 ** used in the journal to signify that the remainder of the journal file
15812 ** is devoted to storing a super-journal name - there are no more pages to
15813 ** roll back. See comments for function writeSuperJournal() in pager.c
15814 ** for details.
15815 */
15816 #define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
15817
15818 /*
15819 ** Allowed values for the flags parameter to sqlite3PagerOpen().
15820 **
15821 ** NOTE: These values must match the corresponding BTREE_ values in btree.h.
15822 */
15823 #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
15824 #define PAGER_MEMORY 0x0002 /* In-memory database */
15825
15826 /*
15827 ** Valid values for the second argument to sqlite3PagerLockingMode().
15828 */
15829 #define PAGER_LOCKINGMODE_QUERY -1
15830 #define PAGER_LOCKINGMODE_NORMAL 0
15831 #define PAGER_LOCKINGMODE_EXCLUSIVE 1
15832
15833 /*
15834 ** Numeric constants that encode the journalmode.
15835 **
15836 ** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
15837 ** are exposed in the API via the "PRAGMA journal_mode" command and
15838 ** therefore cannot be changed without a compatibility break.
15839 */
15840 #define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
15841 #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
15842 #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
15843 #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
15844 #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
15845 #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
15846 #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
15847
15848 /*
15849 ** Flags that make up the mask passed to sqlite3PagerGet().
15850 */
15851 #define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
15852 #define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
15853
15854 /*
15855 ** Flags for sqlite3PagerSetFlags()
15856 **
15857 ** Value constraints (enforced via assert()):
15858 ** PAGER_FULLFSYNC == SQLITE_FullFSync
15859 ** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
15860 ** PAGER_CACHE_SPILL == SQLITE_CacheSpill
15861 */
15862 #define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
15863 #define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
15864 #define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
15865 #define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
15866 #define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
15867 #define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
15868 #define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
15869 #define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
15870 #define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
15871
15872 /*
15873 ** The remainder of this file contains the declarations of the functions
15874 ** that make up the Pager sub-system API. See source code comments for
15875 ** a detailed description of each routine.
15876 */
15877
15878 /* Open and close a Pager connection. */
15879 SQLITE_PRIVATE int sqlite3PagerOpen(
15880 sqlite3_vfs*,
15881 Pager **ppPager,
15882 const char*,
15883 int,
15884 int,
15885 int,
15886 void(*)(DbPage*)
15887 );
15888 SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
15889 SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
15890
15891 /* Functions used to configure a Pager object. */
15892 SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
15893 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
15894 SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
15895 SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
15896 SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
15897 SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
15898 SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
15899 SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
15900 SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
15901 SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
15902 SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
15903 SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
15904 SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
15905 SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
15906 SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
15907
15908 /* Functions used to obtain and release page references. */
15909 SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
15910 SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
15911 SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
15912 SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
15913 SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
15914 SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
15915
15916 /* Operations on page references. */
15917 SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
15918 SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
15919 SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
15920 SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
15921 SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
15922 SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
15923
15924 /* Functions used to manage pager transactions and savepoints. */
15925 SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
15926 SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
15927 SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
15928 SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
15929 SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper);
15930 SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
15931 SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
15932 SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
15933 SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
15934 SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
15935
15936 #ifndef SQLITE_OMIT_WAL
15937 SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
15938 SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
15939 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
15940 SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
15941 SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
15942 # ifdef SQLITE_ENABLE_SNAPSHOT
15943 SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
15944 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
15945 SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
15946 SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
15947 SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
15948 # endif
15949 #endif
15950
15951 #if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
15952 SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
15953 SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
15954 #else
15955 # define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
15956 # define sqlite3PagerWalDb(x,y)
15957 #endif
15958
15959 #ifdef SQLITE_DIRECT_OVERFLOW_READ
15960 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
15961 #endif
15962
15963 #ifdef SQLITE_ENABLE_ZIPVFS
15964 SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
15965 #endif
15966
15967 /* Functions used to query pager state and configuration. */
15968 SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
15969 SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
15970 #ifdef SQLITE_DEBUG
15971 SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
15972 #endif
15973 SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
15974 SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
15975 SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
15976 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
15977 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
15978 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
15979 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
15980 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
15981 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
15982 SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
15983 SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
15984
15985 /* Functions used to truncate the database file. */
15986 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
15987
15988 SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
15989
15990 /* Functions to support testing and debugging. */
15991 #if !defined(NDEBUG) || defined(SQLITE_TEST)
15992 SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
15993 SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
15994 #endif
15995 #ifdef SQLITE_TEST
15996 SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
15997 SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
15998 void disable_simulated_io_errors(void);
15999 void enable_simulated_io_errors(void);
16000 #else
16001 # define disable_simulated_io_errors()
16002 # define enable_simulated_io_errors()
16003 #endif
16004
16005 #endif /* SQLITE_PAGER_H */
16006
16007 /************** End of pager.h ***********************************************/
16008 /************** Continuing where we left off in sqliteInt.h ******************/
16009 /************** Include pcache.h in the middle of sqliteInt.h ****************/
16010 /************** Begin file pcache.h ******************************************/
16011 /*
16012 ** 2008 August 05
@@ -16843,11 +16852,11 @@
16843 int nChange; /* Value returned by sqlite3_changes() */
16844 int nTotalChange; /* Value returned by sqlite3_total_changes() */
16845 int aLimit[SQLITE_N_LIMIT]; /* Limits */
16846 int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
16847 struct sqlite3InitInfo { /* Information used during initialization */
16848 int newTnum; /* Rootpage of table being initialized */
16849 u8 iDb; /* Which db file is being initialized */
16850 u8 busy; /* TRUE if currently initializing */
16851 unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
16852 unsigned imposterTable : 1; /* Building an imposter table */
16853 unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
@@ -16858,11 +16867,14 @@
16858 int nVdbeWrite; /* Number of active VDBEs that read and write */
16859 int nVdbeExec; /* Number of nested calls to VdbeExec() */
16860 int nVDestroy; /* Number of active OP_VDestroy operations */
16861 int nExtension; /* Number of loaded extensions */
16862 void **aExtension; /* Array of shared library handles */
16863 int (*xTrace)(u32,void*,void*,void*); /* Trace function */
 
 
 
16864 void *pTraceArg; /* Argument to the trace function */
16865 #ifndef SQLITE_OMIT_DEPRECATED
16866 void (*xProfile)(void*,const char*,u64); /* Profiling function */
16867 void *pProfileArg; /* Argument to profile function */
16868 #endif
@@ -17482,11 +17494,11 @@
17482 Select *pSelect; /* NULL for tables. Points to definition if a view. */
17483 FKey *pFKey; /* Linked list of all foreign keys in this table */
17484 char *zColAff; /* String defining the affinity of each column */
17485 ExprList *pCheck; /* All CHECK constraints */
17486 /* ... also used as column name list in a VIEW */
17487 int tnum; /* Root BTree page for this table */
17488 u32 nTabRef; /* Number of pointers to this Table */
17489 u32 tabFlags; /* Mask of TF_* values */
17490 i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
17491 i16 nCol; /* Number of columns in this table */
17492 i16 nNVCol; /* Number of columns that are not VIRTUAL */
@@ -17775,11 +17787,11 @@
17775 Schema *pSchema; /* Schema containing this index */
17776 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
17777 const char **azColl; /* Array of collation sequence names for index */
17778 Expr *pPartIdxWhere; /* WHERE clause for partial indices */
17779 ExprList *aColExpr; /* Column expressions */
17780 int tnum; /* DB Page containing root of this index */
17781 LogEst szIdxRow; /* Estimated average row size in bytes */
17782 u16 nKeyCol; /* Number of columns forming the key */
17783 u16 nColumn; /* Number of columns stored in the index */
17784 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
17785 unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
@@ -17901,15 +17913,10 @@
17901 int nFunc; /* Number of entries in aFunc[] */
17902 u32 selId; /* Select to which this AggInfo belongs */
17903 AggInfo *pNext; /* Next in list of them all */
17904 };
17905
17906 /*
17907 ** Value for AggInfo.iAggMagic when the structure is valid
17908 */
17909 #define AggInfoMagic 0x2059e99e
17910
17911 /*
17912 ** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
17913 ** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
17914 ** than 32767 we have to make it 32-bit. 16-bit is preferred because
17915 ** it uses less memory in the Expr object, which is a big memory user
@@ -18744,13 +18751,11 @@
18744
18745 Token sLastToken; /* The last token parsed */
18746 ynVar nVar; /* Number of '?' variables seen in the SQL so far */
18747 u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
18748 u8 explain; /* True if the EXPLAIN flag is found on the query */
18749 #if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
18750 u8 eParseMode; /* PARSE_MODE_XXX constant */
18751 #endif
18752 #ifndef SQLITE_OMIT_VIRTUALTABLE
18753 int nVtabLock; /* Number of virtual tables to lock */
18754 #endif
18755 int nHeight; /* Expression tree height of current sub-select */
18756 #ifndef SQLITE_OMIT_EXPLAIN
@@ -18990,10 +18995,11 @@
18990 char **pzErrMsg; /* Error message stored here */
18991 int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
18992 int rc; /* Result code stored here */
18993 u32 mInitFlags; /* Flags controlling error messages */
18994 u32 nInitRow; /* Number of rows processed */
 
18995 } InitData;
18996
18997 /*
18998 ** Allowed values for mInitFlags
18999 */
@@ -19823,12 +19829,14 @@
19823 SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
19824 SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
19825 SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
19826 SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
19827 SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
 
19828 SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
19829 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
 
19830 SQLITE_PRIVATE int sqlite3Atoi(const char*);
19831 #ifndef SQLITE_OMIT_UTF16
19832 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
19833 #endif
19834 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
@@ -19944,19 +19952,19 @@
19944 SQLITE_PRIVATE const char sqlite3StrBINARY[];
19945 SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
19946 SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
19947 SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
19948 SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
19949 SQLITE_PRIVATE u32 sqlite3SelectTrace;
19950 #ifndef SQLITE_OMIT_WSD
19951 SQLITE_PRIVATE int sqlite3PendingByte;
19952 #endif
19953 #endif /* SQLITE_AMALGAMATION */
19954 #ifdef VDBE_PROFILE
19955 SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt;
19956 #endif
19957 SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int);
19958 SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
19959 SQLITE_PRIVATE void sqlite3AlterFunctions(void);
19960 SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
19961 SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
19962 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
@@ -20066,11 +20074,11 @@
20066 #else
20067 # define sqlite3CloseExtensions(X)
20068 #endif
20069
20070 #ifndef SQLITE_OMIT_SHARED_CACHE
20071 SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *);
20072 #else
20073 #define sqlite3TableLock(v,w,x,y,z)
20074 #endif
20075
20076 #ifdef SQLITE_TEST
@@ -20661,11 +20669,11 @@
20661 #endif
20662
20663 /*
20664 ** Flags for select tracing and the ".selecttrace" macro of the CLI
20665 */
20666 /**/ u32 sqlite3SelectTrace = 0;
20667
20668 /* #include "opcodes.h" */
20669 /*
20670 ** Properties of opcodes. The OPFLG_INITIALIZER macro is
20671 ** created by mkopcodeh.awk during compilation. Data is obtained
@@ -20788,11 +20796,11 @@
20788 Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
20789 Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
20790 Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
20791 Btree *pBtx; /* Separate file holding temporary table */
20792 i64 seqCount; /* Sequence counter */
20793 int *aAltMap; /* Mapping from table to index column numbers */
20794
20795 /* Cached OP_Column parse information is only valid if cacheStatus matches
20796 ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
20797 ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
20798 ** the cache is out of date. */
@@ -21184,11 +21192,11 @@
21184 */
21185 SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
21186 SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
21187 void sqliteVdbePopStack(Vdbe*,int);
21188 SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
21189 SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
21190 SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
21191 SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
21192 SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
21193 SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
21194 SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
@@ -21660,11 +21668,11 @@
21660 ** pagers the database handle is connected to. *pHighwater is always set
21661 ** to zero.
21662 */
21663 case SQLITE_DBSTATUS_CACHE_SPILL:
21664 op = SQLITE_DBSTATUS_CACHE_WRITE+1;
21665 /* Fall through into the next case */
21666 case SQLITE_DBSTATUS_CACHE_HIT:
21667 case SQLITE_DBSTATUS_CACHE_MISS:
21668 case SQLITE_DBSTATUS_CACHE_WRITE:{
21669 int i;
21670 int nRet = 0;
@@ -22816,12 +22824,12 @@
22816 break;
22817 }
22818 case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
22819 case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
22820 case 's': {
22821 sqlite3_snprintf(30,&z[j],"%lld",
22822 (i64)(x.iJD/1000 - 21086676*(i64)10000));
22823 j += sqlite3Strlen30(&z[j]);
22824 break;
22825 }
22826 case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
22827 case 'w': {
@@ -28537,15 +28545,15 @@
28537 assert( precision>=(-1) );
28538 switch( xtype ){
28539 case etPOINTER:
28540 flag_long = sizeof(char*)==sizeof(i64) ? 2 :
28541 sizeof(char*)==sizeof(long int) ? 1 : 0;
28542 /* Fall through into the next case */
28543 case etORDINAL:
28544 case etRADIX:
28545 cThousand = 0;
28546 /* Fall through into the next case */
28547 case etDECIMAL:
28548 if( infop->flags & FLAG_SIGNED ){
28549 i64 v;
28550 if( bArgList ){
28551 v = getIntArg(pArgList);
@@ -31770,10 +31778,34 @@
31770 #endif /* SQLITE_OMIT_FLOATING_POINT */
31771 }
31772 #if defined(_MSC_VER)
31773 #pragma warning(default : 4756)
31774 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31775
31776 /*
31777 ** Compare the 19-character string zNum against the text representation
31778 ** value 2^63: 9223372036854775808. Return negative, zero, or positive
31779 ** if zNum is less than, equal to, or greater than the string.
@@ -32011,13 +32043,31 @@
32011 ** Return a 32-bit integer value extracted from a string. If the
32012 ** string is not an integer, just return 0.
32013 */
32014 SQLITE_PRIVATE int sqlite3Atoi(const char *z){
32015 int x = 0;
32016 if( z ) sqlite3GetInt32(z, &x);
32017 return x;
32018 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32019
32020 /*
32021 ** The variable-length integer encoding is as follows:
32022 **
32023 ** KEY:
@@ -39188,11 +39238,11 @@
39188 }
39189 #endif
39190 if( rc!=SQLITE_OK ){
39191 if( h>=0 ) robust_close(pNew, h, __LINE__);
39192 }else{
39193 pNew->pMethod = pLockingStyle;
39194 OpenCounter(+1);
39195 verifyDbFile(pNew);
39196 }
39197 return rc;
39198 }
@@ -46899,11 +46949,11 @@
46899 {
46900 sqlite3_free(zConverted);
46901 }
46902
46903 sqlite3_free(zTmpname);
46904 pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
46905 pFile->pVfs = pVfs;
46906 pFile->h = h;
46907 if( isReadonly ){
46908 pFile->ctrlFlags |= WINFILE_RDONLY;
46909 }
@@ -48125,11 +48175,11 @@
48125 }
48126 memset(p, 0, sizeof(*p));
48127 p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
48128 assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
48129 *pOutFlags = flags | SQLITE_OPEN_MEMORY;
48130 p->base.pMethods = &memdb_io_methods;
48131 p->szMax = sqlite3GlobalConfig.mxMemdbSize;
48132 return SQLITE_OK;
48133 }
48134
48135 #if 0 /* Only used to delete rollback journals, super-journals, and WAL
@@ -52442,15 +52492,10 @@
52442 # define USEFETCH(x) ((x)->bUseFetch)
52443 #else
52444 # define USEFETCH(x) 0
52445 #endif
52446
52447 /*
52448 ** The maximum legal page number is (2^31 - 1).
52449 */
52450 #define PAGER_MAX_PGNO 2147483647
52451
52452 /*
52453 ** The argument to this macro is a file descriptor (type sqlite3_file*).
52454 ** Return 0 if it is not open, or non-zero (but not 1) if it is.
52455 **
52456 ** This is so that expressions can be written as:
@@ -54153,16 +54198,17 @@
54153
54154 /* Allocate space for both the pJournal and pSuper file descriptors.
54155 ** If successful, open the super-journal file for reading.
54156 */
54157 pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
54158 pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
54159 if( !pSuper ){
54160 rc = SQLITE_NOMEM_BKPT;
 
54161 }else{
54162 const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
54163 rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
 
54164 }
54165 if( rc!=SQLITE_OK ) goto delsuper_out;
54166
54167 /* Load the entire super-journal file into space obtained from
54168 ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
@@ -55419,11 +55465,11 @@
55419 ** Make no changes if mxPage is zero or negative. And never reduce the
55420 ** maximum page count below the current size of the database.
55421 **
55422 ** Regardless of mxPage, return the current maximum page count.
55423 */
55424 SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
55425 if( mxPage>0 ){
55426 pPager->mxPgno = mxPage;
55427 }
55428 assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
55429 /* assert( pPager->mxPgno>=pPager->dbSize ); */
@@ -57146,22 +57192,22 @@
57146
57147 noContent = (flags & PAGER_GET_NOCONTENT)!=0;
57148 if( pPg->pPager && !noContent ){
57149 /* In this case the pcache already contains an initialized copy of
57150 ** the page. Return without further ado. */
57151 assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
57152 pPager->aStat[PAGER_STAT_HIT]++;
57153 return SQLITE_OK;
57154
57155 }else{
57156 /* The pager cache has created a new page. Its content needs to
57157 ** be initialized. But first some error checks:
57158 **
57159 ** (1) The maximum page number is 2^31
57160 ** (2) Never try to fetch the locking page
57161 */
57162 if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
57163 rc = SQLITE_CORRUPT_BKPT;
57164 goto pager_acquire_err;
57165 }
57166
57167 pPg->pPager = pPager;
@@ -59863,11 +59909,11 @@
59863 ** walIteratorFree() - Free an iterator.
59864 **
59865 ** This functionality is used by the checkpoint code (see walCheckpoint()).
59866 */
59867 struct WalIterator {
59868 int iPrior; /* Last result returned from the iterator */
59869 int nSegment; /* Number of entries in aSegment[] */
59870 struct WalSegment {
59871 int iNext; /* Next slot in aIndex[] not yet returned */
59872 ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
59873 u32 *aPgno; /* Array of page numbers. */
@@ -59945,11 +59991,13 @@
59945 rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
59946 pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
59947 );
59948 assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
59949 testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
59950 if( (rc&0xff)==SQLITE_READONLY ){
 
 
59951 pWal->readOnly |= WAL_SHM_RDONLY;
59952 if( rc==SQLITE_READONLY ){
59953 rc = SQLITE_OK;
59954 }
59955 }
@@ -60320,10 +60368,11 @@
60320 && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
60321 && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
60322 && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
60323 && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
60324 );
 
60325 return iHash;
60326 }
60327
60328 /*
60329 ** Return the page number associated with frame iFrame in this WAL.
@@ -60516,16 +60565,10 @@
60516 assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
60517 assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
60518 assert( pWal->writeLock );
60519 iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
60520 rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
60521 if( rc==SQLITE_OK ){
60522 rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
60523 if( rc!=SQLITE_OK ){
60524 walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
60525 }
60526 }
60527 if( rc ){
60528 return rc;
60529 }
60530
60531 WALTRACE(("WAL%p: recovery begin...\n", pWal));
@@ -60537,19 +60580,20 @@
60537 goto recovery_error;
60538 }
60539
60540 if( nSize>WAL_HDRSIZE ){
60541 u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
 
60542 u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
60543 int szFrame; /* Number of bytes in buffer aFrame[] */
60544 u8 *aData; /* Pointer to data part of aFrame buffer */
60545 int iFrame; /* Index of last frame read */
60546 i64 iOffset; /* Next offset to read from log file */
60547 int szPage; /* Page size according to the log */
60548 u32 magic; /* Magic value read from WAL header */
60549 u32 version; /* Magic value read from WAL header */
60550 int isValid; /* True if this frame is valid */
 
 
60551
60552 /* Read in the WAL header. */
60553 rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
60554 if( rc!=SQLITE_OK ){
60555 goto recovery_error;
@@ -60592,42 +60636,86 @@
60592 goto finished;
60593 }
60594
60595 /* Malloc a buffer to read frames into. */
60596 szFrame = szPage + WAL_FRAME_HDRSIZE;
60597 aFrame = (u8 *)sqlite3_malloc64(szFrame);
60598 if( !aFrame ){
60599 rc = SQLITE_NOMEM_BKPT;
60600 goto recovery_error;
60601 }
60602 aData = &aFrame[WAL_FRAME_HDRSIZE];
 
60603
60604 /* Read all frames from the log file. */
60605 iFrame = 0;
60606 for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
60607 u32 pgno; /* Database page number for frame */
60608 u32 nTruncate; /* dbsize field from frame header */
60609
60610 /* Read and decode the next log frame. */
60611 iFrame++;
60612 rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
60613 if( rc!=SQLITE_OK ) break;
60614 isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
60615 if( !isValid ) break;
60616 rc = walIndexAppend(pWal, iFrame, pgno);
60617 if( rc!=SQLITE_OK ) break;
60618
60619 /* If nTruncate is non-zero, this is a commit record. */
60620 if( nTruncate ){
60621 pWal->hdr.mxFrame = iFrame;
60622 pWal->hdr.nPage = nTruncate;
60623 pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
60624 testcase( szPage<=32768 );
60625 testcase( szPage>=65536 );
60626 aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
60627 aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
60628 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60629 }
60630
60631 sqlite3_free(aFrame);
60632 }
60633
@@ -60638,19 +60726,30 @@
60638 pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
60639 pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
60640 walIndexWriteHdr(pWal);
60641
60642 /* Reset the checkpoint-header. This is safe because this thread is
60643 ** currently holding locks that exclude all other readers, writers and
60644 ** checkpointers.
60645 */
60646 pInfo = walCkptInfo(pWal);
60647 pInfo->nBackfill = 0;
60648 pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
60649 pInfo->aReadMark[0] = 0;
60650 for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
60651 if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
 
 
 
 
 
 
 
 
 
 
 
60652
60653 /* If more than one frame was recovered from the log file, report an
60654 ** event via sqlite3_log(). This is to help with identifying performance
60655 ** problems caused by applications routinely shutting down without
60656 ** checkpointing the log file.
@@ -60664,11 +60763,10 @@
60664 }
60665
60666 recovery_error:
60667 WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
60668 walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
60669 walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
60670 return rc;
60671 }
60672
60673 /*
60674 ** Close an open wal-index.
@@ -61312,14 +61410,22 @@
61312 i64 nReq = ((i64)mxPage * szPage);
61313 i64 nSize; /* Current size of database file */
61314 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
61315 rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
61316 if( rc==SQLITE_OK && nSize<nReq ){
61317 sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
 
 
 
 
 
 
 
 
61318 }
 
61319 }
61320
61321
61322 /* Iterate through the contents of the WAL, copying data to the db file */
61323 while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
61324 i64 iOffset;
61325 assert( walFramePgno(pWal, iFrame)==iDbpage );
@@ -64048,11 +64154,12 @@
64048 Pgno nPage; /* Number of pages in the database */
64049 int mxErr; /* Stop accumulating errors when this reaches zero */
64050 int nErr; /* Number of messages written to zErrMsg so far */
64051 int bOomFault; /* A memory allocation error has occurred */
64052 const char *zPfx; /* Error message prefix */
64053 int v1, v2; /* Values for up to two %d fields in zPfx */
 
64054 StrAccum errMsg; /* Accumulate the error message text here */
64055 u32 *heap; /* Min-heap used for analyzing cell coverage */
64056 sqlite3 *db; /* Database connection running the check */
64057 };
64058
@@ -66513,16 +66620,15 @@
66513 /*
66514 ** Return the size of the database file in pages. If there is any kind of
66515 ** error, return ((unsigned int)-1).
66516 */
66517 static Pgno btreePagecount(BtShared *pBt){
66518 assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
66519 return pBt->nPage;
66520 }
66521 SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
66522 assert( sqlite3BtreeHoldsMutex(p) );
66523 return btreePagecount(p->pBt) & 0x7fffffff;
66524 }
66525
66526 /*
66527 ** Get a page from the pager and initialize it.
66528 **
@@ -67306,12 +67412,12 @@
67306 /*
67307 ** Set the maximum page count for a database if mxPage is positive.
67308 ** No changes are made if mxPage is 0 or negative.
67309 ** Regardless of the value of mxPage, return the maximum page count.
67310 */
67311 SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
67312 int n;
67313 sqlite3BtreeEnter(p);
67314 n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
67315 sqlite3BtreeLeave(p);
67316 return n;
67317 }
@@ -68746,11 +68852,11 @@
68746 ** It is assumed that the sqlite3BtreeCursorZero() has been called
68747 ** on pCur to initialize the memory space prior to invoking this routine.
68748 */
68749 static int btreeCursor(
68750 Btree *p, /* The btree */
68751 int iTable, /* Root page of table to open */
68752 int wrFlag, /* 1 to write. 0 read-only */
68753 struct KeyInfo *pKeyInfo, /* First arg to comparison function */
68754 BtCursor *pCur /* Space for new cursor */
68755 ){
68756 BtShared *pBt = p->pBt; /* Shared b-tree handle */
@@ -68789,21 +68895,21 @@
68789 }
68790 }
68791
68792 /* Now that no other errors can occur, finish filling in the BtCursor
68793 ** variables and link the cursor into the BtShared list. */
68794 pCur->pgnoRoot = (Pgno)iTable;
68795 pCur->iPage = -1;
68796 pCur->pKeyInfo = pKeyInfo;
68797 pCur->pBtree = p;
68798 pCur->pBt = pBt;
68799 pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
68800 pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
68801 /* If there are two or more cursors on the same btree, then all such
68802 ** cursors *must* have the BTCF_Multiple flag set. */
68803 for(pX=pBt->pCursor; pX; pX=pX->pNext){
68804 if( pX->pgnoRoot==(Pgno)iTable ){
68805 pX->curFlags |= BTCF_Multiple;
68806 pCur->curFlags |= BTCF_Multiple;
68807 }
68808 }
68809 pCur->pNext = pBt->pCursor;
@@ -68811,11 +68917,11 @@
68811 pCur->eState = CURSOR_INVALID;
68812 return SQLITE_OK;
68813 }
68814 static int btreeCursorWithLock(
68815 Btree *p, /* The btree */
68816 int iTable, /* Root page of table to open */
68817 int wrFlag, /* 1 to write. 0 read-only */
68818 struct KeyInfo *pKeyInfo, /* First arg to comparison function */
68819 BtCursor *pCur /* Space for new cursor */
68820 ){
68821 int rc;
@@ -68824,11 +68930,11 @@
68824 sqlite3BtreeLeave(p);
68825 return rc;
68826 }
68827 SQLITE_PRIVATE int sqlite3BtreeCursor(
68828 Btree *p, /* The btree */
68829 int iTable, /* Root page of table to open */
68830 int wrFlag, /* 1 to write. 0 read-only */
68831 struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
68832 BtCursor *pCur /* Write new cursor here */
68833 ){
68834 if( p->sharable ){
@@ -69249,10 +69355,11 @@
69249 }
69250
69251 assert( rc==SQLITE_OK && amt>0 );
69252 while( nextPage ){
69253 /* If required, populate the overflow page-list cache. */
 
69254 assert( pCur->aOverflow[iIdx]==0
69255 || pCur->aOverflow[iIdx]==nextPage
69256 || CORRUPT_DB );
69257 pCur->aOverflow[iIdx] = nextPage;
69258
@@ -70664,10 +70771,14 @@
70664 */
70665 if( nFree!=0 ){
70666 u32 nLeaf; /* Initial number of leaf cells on trunk page */
70667
70668 iTrunk = get4byte(&pPage1->aData[32]);
 
 
 
 
70669 rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
70670 if( rc!=SQLITE_OK ){
70671 goto freepage_out;
70672 }
70673
@@ -73468,11 +73579,11 @@
73468 ** flags might not work:
73469 **
73470 ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
73471 ** BTREE_ZERODATA Used for SQL indices
73472 */
73473 static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
73474 BtShared *pBt = p->pBt;
73475 MemPage *pRoot;
73476 Pgno pgnoRoot;
73477 int rc;
73478 int ptfFlags; /* Page-type flage for the root page of new table */
@@ -73501,21 +73612,23 @@
73501 /* Read the value of meta[3] from the database to determine where the
73502 ** root page of the new table should go. meta[3] is the largest root-page
73503 ** created so far, so the new root-page is (meta[3]+1).
73504 */
73505 sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
 
 
 
73506 pgnoRoot++;
73507
73508 /* The new root-page may not be allocated on a pointer-map page, or the
73509 ** PENDING_BYTE page.
73510 */
73511 while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
73512 pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
73513 pgnoRoot++;
73514 }
73515 assert( pgnoRoot>=3 || CORRUPT_DB );
73516 testcase( pgnoRoot<3 );
73517
73518 /* Allocate a page. The page that currently resides at pgnoRoot will
73519 ** be moved to the allocated page (unless the allocated page happens
73520 ** to reside at pgnoRoot).
73521 */
@@ -73608,14 +73721,14 @@
73608 ptfFlags = PTF_ZERODATA | PTF_LEAF;
73609 }
73610 zeroPage(pRoot, ptfFlags);
73611 sqlite3PagerUnref(pRoot->pDbPage);
73612 assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
73613 *piTable = (int)pgnoRoot;
73614 return SQLITE_OK;
73615 }
73616 SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
73617 int rc;
73618 sqlite3BtreeEnter(p);
73619 rc = btreeCreateTable(p, piTable, flags);
73620 sqlite3BtreeLeave(p);
73621 return rc;
@@ -74095,11 +74208,11 @@
74095 ** Verify that the number of pages on the list is N.
74096 */
74097 static void checkList(
74098 IntegrityCk *pCheck, /* Integrity checking context */
74099 int isFreeList, /* True for a freelist. False for overflow page list */
74100 int iPage, /* Page number for first page in the list */
74101 u32 N /* Expected number of pages in the list */
74102 ){
74103 int i;
74104 u32 expected = N;
74105 int nErrAtStart = pCheck->nErr;
@@ -74227,11 +74340,11 @@
74227 ** 4. Recursively call checkTreePage on all children.
74228 ** 5. Verify that the depth of all children is the same.
74229 */
74230 static int checkTreePage(
74231 IntegrityCk *pCheck, /* Context for the sanity check */
74232 int iPage, /* Page number of the page to check */
74233 i64 *piMinKey, /* Write minimum integer primary key here */
74234 i64 maxKey /* Error if integer primary key greater than this */
74235 ){
74236 MemPage *pPage = 0; /* The page being analyzed */
74237 int i; /* Loop counter */
@@ -74263,13 +74376,13 @@
74263 */
74264 pBt = pCheck->pBt;
74265 usableSize = pBt->usableSize;
74266 if( iPage==0 ) return 0;
74267 if( checkRef(pCheck, iPage) ) return 0;
74268 pCheck->zPfx = "Page %d: ";
74269 pCheck->v1 = iPage;
74270 if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
74271 checkAppendMsg(pCheck,
74272 "unable to get the page. error code=%d", rc);
74273 goto end_of_check;
74274 }
74275
@@ -74290,11 +74403,11 @@
74290 }
74291 data = pPage->aData;
74292 hdr = pPage->hdrOffset;
74293
74294 /* Set up for cell analysis */
74295 pCheck->zPfx = "On tree page %d cell %d: ";
74296 contentOffset = get2byteNotZero(&data[hdr+5]);
74297 assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
74298
74299 /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
74300 ** number of cells on the page. */
@@ -74310,11 +74423,11 @@
74310 if( !pPage->leaf ){
74311 /* Analyze the right-child page of internal pages */
74312 pgno = get4byte(&data[hdr+8]);
74313 #ifndef SQLITE_OMIT_AUTOVACUUM
74314 if( pBt->autoVacuum ){
74315 pCheck->zPfx = "On page %d at right child: ";
74316 checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
74317 }
74318 #endif
74319 depth = checkTreePage(pCheck, pgno, &maxKey, maxKey);
74320 keyCanBeEqual = 0;
@@ -74451,11 +74564,11 @@
74451 nFrag = 0;
74452 prev = contentOffset - 1; /* Implied first min-heap entry */
74453 while( btreeHeapPull(heap,&x) ){
74454 if( (prev&0xffff)>=(x>>16) ){
74455 checkAppendMsg(pCheck,
74456 "Multiple uses for byte %u of page %d", x>>16, iPage);
74457 break;
74458 }else{
74459 nFrag += (x>>16) - (prev&0xffff) - 1;
74460 prev = x;
74461 }
@@ -74466,11 +74579,11 @@
74466 ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
74467 ** number of fragmented free bytes within the cell content area.
74468 */
74469 if( heap[0]==0 && nFrag!=data[hdr+7] ){
74470 checkAppendMsg(pCheck,
74471 "Fragmentation of %d bytes reported as %d on page %d",
74472 nFrag, data[hdr+7], iPage);
74473 }
74474 }
74475
74476 end_of_check:
@@ -74494,25 +74607,44 @@
74494 **
74495 ** Write the number of error seen in *pnErr. Except for some memory
74496 ** allocation errors, an error message held in memory obtained from
74497 ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
74498 ** returned. If a memory allocation error occurs, NULL is returned.
 
 
 
 
 
 
 
 
 
74499 */
74500 SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
74501 sqlite3 *db, /* Database connection that is running the check */
74502 Btree *p, /* The btree to be checked */
74503 int *aRoot, /* An array of root pages numbers for individual trees */
74504 int nRoot, /* Number of entries in aRoot[] */
74505 int mxErr, /* Stop reporting errors after this many */
74506 int *pnErr /* Write number of errors seen to this variable */
74507 ){
74508 Pgno i;
74509 IntegrityCk sCheck;
74510 BtShared *pBt = p->pBt;
74511 u64 savedDbFlags = pBt->db->flags;
74512 char zErr[100];
 
 
74513 VVA_ONLY( int nRef );
 
 
 
 
 
 
 
 
74514
74515 sqlite3BtreeEnter(p);
74516 assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
74517 VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
74518 assert( nRef>=0 );
@@ -74548,69 +74680,75 @@
74548 i = PENDING_BYTE_PAGE(pBt);
74549 if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
74550
74551 /* Check the integrity of the freelist
74552 */
74553 sCheck.zPfx = "Main freelist: ";
74554 checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
74555 get4byte(&pBt->pPage1->aData[36]));
74556 sCheck.zPfx = 0;
 
 
74557
74558 /* Check all the tables.
74559 */
74560 #ifndef SQLITE_OMIT_AUTOVACUUM
74561 if( pBt->autoVacuum ){
74562 int mx = 0;
74563 int mxInHdr;
74564 for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
74565 mxInHdr = get4byte(&pBt->pPage1->aData[52]);
74566 if( mx!=mxInHdr ){
74567 checkAppendMsg(&sCheck,
74568 "max rootpage (%d) disagrees with header (%d)",
74569 mx, mxInHdr
74570 );
74571 }
74572 }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
74573 checkAppendMsg(&sCheck,
74574 "incremental_vacuum enabled with a max rootpage of zero"
74575 );
 
 
74576 }
74577 #endif
74578 testcase( pBt->db->flags & SQLITE_CellSizeCk );
74579 pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
74580 for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
74581 i64 notUsed;
74582 if( aRoot[i]==0 ) continue;
74583 #ifndef SQLITE_OMIT_AUTOVACUUM
74584 if( pBt->autoVacuum && aRoot[i]>1 ){
74585 checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
74586 }
74587 #endif
74588 checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
74589 }
74590 pBt->db->flags = savedDbFlags;
74591
74592 /* Make sure every page in the file is referenced
74593 */
74594 for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
 
74595 #ifdef SQLITE_OMIT_AUTOVACUUM
74596 if( getPageReferenced(&sCheck, i)==0 ){
74597 checkAppendMsg(&sCheck, "Page %d is never used", i);
74598 }
74599 #else
74600 /* If the database supports auto-vacuum, make sure no tables contain
74601 ** references to pointer-map pages.
74602 */
74603 if( getPageReferenced(&sCheck, i)==0 &&
74604 (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
74605 checkAppendMsg(&sCheck, "Page %d is never used", i);
74606 }
74607 if( getPageReferenced(&sCheck, i)!=0 &&
74608 (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
74609 checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
74610 }
74611 #endif
 
74612 }
74613
74614 /* Clean up and report errors.
74615 */
74616 integrity_ck_cleanup:
@@ -75794,20 +75932,29 @@
75794 ** into a buffer.
75795 */
75796 static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
75797 StrAccum acc;
75798 assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
75799 sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
75800 if( p->flags & MEM_Int ){
75801 sqlite3_str_appendf(&acc, "%lld", p->u.i);
75802 }else if( p->flags & MEM_IntReal ){
75803 sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
 
 
 
 
 
 
 
75804 }else{
75805 sqlite3_str_appendf(&acc, "%!.15g", p->u.r);
 
 
 
 
75806 }
75807 assert( acc.zText==zBuf && acc.mxAlloc<=0 );
75808 zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
75809 }
75810
75811 #ifdef SQLITE_DEBUG
75812 /*
75813 ** Validity checks on pMem. pMem holds a string.
@@ -78397,11 +78544,11 @@
78397 /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
78398 ** cases from this switch! */
78399 switch( pOp->opcode ){
78400 case OP_Transaction: {
78401 if( pOp->p2!=0 ) p->readOnly = 0;
78402 /* fall thru */
78403 }
78404 case OP_AutoCommit:
78405 case OP_Savepoint: {
78406 p->bIsReader = 1;
78407 break;
@@ -78444,10 +78591,11 @@
78444 assert( (pOp - p->aOp) >= 3 );
78445 assert( pOp[-1].opcode==OP_Integer );
78446 n = pOp[-1].p1;
78447 if( n>nMaxArgs ) nMaxArgs = n;
78448 /* Fall through into the default case */
 
78449 }
78450 #endif
78451 default: {
78452 if( pOp->p2<0 ){
78453 /* The mkopcodeh.tcl script has so arranged things that the only
@@ -79301,16 +79449,16 @@
79301 sqlite3_str_appendf(&x, "vtab:%p", pVtab);
79302 break;
79303 }
79304 #endif
79305 case P4_INTARRAY: {
79306 int i;
79307 int *ai = pOp->p4.ai;
79308 int n = ai[0]; /* The first element of an INTARRAY is always the
79309 ** count of the number of elements to follow */
79310 for(i=1; i<=n; i++){
79311 sqlite3_str_appendf(&x, "%c%d", (i==1 ? '[' : ','), ai[i]);
79312 }
79313 sqlite3_str_append(&x, "]", 1);
79314 break;
79315 }
79316 case P4_SUBPROGRAM: {
@@ -81150,15 +81298,15 @@
81150 ** a NULL row.
81151 **
81152 ** If the cursor is already pointing to the correct row and that row has
81153 ** not been deleted out from under the cursor, then this routine is a no-op.
81154 */
81155 SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
81156 VdbeCursor *p = *pp;
81157 assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
81158 if( p->deferredMoveto ){
81159 int iMap;
81160 if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
81161 *pp = p->pAltCursor;
81162 *piCol = iMap - 1;
81163 return SQLITE_OK;
81164 }
@@ -82910,11 +83058,11 @@
82910 if( db->xProfile ){
82911 db->xProfile(db->pProfileArg, p->zSql, iElapse);
82912 }
82913 #endif
82914 if( db->mTrace & SQLITE_TRACE_PROFILE ){
82915 db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
82916 }
82917 p->startTime = 0;
82918 }
82919 /*
82920 ** The checkProfileCallback(DB,P) macro checks to see if a profile callback
@@ -86210,10 +86358,11 @@
86210 #ifdef SQLITE_DEBUG
86211 if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
86212 #endif
86213 if( (pIn3->flags & MEM_Null)==0 ) break;
86214 /* Fall through into OP_Halt */
 
86215 }
86216
86217 /* Opcode: Halt P1 P2 * P4 P5
86218 **
86219 ** Exit immediately. All open cursors, etc are closed
@@ -86380,10 +86529,11 @@
86380 goto too_big;
86381 }
86382 pOp->opcode = OP_String;
86383 assert( rc==SQLITE_OK );
86384 /* Fall through to the next case, OP_String */
 
86385 }
86386
86387 /* Opcode: String P1 P2 P3 P4 P5
86388 ** Synopsis: r[P2]='P4' (len=P1)
86389 **
@@ -86691,11 +86841,11 @@
86691 #endif
86692 }
86693 if( db->mallocFailed ) goto no_mem;
86694
86695 if( db->mTrace & SQLITE_TRACE_ROW ){
86696 db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
86697 }
86698
86699
86700 /* Return SQLITE_ROW
86701 */
@@ -87427,14 +87577,14 @@
87427 int n;
87428 int i;
87429 int p1;
87430 int p2;
87431 const KeyInfo *pKeyInfo;
87432 int idx;
87433 CollSeq *pColl; /* Collating sequence to use on this term */
87434 int bRev; /* True for DESCENDING sort order */
87435 int *aPermute; /* The permutation */
87436
87437 if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
87438 aPermute = 0;
87439 }else{
87440 assert( pOp>aOp );
@@ -87450,20 +87600,20 @@
87450 p1 = pOp->p1;
87451 p2 = pOp->p2;
87452 #ifdef SQLITE_DEBUG
87453 if( aPermute ){
87454 int k, mx = 0;
87455 for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
87456 assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
87457 assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
87458 }else{
87459 assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
87460 assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
87461 }
87462 #endif /* SQLITE_DEBUG */
87463 for(i=0; i<n; i++){
87464 idx = aPermute ? aPermute[i] : i;
87465 assert( memIsValid(&aMem[p1+idx]) );
87466 assert( memIsValid(&aMem[p2+idx]) );
87467 REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
87468 REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
87469 assert( i<pKeyInfo->nKeyField );
@@ -87770,11 +87920,11 @@
87770 ** the result is guaranteed to only be used as the argument of a length()
87771 ** or typeof() function, respectively. The loading of large blobs can be
87772 ** skipped for length() and all content loading can be skipped for typeof().
87773 */
87774 case OP_Column: {
87775 int p2; /* column number to retrieve */
87776 VdbeCursor *pC; /* The VDBE cursor */
87777 BtCursor *pCrsr; /* The BTree cursor */
87778 u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
87779 int len; /* The length of the serialized data for the column */
87780 int i; /* Loop counter */
@@ -87788,11 +87938,11 @@
87788 Mem *pReg; /* PseudoTable input register */
87789
87790 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
87791 pC = p->apCsr[pOp->p1];
87792 assert( pC!=0 );
87793 p2 = pOp->p2;
87794
87795 /* If the cursor cache is stale (meaning it is not currently point at
87796 ** the correct row) then bring it up-to-date by doing the necessary
87797 ** B-Tree seek. */
87798 rc = sqlite3VdbeCursorMoveto(&pC, &p2);
@@ -87800,11 +87950,11 @@
87800
87801 assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
87802 pDest = &aMem[pOp->p3];
87803 memAboutToChange(p, pDest);
87804 assert( pC!=0 );
87805 assert( p2<pC->nField );
87806 aOffset = pC->aOffset;
87807 assert( pC->eCurType!=CURTYPE_VTAB );
87808 assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
87809 assert( pC->eCurType!=CURTYPE_SORTER );
87810
@@ -87915,11 +88065,11 @@
87915 zHdr += sqlite3GetVarint32(zHdr, &t);
87916 pC->aType[i] = t;
87917 offset64 += sqlite3VdbeSerialTypeLen(t);
87918 }
87919 aOffset[++i] = (u32)(offset64 & 0xffffffff);
87920 }while( i<=p2 && zHdr<zEndHdr );
87921
87922 /* The record is corrupt if any of the following are true:
87923 ** (1) the bytes of the header extend past the declared header size
87924 ** (2) the entire header was used but not all data was used
87925 ** (3) the end of the data extends beyond the end of the record.
@@ -88939,11 +89089,11 @@
88939 ** See also: OP_OpenRead, OP_ReopenIdx
88940 */
88941 case OP_ReopenIdx: {
88942 int nField;
88943 KeyInfo *pKeyInfo;
88944 int p2;
88945 int iDb;
88946 int wrFlag;
88947 Btree *pX;
88948 VdbeCursor *pCur;
88949 Db *pDb;
@@ -88970,11 +89120,11 @@
88970 goto abort_due_to_error;
88971 }
88972
88973 nField = 0;
88974 pKeyInfo = 0;
88975 p2 = pOp->p2;
88976 iDb = pOp->p3;
88977 assert( iDb>=0 && iDb<db->nDb );
88978 assert( DbMaskTest(p->btreeMask, iDb) );
88979 pDb = &db->aDb[iDb];
88980 pX = pDb->pBt;
@@ -88989,11 +89139,11 @@
88989 }else{
88990 wrFlag = 0;
88991 }
88992 if( pOp->p5 & OPFLAG_P2ISREG ){
88993 assert( p2>0 );
88994 assert( p2<=(p->nMem+1 - p->nCursor) );
88995 assert( pOp->opcode==OP_OpenWrite );
88996 pIn2 = &aMem[p2];
88997 assert( memIsValid(pIn2) );
88998 assert( (pIn2->flags & MEM_Int)!=0 );
88999 sqlite3VdbeMemIntegerify(pIn2);
@@ -89142,11 +89292,11 @@
89142 ** opening it. If a transient table is required, just use the
89143 ** automatically created table with root-page 1 (an BLOB_INTKEY table).
89144 */
89145 if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
89146 assert( pOp->p4type==P4_KEYINFO );
89147 rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot,
89148 BTREE_BLOBKEY | pOp->p5);
89149 if( rc==SQLITE_OK ){
89150 assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
89151 assert( pKeyInfo->db==db );
89152 assert( pKeyInfo->enc==ENC(db) );
@@ -89684,10 +89834,11 @@
89684 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
89685 pC = p->apCsr[pOp->p1];
89686 assert( pC!=0 );
89687 if( pC->seekHit ) break;
89688 /* Fall through into OP_NotFound */
 
89689 }
89690 case OP_NoConflict: /* jump, in3 */
89691 case OP_NotFound: /* jump, in3 */
89692 case OP_Found: { /* jump, in3 */
89693 int alreadyExists;
@@ -89838,10 +89989,11 @@
89838 if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
89839 iKey = x.u.i;
89840 goto notExistsWithKey;
89841 }
89842 /* Fall through into OP_NotExists */
 
89843 case OP_NotExists: /* jump, in3 */
89844 pIn3 = &aMem[pOp->p3];
89845 assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
89846 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
89847 iKey = pIn3->u.i;
@@ -90406,14 +90558,10 @@
90406 ** generator) then the fix would be to insert a call to
90407 ** sqlite3VdbeCursorMoveto().
90408 */
90409 assert( pC->deferredMoveto==0 );
90410 assert( sqlite3BtreeCursorIsValid(pCrsr) );
90411 #if 0 /* Not required due to the previous to assert() statements */
90412 rc = sqlite3VdbeCursorMoveto(pC);
90413 if( rc!=SQLITE_OK ) goto abort_due_to_error;
90414 #endif
90415
90416 n = sqlite3BtreePayloadSize(pCrsr);
90417 if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
90418 goto too_big;
90419 }
@@ -90613,10 +90761,11 @@
90613 sqlite3_sort_count++;
90614 sqlite3_search_count--;
90615 #endif
90616 p->aCounter[SQLITE_STMTSTATUS_SORT]++;
90617 /* Fall through into OP_Rewind */
 
90618 }
90619 /* Opcode: Rewind P1 P2 * * *
90620 **
90621 ** The next use of the Rowid or Column or Next instruction for P1
90622 ** will refer to the first entry in the database table or index.
@@ -91179,11 +91328,11 @@
91179 sqlite3VdbeIncrWriteCounter(p, 0);
91180 nChange = 0;
91181 assert( p->readOnly==0 );
91182 assert( DbMaskTest(p->btreeMask, pOp->p2) );
91183 rc = sqlite3BtreeClearTable(
91184 db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
91185 );
91186 if( pOp->p3 ){
91187 p->nChange += nChange;
91188 if( pOp->p3>0 ){
91189 assert( memIsValid(&aMem[pOp->p3]) );
@@ -91228,11 +91377,11 @@
91228 ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
91229 ** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table.
91230 ** The root page number of the new b-tree is stored in register P2.
91231 */
91232 case OP_CreateBtree: { /* out2 */
91233 int pgno;
91234 Db *pDb;
91235
91236 sqlite3VdbeIncrWriteCounter(p, 0);
91237 pOut = out2Prerelease(p, pOp);
91238 pgno = 0;
@@ -91303,10 +91452,11 @@
91303 zSchema = DFLT_SCHEMA_TABLE;
91304 initData.db = db;
91305 initData.iDb = iDb;
91306 initData.pzErrMsg = &p->zErrMsg;
91307 initData.mInitFlags = 0;
 
91308 zSql = sqlite3MPrintf(db,
91309 "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
91310 db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
91311 if( zSql==0 ){
91312 rc = SQLITE_NOMEM_BKPT;
@@ -91416,20 +91566,20 @@
91416 **
91417 ** This opcode is used to implement the integrity_check pragma.
91418 */
91419 case OP_IntegrityCk: {
91420 int nRoot; /* Number of tables to check. (Number of root pages.) */
91421 int *aRoot; /* Array of rootpage numbers for tables to be checked */
91422 int nErr; /* Number of errors reported */
91423 char *z; /* Text of the error report */
91424 Mem *pnErr; /* Register keeping track of errors remaining */
91425
91426 assert( p->bIsReader );
91427 nRoot = pOp->p2;
91428 aRoot = pOp->p4.ai;
91429 assert( nRoot>0 );
91430 assert( aRoot[0]==nRoot );
91431 assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
91432 pnErr = &aMem[pOp->p3];
91433 assert( (pnErr->flags & MEM_Int)!=0 );
91434 assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
91435 pIn1 = &aMem[pOp->p1];
@@ -91965,10 +92115,11 @@
91965 /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
91966 assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
91967
91968 pOp->opcode = OP_AggStep1;
91969 /* Fall through into OP_AggStep */
 
91970 }
91971 case OP_AggStep1: {
91972 int i;
91973 sqlite3_context *pCtx;
91974 Mem *pMem;
@@ -92954,22 +93105,21 @@
92954 && !p->doingRerun
92955 && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
92956 ){
92957 #ifndef SQLITE_OMIT_DEPRECATED
92958 if( db->mTrace & SQLITE_TRACE_LEGACY ){
92959 void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
92960 char *z = sqlite3VdbeExpandSql(p, zTrace);
92961 x(db->pTraceArg, z);
92962 sqlite3_free(z);
92963 }else
92964 #endif
92965 if( db->nVdbeExec>1 ){
92966 char *z = sqlite3MPrintf(db, "-- %s", zTrace);
92967 (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
92968 sqlite3DbFree(db, z);
92969 }else{
92970 (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
92971 }
92972 }
92973 #ifdef SQLITE_USE_FCNTL_TRACE
92974 zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
92975 if( zTrace ){
@@ -96701,11 +96851,11 @@
96701 }else{
96702 if( i<=2 && pCur->zType==0 ){
96703 Schema *pSchema;
96704 HashElem *k;
96705 int iDb = pOp->p3;
96706 int iRoot = pOp->p2;
96707 sqlite3 *db = pVTab->db;
96708 pSchema = db->aDb[iDb].pSchema;
96709 pCur->zSchema = db->aDb[iDb].zDbSName;
96710 for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
96711 Table *pTab = (Table*)sqliteHashData(k);
@@ -97288,11 +97438,11 @@
97288 }else{
97289 p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
97290 assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
97291 }
97292
97293 p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
97294 p->nSpill = nSpill;
97295 p->flags = flags;
97296 p->zJournal = zName;
97297 p->pVfs = pVfs;
97298 return SQLITE_OK;
@@ -97314,11 +97464,11 @@
97314 ** file has not yet been created, create it now.
97315 */
97316 SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
97317 int rc = SQLITE_OK;
97318 MemJournal *p = (MemJournal*)pJfd;
97319 if( p->pMethod==&MemJournalMethods && (
97320 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
97321 p->nSpill>0
97322 #else
97323 /* While this appears to not be possible without ATOMIC_WRITE, the
97324 ** paths are complex, so it seems prudent to leave the test in as
@@ -98687,11 +98837,11 @@
98687 pExpr->op2 = pExpr->op;
98688 pExpr->op = TK_TRUTH;
98689 return WRC_Continue;
98690 }
98691 }
98692 /* Fall thru */
98693 }
98694 case TK_BETWEEN:
98695 case TK_EQ:
98696 case TK_NE:
98697 case TK_LT:
@@ -101591,11 +101741,11 @@
101591 /* Convert "true" or "false" in a DEFAULT clause into the
101592 ** appropriate TK_TRUEFALSE operator */
101593 if( sqlite3ExprIdToTrueFalse(pExpr) ){
101594 return WRC_Prune;
101595 }
101596 /* Fall thru */
101597 case TK_COLUMN:
101598 case TK_AGG_FUNCTION:
101599 case TK_AGG_COLUMN:
101600 testcase( pExpr->op==TK_ID );
101601 testcase( pExpr->op==TK_COLUMN );
@@ -101605,11 +101755,11 @@
101605 return WRC_Continue;
101606 }
101607 if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
101608 return WRC_Continue;
101609 }
101610 /* Fall through */
101611 case TK_IF_NULL_ROW:
101612 case TK_REGISTER:
101613 case TK_DOT:
101614 testcase( pExpr->op==TK_REGISTER );
101615 testcase( pExpr->op==TK_IF_NULL_ROW );
@@ -101626,11 +101776,11 @@
101626 /* A bound parameter in a CREATE statement that originates from
101627 ** sqlite3_prepare() causes an error */
101628 pWalker->eCode = 0;
101629 return WRC_Abort;
101630 }
101631 /* Fall through */
101632 default:
101633 testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
101634 testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
101635 return WRC_Continue;
101636 }
@@ -103398,10 +103548,11 @@
103398 }
103399 }
103400 return target;
103401 }
103402 /* Otherwise, fall thru into the TK_COLUMN case */
 
103403 }
103404 case TK_COLUMN: {
103405 int iTab = pExpr->iTable;
103406 int iReg;
103407 if( ExprHasProperty(pExpr, EP_FixedCol) ){
@@ -104463,11 +104614,11 @@
104463 case TK_ISNOT:
104464 testcase( op==TK_IS );
104465 testcase( op==TK_ISNOT );
104466 op = (op==TK_IS) ? TK_EQ : TK_NE;
104467 jumpIfNull = SQLITE_NULLEQ;
104468 /* Fall thru */
104469 case TK_LT:
104470 case TK_LE:
104471 case TK_GT:
104472 case TK_GE:
104473 case TK_NE:
@@ -104639,11 +104790,11 @@
104639 case TK_ISNOT:
104640 testcase( pExpr->op==TK_IS );
104641 testcase( pExpr->op==TK_ISNOT );
104642 op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
104643 jumpIfNull = SQLITE_NULLEQ;
104644 /* Fall thru */
104645 case TK_LT:
104646 case TK_LE:
104647 case TK_GT:
104648 case TK_GE:
104649 case TK_NE:
@@ -104951,17 +105102,17 @@
104951 case TK_BITOR:
104952 case TK_LSHIFT:
104953 case TK_RSHIFT:
104954 case TK_CONCAT:
104955 seenNot = 1;
104956 /* Fall thru */
104957 case TK_STAR:
104958 case TK_REM:
104959 case TK_BITAND:
104960 case TK_SLASH: {
104961 if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
104962 /* Fall thru into the next case */
104963 }
104964 case TK_SPAN:
104965 case TK_COLLATE:
104966 case TK_UPLUS:
104967 case TK_UMINUS: {
@@ -105106,10 +105257,11 @@
105106 || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0)
105107 && IsVirtual(pRight->y.pTab))
105108 ){
105109 return WRC_Prune;
105110 }
 
105111 }
105112 default:
105113 return WRC_Continue;
105114 }
105115 }
@@ -106839,11 +106991,11 @@
106839 }
106840 if( rc==SQLITE_OK && pStep->zTarget ){
106841 SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
106842 if( pSrc ){
106843 int i;
106844 for(i=0; i<pSrc->nSrc; i++){
106845 struct SrcList_item *p = &pSrc->a[i];
106846 p->pTab = sqlite3LocateTableItem(pParse, 0, p);
106847 p->iCursor = pParse->nTab++;
106848 if( p->pTab==0 ){
106849 rc = SQLITE_ERROR;
@@ -107581,11 +107733,11 @@
107581 };
107582 int i;
107583 sqlite3 *db = pParse->db;
107584 Db *pDb;
107585 Vdbe *v = sqlite3GetVdbe(pParse);
107586 int aRoot[ArraySize(aTable)];
107587 u8 aCreateTbl[ArraySize(aTable)];
107588 #ifdef SQLITE_ENABLE_STAT4
107589 const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
107590 #else
107591 const int nToOpen = 1;
@@ -107610,11 +107762,11 @@
107610 ** of the new table in register pParse->regRoot. This is important
107611 ** because the OpenWrite opcode below will be needing it. */
107612 sqlite3NestedParse(pParse,
107613 "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
107614 );
107615 aRoot[i] = pParse->regRoot;
107616 aCreateTbl[i] = OPFLAG_P2ISREG;
107617 }
107618 }else{
107619 /* The table already exists. If zWhere is not NULL, delete all entries
107620 ** associated with the table zWhere. If zWhere is NULL, delete the
@@ -107630,19 +107782,19 @@
107630 }else if( db->xPreUpdateCallback ){
107631 sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
107632 #endif
107633 }else{
107634 /* The sqlite_stat[134] table already exists. Delete all rows. */
107635 sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
107636 }
107637 }
107638 }
107639
107640 /* Open the sqlite_stat[134] tables for writing. */
107641 for(i=0; i<nToOpen; i++){
107642 assert( i<ArraySize(aTable) );
107643 sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
107644 sqlite3VdbeChangeP5(v, aCreateTbl[i]);
107645 VdbeComment((v, aTable[i].zName));
107646 }
107647 }
107648
@@ -110271,11 +110423,11 @@
110271 ** The TableLock structure is only used by the sqlite3TableLock() and
110272 ** codeTableLocks() functions.
110273 */
110274 struct TableLock {
110275 int iDb; /* The database containing the table to be locked */
110276 int iTab; /* The root page of the table to be locked */
110277 u8 isWriteLock; /* True for write lock. False for a read lock */
110278 const char *zLockName; /* Name of the table */
110279 };
110280
110281 /*
@@ -110289,11 +110441,11 @@
110289 ** codeTableLocks() which occurs during sqlite3FinishCoding().
110290 */
110291 SQLITE_PRIVATE void sqlite3TableLock(
110292 Parse *pParse, /* Parsing context */
110293 int iDb, /* Index of the database containing the table to lock */
110294 int iTab, /* Root page number of the table to be locked */
110295 u8 isWriteLock, /* True for a write lock */
110296 const char *zName /* Name of the table to be locked */
110297 ){
110298 Parse *pToplevel = sqlite3ParseToplevel(pParse);
110299 int i;
@@ -111128,23 +111280,24 @@
111128 const char *zName, /* Name of the object to check */
111129 const char *zType, /* Type of this object */
111130 const char *zTblName /* Parent table name for triggers and indexes */
111131 ){
111132 sqlite3 *db = pParse->db;
111133 if( sqlite3WritableSchema(db) || db->init.imposterTable ){
 
 
 
111134 /* Skip these error checks for writable_schema=ON */
111135 return SQLITE_OK;
111136 }
111137 if( db->init.busy ){
111138 if( sqlite3_stricmp(zType, db->init.azInit[0])
111139 || sqlite3_stricmp(zName, db->init.azInit[1])
111140 || sqlite3_stricmp(zTblName, db->init.azInit[2])
111141 ){
111142 if( sqlite3Config.bExtraSchemaChecks ){
111143 sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
111144 return SQLITE_ERROR;
111145 }
111146 }
111147 }else{
111148 if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
111149 || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
111150 ){
@@ -112354,11 +112507,11 @@
112354 ** table entry. This is only required if currently generating VDBE
112355 ** code for a CREATE TABLE (not when parsing one as part of reading
112356 ** a database schema). */
112357 if( v && pPk->tnum>0 ){
112358 assert( db->init.busy==0 );
112359 sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
112360 }
112361
112362 /* The root page of the PRIMARY KEY is the table root page */
112363 pPk->tnum = pTab->tnum;
112364
@@ -112942,14 +113095,12 @@
112942 ** statement that defines the view.
112943 */
112944 assert( pTable->pSelect );
112945 pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
112946 if( pSel ){
112947 #ifndef SQLITE_OMIT_ALTERTABLE
112948 u8 eParseMode = pParse->eParseMode;
112949 pParse->eParseMode = PARSE_MODE_NORMAL;
112950 #endif
112951 n = pParse->nTab;
112952 sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
112953 pTable->nCol = -1;
112954 DisableLookaside;
112955 #ifndef SQLITE_OMIT_AUTHORIZATION
@@ -112993,13 +113144,11 @@
112993 }
112994 pTable->nNVCol = pTable->nCol;
112995 sqlite3DeleteTable(db, pSelTab);
112996 sqlite3SelectDelete(db, pSel);
112997 EnableLookaside;
112998 #ifndef SQLITE_OMIT_ALTERTABLE
112999 pParse->eParseMode = eParseMode;
113000 #endif
113001 } else {
113002 nErr++;
113003 }
113004 pTable->pSchema->schemaFlags |= DB_UnresetViews;
113005 if( db->mallocFailed ){
@@ -113050,11 +113199,11 @@
113050 ** We must continue looping until all tables and indices with
113051 ** rootpage==iFrom have been converted to have a rootpage of iTo
113052 ** in order to be certain that we got the right one.
113053 */
113054 #ifndef SQLITE_OMIT_AUTOVACUUM
113055 SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
113056 HashElem *pElem;
113057 Hash *pHash;
113058 Db *pDb;
113059
113060 assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
@@ -113127,22 +113276,22 @@
113127 ** and root page 5 happened to be the largest root-page number in the
113128 ** database, then root page 5 would be moved to page 4 by the
113129 ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
113130 ** a free-list page.
113131 */
113132 int iTab = pTab->tnum;
113133 int iDestroyed = 0;
113134
113135 while( 1 ){
113136 Index *pIdx;
113137 int iLargest = 0;
113138
113139 if( iDestroyed==0 || iTab<iDestroyed ){
113140 iLargest = iTab;
113141 }
113142 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
113143 int iIdx = pIdx->tnum;
113144 assert( pIdx->pSchema==pTab->pSchema );
113145 if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
113146 iLargest = iIdx;
113147 }
113148 }
@@ -113561,11 +113710,11 @@
113561 int iTab = pParse->nTab++; /* Btree cursor used for pTab */
113562 int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
113563 int iSorter; /* Cursor opened by OpenSorter (if in use) */
113564 int addr1; /* Address of top of loop */
113565 int addr2; /* Address to jump to for next iteration */
113566 int tnum; /* Root page of index */
113567 int iPartIdxLabel; /* Jump to this label to skip a row */
113568 Vdbe *v; /* Generate code into this virtual machine */
113569 KeyInfo *pKey; /* KeyInfo for index */
113570 int regRecord; /* Register holding assembled index record */
113571 sqlite3 *db = pParse->db; /* The database connection */
@@ -113582,11 +113731,11 @@
113582 sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
113583
113584 v = sqlite3GetVdbe(pParse);
113585 if( v==0 ) return;
113586 if( memRootPage>=0 ){
113587 tnum = memRootPage;
113588 }else{
113589 tnum = pIndex->tnum;
113590 }
113591 pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
113592 assert( pKey!=0 || db->mallocFailed || pParse->nErr );
@@ -113607,11 +113756,11 @@
113607 sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
113608 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
113609 sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
113610 sqlite3VdbeJumpHere(v, addr1);
113611 if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
113612 sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
113613 (char *)pKey, P4_KEYINFO);
113614 sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
113615
113616 addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
113617 if( IsUniqueIndex(pIndex) ){
@@ -114216,11 +114365,11 @@
114216 ** doing so, code a Noop instruction and store its address in
114217 ** Index.tnum. This is required in case this index is actually a
114218 ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
114219 ** that case the convertToWithoutRowidTable() routine will replace
114220 ** the Noop with a Goto to jump over the VDBE code generated below. */
114221 pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
114222 sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
114223
114224 /* Gather the complete text of the CREATE INDEX statement into
114225 ** the zStmt variable
114226 */
@@ -114258,11 +114407,11 @@
114258 sqlite3VdbeAddParseSchemaOp(v, iDb,
114259 sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
114260 sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
114261 }
114262
114263 sqlite3VdbeJumpHere(v, pIndex->tnum);
114264 }
114265 }
114266 if( db->init.busy || pTblName==0 ){
114267 pIndex->pNext = pTab->pIndex;
114268 pTab->pIndex = pIndex;
@@ -114333,11 +114482,11 @@
114333 **
114334 ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
114335 ** table but other parts we are having to guess at, then do not let the
114336 ** estimated number of rows in the table be less than 1000 (LogEst 99).
114337 ** Failure to do this can cause the indexes for which we do not have
114338 ** stat1 data to be ignored by the query planner. tag-20200527-1
114339 */
114340 x = pIdx->pTable->nRowLogEst;
114341 assert( 99==sqlite3LogEst(1000) );
114342 if( x<99 ){
114343 pIdx->pTable->nRowLogEst = x = 99;
@@ -120309,10 +120458,11 @@
120309 case OE_Cascade:
120310 if( !pChanges ){
120311 pStep->op = TK_DELETE;
120312 break;
120313 }
 
120314 default:
120315 pStep->op = TK_UPDATE;
120316 }
120317 pStep->pTrig = pTrigger;
120318 pTrigger->pSchema = pTab->pSchema;
@@ -120581,11 +120731,11 @@
120581 for(i=1; i<iEnd; i++){
120582 VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
120583 assert( pOp!=0 );
120584 if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
120585 Index *pIndex;
120586 int tnum = pOp->p2;
120587 if( tnum==pTab->tnum ){
120588 return 1;
120589 }
120590 for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
120591 if( tnum==pIndex->tnum ){
@@ -122013,11 +122163,11 @@
122013 sqlite3VdbeJumpHere(v, addr1);
122014 break;
122015 }
122016 case OE_Abort:
122017 sqlite3MayAbort(pParse);
122018 /* Fall through */
122019 case OE_Rollback:
122020 case OE_Fail: {
122021 char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
122022 pCol->zName);
122023 sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
@@ -122241,11 +122391,11 @@
122241 VdbeCoverage(v);
122242
122243 switch( onError ){
122244 default: {
122245 onError = OE_Abort;
122246 /* Fall thru into the next case */
122247 }
122248 case OE_Rollback:
122249 case OE_Abort:
122250 case OE_Fail: {
122251 testcase( onError==OE_Rollback );
@@ -122302,11 +122452,11 @@
122302 break;
122303 }
122304 #ifndef SQLITE_OMIT_UPSERT
122305 case OE_Update: {
122306 sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
122307 /* Fall through */
122308 }
122309 #endif
122310 case OE_Ignore: {
122311 testcase( onError==OE_Ignore );
122312 sqlite3VdbeGoto(v, ignoreDest);
@@ -122523,11 +122673,11 @@
122523 break;
122524 }
122525 #ifndef SQLITE_OMIT_UPSERT
122526 case OE_Update: {
122527 sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
122528 /* Fall through */
122529 }
122530 #endif
122531 case OE_Ignore: {
122532 testcase( onError==OE_Ignore );
122533 sqlite3VdbeGoto(v, ignoreDest);
@@ -126204,17 +126354,23 @@
126204 **
126205 ** Return the number of pages in the specified database.
126206 */
126207 case PragTyp_PAGE_COUNT: {
126208 int iReg;
 
126209 sqlite3CodeVerifySchema(pParse, iDb);
126210 iReg = ++pParse->nMem;
126211 if( sqlite3Tolower(zLeft[0])=='p' ){
126212 sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
126213 }else{
126214 sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
126215 sqlite3AbsInt32(sqlite3Atoi(zRight)));
 
 
 
 
 
126216 }
126217 sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
126218 break;
126219 }
126220
@@ -127113,13 +127269,26 @@
127113 **
127114 ** The "quick_check" is reduced version of
127115 ** integrity_check designed to detect most database corruption
127116 ** without the overhead of cross-checking indexes. Quick_check
127117 ** is linear time wherease integrity_check is O(NlogN).
 
 
 
 
 
 
 
 
 
 
 
 
127118 */
127119 case PragTyp_INTEGRITY_CHECK: {
127120 int i, j, addr, mxErr;
 
127121
127122 int isQuick = (sqlite3Tolower(zLeft[0])=='q');
127123
127124 /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
127125 ** then iDb is set to the index of the database identified by <db>.
@@ -127138,13 +127307,17 @@
127138 pParse->nMem = 6;
127139
127140 /* Set the maximum error count */
127141 mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
127142 if( zRight ){
127143 sqlite3GetInt32(zRight, &mxErr);
127144 if( mxErr<=0 ){
127145 mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
 
 
 
 
127146 }
127147 }
127148 sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
127149
127150 /* Do an integrity check on each database file */
@@ -127169,19 +127342,25 @@
127169 pTbls = &db->aDb[i].pSchema->tblHash;
127170 for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
127171 Table *pTab = sqliteHashData(x); /* Current table */
127172 Index *pIdx; /* An index on pTab */
127173 int nIdx; /* Number of indexes on pTab */
 
127174 if( HasRowid(pTab) ) cnt++;
127175 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
127176 if( nIdx>mxIdx ) mxIdx = nIdx;
127177 }
 
 
127178 aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
127179 if( aRoot==0 ) break;
127180 for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
 
 
127181 Table *pTab = sqliteHashData(x);
127182 Index *pIdx;
 
127183 if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
127184 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
127185 aRoot[++cnt] = pIdx->tnum;
127186 }
127187 }
@@ -127211,10 +127390,11 @@
127211 int loopTop;
127212 int iDataCur, iIdxCur;
127213 int r1 = -1;
127214
127215 if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
 
127216 pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
127217 sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
127218 1, 0, &iDataCur, &iIdxCur);
127219 /* reg[7] counts the number of entries in the table.
127220 ** reg[8+i] counts the number of entries in the i-th index
@@ -128272,11 +128452,17 @@
128272 sqlite3_stmt *pStmt;
128273 TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
128274
128275 assert( db->init.busy );
128276 db->init.iDb = iDb;
128277 db->init.newTnum = sqlite3Atoi(argv[3]);
 
 
 
 
 
 
128278 db->init.orphanTrigger = 0;
128279 db->init.azInit = argv;
128280 pStmt = 0;
128281 TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
128282 rc = db->errCode;
@@ -128305,16 +128491,21 @@
128305 ** been created when we processed the CREATE TABLE. All we have
128306 ** to do here is record the root page number for that index.
128307 */
128308 Index *pIndex;
128309 pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
128310 if( pIndex==0
128311 || sqlite3GetInt32(argv[3],&pIndex->tnum)==0
 
 
128312 || pIndex->tnum<2
 
128313 || sqlite3IndexHasDuplicateRootPage(pIndex)
128314 ){
128315 corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
 
 
128316 }
128317 }
128318 return 0;
128319 }
128320
@@ -128364,10 +128555,11 @@
128364 initData.iDb = iDb;
128365 initData.rc = SQLITE_OK;
128366 initData.pzErrMsg = pzErrMsg;
128367 initData.mInitFlags = mFlags;
128368 initData.nInitRow = 0;
 
128369 sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
128370 db->mDbFlags &= mask;
128371 if( initData.rc ){
128372 rc = initData.rc;
128373 goto error_out;
@@ -128486,10 +128678,11 @@
128486 }
128487
128488 /* Read the schema information out of the schema tables
128489 */
128490 assert( db->init.busy );
 
128491 {
128492 char *zSql;
128493 zSql = sqlite3MPrintf(db,
128494 "SELECT*FROM\"%w\".%s ORDER BY rowid",
128495 db->aDb[iDb].zDbSName, zSchemaTabName);
@@ -129368,12 +129561,14 @@
129368 ** Return the index of a column in a table. Return -1 if the column
129369 ** is not contained in the table.
129370 */
129371 static int columnIndex(Table *pTab, const char *zCol){
129372 int i;
129373 for(i=0; i<pTab->nCol; i++){
129374 if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
 
 
129375 }
129376 return -1;
129377 }
129378
129379 /*
@@ -130231,20 +130426,24 @@
130231 sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
130232 break;
130233 }
130234
130235 case SRT_Upfrom: {
130236 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
130237 if( pSort ){
130238 pushOntoSorter(
130239 pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
130240 }else
130241 #endif
130242 {
130243 int i2 = pDest->iSDParm2;
130244 int r1 = sqlite3GetTempReg(pParse);
130245 sqlite3VdbeAddOp3(v, OP_MakeRecord,regResult+(i2<0),nResultCol-(i2<0),r1);
 
 
 
 
 
 
 
130246 if( i2<0 ){
130247 sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
130248 }else{
130249 sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
130250 }
@@ -130682,11 +130881,10 @@
130682 case SRT_Mem: {
130683 /* The LIMIT clause will terminate the loop for us */
130684 break;
130685 }
130686 #endif
130687 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
130688 case SRT_Upfrom: {
130689 int i2 = pDest->iSDParm2;
130690 int r1 = sqlite3GetTempReg(pParse);
130691 sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
130692 if( i2<0 ){
@@ -130694,11 +130892,10 @@
130694 }else{
130695 sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
130696 }
130697 break;
130698 }
130699 #endif
130700 default: {
130701 assert( eDest==SRT_Output || eDest==SRT_Coroutine );
130702 testcase( eDest==SRT_Output );
130703 testcase( eDest==SRT_Coroutine );
130704 if( eDest==SRT_Output ){
@@ -132281,11 +132478,11 @@
132281 KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
132282 KeyInfo *pKeyMerge; /* Comparison information for merging rows */
132283 sqlite3 *db; /* Database connection */
132284 ExprList *pOrderBy; /* The ORDER BY clause */
132285 int nOrderBy; /* Number of terms in the ORDER BY clause */
132286 int *aPermute; /* Mapping from ORDER BY terms to result set columns */
132287
132288 assert( p->pOrderBy!=0 );
132289 assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
132290 db = pParse->db;
132291 v = pParse->pVdbe;
@@ -132330,11 +132527,11 @@
132330 ** row of results comes from selectA or selectB. Also add explicit
132331 ** collations to the ORDER BY clause terms so that when the subqueries
132332 ** to the right and the left are evaluated, they use the correct
132333 ** collation.
132334 */
132335 aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
132336 if( aPermute ){
132337 struct ExprList_item *pItem;
132338 aPermute[0] = nOrderBy;
132339 for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
132340 assert( pItem->u.x.iOrderByCol>0 );
@@ -133286,11 +133483,11 @@
133286 sqlite3AggInfoPersistWalkerInit(&w, pParse);
133287 sqlite3WalkSelect(&w,pSub1);
133288 sqlite3SelectDelete(db, pSub1);
133289
133290 #if SELECTTRACE_ENABLED
133291 if( sqlite3SelectTrace & 0x100 ){
133292 SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
133293 sqlite3TreeViewSelect(0, p, 0);
133294 }
133295 #endif
133296
@@ -134724,11 +134921,11 @@
134724 sWalker.pParse = pParse;
134725 sWalker.xExprCallback = havingToWhereExprCb;
134726 sWalker.u.pSelect = p;
134727 sqlite3WalkExpr(&sWalker, p->pHaving);
134728 #if SELECTTRACE_ENABLED
134729 if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){
134730 SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
134731 sqlite3TreeViewSelect(0, p, 0);
134732 }
134733 #endif
134734 }
@@ -134846,11 +135043,11 @@
134846 }
134847 p->pEList->a[0].pExpr = pExpr;
134848 p->selFlags &= ~SF_Aggregate;
134849
134850 #if SELECTTRACE_ENABLED
134851 if( sqlite3SelectTrace & 0x400 ){
134852 SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
134853 sqlite3TreeViewSelect(0, p, 0);
134854 }
134855 #endif
134856 return 1;
@@ -134899,11 +135096,11 @@
134899 return 1;
134900 }
134901 if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
134902 #if SELECTTRACE_ENABLED
134903 SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
134904 if( sqlite3SelectTrace & 0x100 ){
134905 sqlite3TreeViewSelect(0, p, 0);
134906 }
134907 #endif
134908
134909 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
@@ -134926,11 +135123,11 @@
134926 if( pParse->nErr || db->mallocFailed ){
134927 goto select_end;
134928 }
134929 assert( p->pEList!=0 );
134930 #if SELECTTRACE_ENABLED
134931 if( sqlite3SelectTrace & 0x104 ){
134932 SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
134933 sqlite3TreeViewSelect(0, p, 0);
134934 }
134935 #endif
134936
@@ -134961,11 +135158,11 @@
134961 if( rc ){
134962 assert( db->mallocFailed || pParse->nErr>0 );
134963 goto select_end;
134964 }
134965 #if SELECTTRACE_ENABLED
134966 if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
134967 SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
134968 sqlite3TreeViewSelect(0, p, 0);
134969 }
134970 #endif
134971 #endif /* SQLITE_OMIT_WINDOWFUNC */
@@ -135068,11 +135265,11 @@
135068 */
135069 if( p->pPrior ){
135070 rc = multiSelect(pParse, p, pDest);
135071 #if SELECTTRACE_ENABLED
135072 SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
135073 if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
135074 sqlite3TreeViewSelect(0, p, 0);
135075 }
135076 #endif
135077 if( p->pNext==0 ) ExplainQueryPlanPop(pParse);
135078 return rc;
@@ -135087,11 +135284,11 @@
135087 if( pTabList->nSrc>1
135088 && OptimizationEnabled(db, SQLITE_PropagateConst)
135089 && propagateConstants(pParse, p)
135090 ){
135091 #if SELECTTRACE_ENABLED
135092 if( sqlite3SelectTrace & 0x100 ){
135093 SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
135094 sqlite3TreeViewSelect(0, p, 0);
135095 }
135096 #endif
135097 }else{
@@ -135175,11 +135372,11 @@
135175 if( OptimizationEnabled(db, SQLITE_PushDown)
135176 && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
135177 (pItem->fg.jointype & JT_OUTER)!=0)
135178 ){
135179 #if SELECTTRACE_ENABLED
135180 if( sqlite3SelectTrace & 0x100 ){
135181 SELECTTRACE(0x100,pParse,p,
135182 ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
135183 sqlite3TreeViewSelect(0, p, 0);
135184 }
135185 #endif
@@ -135275,11 +135472,11 @@
135275 pGroupBy = p->pGroupBy;
135276 pHaving = p->pHaving;
135277 sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
135278
135279 #if SELECTTRACE_ENABLED
135280 if( sqlite3SelectTrace & 0x400 ){
135281 SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
135282 sqlite3TreeViewSelect(0, p, 0);
135283 }
135284 #endif
135285
@@ -135311,11 +135508,11 @@
135311 ** the sDistinct.isTnct is still set. Hence, isTnct represents the
135312 ** original setting of the SF_Distinct flag, not the current setting */
135313 assert( sDistinct.isTnct );
135314
135315 #if SELECTTRACE_ENABLED
135316 if( sqlite3SelectTrace & 0x400 ){
135317 SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
135318 sqlite3TreeViewSelect(0, p, 0);
135319 }
135320 #endif
135321 }
@@ -135559,11 +135756,11 @@
135559 sNC.ncFlags &= ~NC_InAggFunc;
135560 }
135561 pAggInfo->mxReg = pParse->nMem;
135562 if( db->mallocFailed ) goto select_end;
135563 #if SELECTTRACE_ENABLED
135564 if( sqlite3SelectTrace & 0x400 ){
135565 int ii;
135566 SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
135567 sqlite3TreeViewSelect(0, p, 0);
135568 for(ii=0; ii<pAggInfo->nColumn; ii++){
135569 sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
@@ -135823,11 +136020,11 @@
135823 const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
135824 const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
135825 Index *pIdx; /* Iterator variable */
135826 KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
135827 Index *pBest = 0; /* Best index found so far */
135828 int iRoot = pTab->tnum; /* Root page of scanned b-tree */
135829
135830 sqlite3CodeVerifySchema(pParse, iDb);
135831 sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
135832
135833 /* Search for the index that has the lowest scan cost.
@@ -135855,11 +136052,11 @@
135855 iRoot = pBest->tnum;
135856 pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
135857 }
135858
135859 /* Open a read-only cursor, execute the OP_Count, close the cursor. */
135860 sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
135861 if( pKeyInfo ){
135862 sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
135863 }
135864 sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
135865 sqlite3VdbeAddOp1(v, OP_Close, iCsr);
@@ -135978,11 +136175,11 @@
135978 }
135979 #endif
135980
135981 #if SELECTTRACE_ENABLED
135982 SELECTTRACE(0x1,pParse,p,("end processing\n"));
135983 if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
135984 sqlite3TreeViewSelect(0, p, 0);
135985 }
135986 #endif
135987 ExplainQueryPlanPop(pParse);
135988 return rc;
@@ -142375,11 +142572,11 @@
142375 if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
142376 && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
142377 ){
142378 int i;
142379 Table *pTab = pIdx->pTable;
142380 int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
142381 if( ai ){
142382 ai[0] = pTab->nCol;
142383 for(i=0; i<pIdx->nColumn-1; i++){
142384 int x1, x2;
142385 assert( pIdx->aiColumn[i]<pTab->nCol );
@@ -151749,11 +151946,11 @@
151749 assert( pWin->pOwner==pExpr );
151750 return WRC_Prune;
151751 }
151752 }
151753 }
151754 /* Fall through. */
151755
151756 case TK_AGG_FUNCTION:
151757 case TK_COLUMN: {
151758 int iCol = -1;
151759 if( p->pSub ){
@@ -159966,10 +160163,11 @@
159966 *tokenType = TK_DOT;
159967 return 1;
159968 }
159969 /* If the next character is a digit, this is a floating point
159970 ** number that begins with ".". Fall thru into the next case */
 
159971 }
159972 case CC_DIGIT: {
159973 testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
159974 testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
159975 testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
@@ -160070,10 +160268,11 @@
160070 return i;
160071 }
160072 #endif
160073 /* If it is not a BLOB literal, then it must be an ID, since no
160074 ** SQL keywords start with the letter 'x'. Fall through */
 
160075 }
160076 case CC_ID: {
160077 i = 1;
160078 break;
160079 }
@@ -162000,11 +162199,11 @@
162000 if( !sqlite3SafetyCheckSickOrOk(db) ){
162001 return SQLITE_MISUSE_BKPT;
162002 }
162003 sqlite3_mutex_enter(db->mutex);
162004 if( db->mTrace & SQLITE_TRACE_CLOSE ){
162005 db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
162006 }
162007
162008 /* Force xDisconnect calls on all virtual tables */
162009 disconnectAllVtab(db);
162010
@@ -162889,11 +163088,11 @@
162889 }
162890 #endif
162891 sqlite3_mutex_enter(db->mutex);
162892 pOld = db->pTraceArg;
162893 db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
162894 db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
162895 db->pTraceArg = pArg;
162896 sqlite3_mutex_leave(db->mutex);
162897 return pOld;
162898 }
162899 #endif /* SQLITE_OMIT_DEPRECATED */
@@ -162913,11 +163112,11 @@
162913 #endif
162914 sqlite3_mutex_enter(db->mutex);
162915 if( mTrace==0 ) xTrace = 0;
162916 if( xTrace==0 ) mTrace = 0;
162917 db->mTrace = mTrace;
162918 db->xTrace = xTrace;
162919 db->pTraceArg = pArg;
162920 sqlite3_mutex_leave(db->mutex);
162921 return SQLITE_OK;
162922 }
162923
@@ -164889,10 +165088,16 @@
164889 /* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
164890 **
164891 ** Set or clear a flag that causes SQLite to verify that type, name,
164892 ** and tbl_name fields of the sqlite_schema table. This is normally
164893 ** on, but it is sometimes useful to turn it off for testing.
 
 
 
 
 
 
164894 */
164895 case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
164896 sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
164897 break;
164898 }
@@ -166503,10 +166708,12 @@
166503 # define TESTONLY(X)
166504 #endif
166505
166506 #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
166507 #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
 
 
166508
166509 #endif /* SQLITE_AMALGAMATION */
166510
166511 #ifdef SQLITE_DEBUG
166512 SQLITE_PRIVATE int sqlite3Fts3Corrupt(void);
@@ -170146,11 +170353,11 @@
170146 }else if( p->zLanguageid==0 ){
170147 sqlite3_result_int(pCtx, 0);
170148 break;
170149 }else{
170150 iCol = p->nColumn;
170151 /* fall-through */
170152 }
170153
170154 default:
170155 /* A user column. Or, if this is a full-table scan, possibly the
170156 ** language-id column. Seek the cursor. */
@@ -170389,13 +170596,17 @@
170389 }
170390 if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return;
170391
170392 switch( nVal ){
170393 case 6: nToken = sqlite3_value_int(apVal[5]);
 
170394 case 5: iCol = sqlite3_value_int(apVal[4]);
 
170395 case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
 
170396 case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
 
170397 case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
170398 }
170399 if( !zEllipsis || !zEnd || !zStart ){
170400 sqlite3_result_error_nomem(pContext);
170401 }else if( nToken==0 ){
@@ -172498,11 +172709,12 @@
172498 ** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK );
172499 */
172500 fts3EvalRestart(pCsr, pRoot, &rc);
172501 do {
172502 fts3EvalNextRow(pCsr, pRoot, &rc);
172503 assert( pRoot->bEof==0 );
 
172504 }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
172505 }
172506 }
172507 return rc;
172508 }
@@ -176607,11 +176819,12 @@
176607 rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr);
176608 }
176609
176610 assert( (rc==SQLITE_OK)==(pMod!=0) );
176611 if( rc==SQLITE_OK ){
176612 const char * const *azArg = (const char * const *)&azDequote[1];
 
176613 rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
176614 }
176615
176616 if( rc==SQLITE_OK ){
176617 pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable));
@@ -185252,10 +185465,14 @@
185252 #ifndef LARGEST_INT64
185253 # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
185254 # define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
185255 #endif
185256
 
 
 
 
185257 /*
185258 ** Versions of isspace(), isalnum() and isdigit() to which it is safe
185259 ** to pass signed char values.
185260 */
185261 #ifdef sqlite3Isdigit
@@ -185670,11 +185887,11 @@
185670 case JSON_STRING: {
185671 if( pNode->jnFlags & JNODE_RAW ){
185672 jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
185673 break;
185674 }
185675 /* Fall through into the next case */
185676 }
185677 case JSON_REAL:
185678 case JSON_INT: {
185679 jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
185680 break;
@@ -185811,11 +186028,11 @@
185811 }
185812 if( pNode->u.zJContent[0]=='-' ){ i = -i; }
185813 sqlite3_result_int64(pCtx, i);
185814 int_done:
185815 break;
185816 int_as_real: /* fall through to real */;
185817 }
185818 case JSON_REAL: {
185819 double r;
185820 #ifdef SQLITE_AMALGAMATION
185821 const char *z = pNode->u.zJContent;
@@ -187514,10 +187731,11 @@
187514 jsonResult(&x);
187515 break;
187516 }
187517 /* For json_each() path and root are the same so fall through
187518 ** into the root case */
 
187519 }
187520 default: {
187521 const char *zRoot = p->zRoot;
187522 if( zRoot==0 ) zRoot = "$";
187523 sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
@@ -187921,10 +188139,11 @@
187921 #endif
187922
187923 /* #include <string.h> */
187924 /* #include <stdio.h> */
187925 /* #include <assert.h> */
 
187926
187927 /* The following macro is used to suppress compiler warnings.
187928 */
187929 #ifndef UNUSED_PARAMETER
187930 # define UNUSED_PARAMETER(x) (void)(x)
@@ -188258,10 +188477,27 @@
188258 */
188259 #ifndef SQLITE_AMALGAMATION
188260 # define testcase(X)
188261 #endif
188262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188263 /*
188264 ** Macros to determine whether the machine is big or little endian,
188265 ** and whether or not that determination is run-time or compile-time.
188266 **
188267 ** For best performance, an attempt is made to guess at the byte-order
@@ -205152,12 +205388,17 @@
205152 memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
205153 p->in.iNext += nCopy;
205154 }
205155
205156 p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
205157 p->abPK = (u8*)&p->apValue[p->nCol*2];
205158 p->zTab = (char*)&p->abPK[p->nCol];
 
 
 
 
 
205159 return (p->rc = rc);
205160 }
205161
205162 /*
205163 ** Advance the changeset iterator to the next change.
@@ -225482,11 +225723,11 @@
225482 int nArg, /* Number of args */
225483 sqlite3_value **apUnused /* Function arguments */
225484 ){
225485 assert( nArg==0 );
225486 UNUSED_PARAM2(nArg, apUnused);
225487 sqlite3_result_text(pCtx, "fts5: 2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829b9c3", -1, SQLITE_TRANSIENT);
225488 }
225489
225490 /*
225491 ** Return true if zName is the extension on one of the shadow tables used
225492 ** by this module.
@@ -230265,12 +230506,12 @@
230265 }
230266 #endif /* SQLITE_CORE */
230267 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
230268
230269 /************** End of stmt.c ************************************************/
230270 #if __LINE__!=230270
230271 #undef SQLITE_SOURCE_ID
230272 #define SQLITE_SOURCE_ID "2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829alt2"
230273 #endif
230274 /* Return the source-id for this library */
230275 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
230276 /************************** End of sqlite3.c ******************************/
230277
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -997,10 +997,19 @@
997
998 #if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
999 # define _BSD_SOURCE
1000 #endif
1001
1002 /*
1003 ** Macro to disable warnings about missing "break" at the end of a "case".
1004 */
1005 #if GCC_VERSION>=7000000
1006 # define deliberate_fall_through __attribute__((fallthrough));
1007 #else
1008 # define deliberate_fall_through
1009 #endif
1010
1011 /*
1012 ** For MinGW, check to see if we can include the header file containing its
1013 ** version information, among other things. Normally, this internal MinGW
1014 ** header file would [only] be included automatically by other MinGW header
1015 ** files; however, the contained version information is now required by this
@@ -1162,11 +1171,11 @@
1171 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1172 ** [sqlite_version()] and [sqlite_source_id()].
1173 */
1174 #define SQLITE_VERSION "3.33.0"
1175 #define SQLITE_VERSION_NUMBER 3033000
1176 #define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f"
1177
1178 /*
1179 ** CAPI3REF: Run-Time Library Version Numbers
1180 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1181 **
@@ -14532,11 +14541,11 @@
14541 # define SELECTTRACE_ENABLED 0
14542 #endif
14543 #if defined(SQLITE_ENABLE_SELECTTRACE)
14544 # define SELECTTRACE_ENABLED 1
14545 # define SELECTTRACE(K,P,S,X) \
14546 if(sqlite3_unsupported_selecttrace&(K)) \
14547 sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
14548 sqlite3DebugPrintf X
14549 #else
14550 # define SELECTTRACE(K,P,S,X)
14551 # define SELECTTRACE_ENABLED 0
@@ -14595,11 +14604,11 @@
14604 ** one parameter that destructors normally want. So we have to introduce
14605 ** this magic value that the code knows to handle differently. Any
14606 ** pointer will work here as long as it is distinct from SQLITE_STATIC
14607 ** and SQLITE_TRANSIENT.
14608 */
14609 #define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault)
14610
14611 /*
14612 ** When SQLITE_OMIT_WSD is defined, it means that the target platform does
14613 ** not support Writable Static Data (WSD) such as global and static variables.
14614 ** All variables must either be on the stack or dynamically allocated from
@@ -14735,10 +14744,257 @@
14744 /*
14745 ** Defer sourcing vdbe.h and btree.h until after the "u8" and
14746 ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
14747 ** pointer types (i.e. FuncDef) defined above.
14748 */
14749 /************** Include pager.h in the middle of sqliteInt.h *****************/
14750 /************** Begin file pager.h *******************************************/
14751 /*
14752 ** 2001 September 15
14753 **
14754 ** The author disclaims copyright to this source code. In place of
14755 ** a legal notice, here is a blessing:
14756 **
14757 ** May you do good and not evil.
14758 ** May you find forgiveness for yourself and forgive others.
14759 ** May you share freely, never taking more than you give.
14760 **
14761 *************************************************************************
14762 ** This header file defines the interface that the sqlite page cache
14763 ** subsystem. The page cache subsystem reads and writes a file a page
14764 ** at a time and provides a journal for rollback.
14765 */
14766
14767 #ifndef SQLITE_PAGER_H
14768 #define SQLITE_PAGER_H
14769
14770 /*
14771 ** Default maximum size for persistent journal files. A negative
14772 ** value means no limit. This value may be overridden using the
14773 ** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
14774 */
14775 #ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
14776 #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
14777 #endif
14778
14779 /*
14780 ** The type used to represent a page number. The first page in a file
14781 ** is called page 1. 0 is used to represent "not a page".
14782 */
14783 typedef u32 Pgno;
14784
14785 /*
14786 ** Each open file is managed by a separate instance of the "Pager" structure.
14787 */
14788 typedef struct Pager Pager;
14789
14790 /*
14791 ** Handle type for pages.
14792 */
14793 typedef struct PgHdr DbPage;
14794
14795 /*
14796 ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
14797 ** reserved for working around a windows/posix incompatibility). It is
14798 ** used in the journal to signify that the remainder of the journal file
14799 ** is devoted to storing a super-journal name - there are no more pages to
14800 ** roll back. See comments for function writeSuperJournal() in pager.c
14801 ** for details.
14802 */
14803 #define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
14804
14805 /*
14806 ** Allowed values for the flags parameter to sqlite3PagerOpen().
14807 **
14808 ** NOTE: These values must match the corresponding BTREE_ values in btree.h.
14809 */
14810 #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
14811 #define PAGER_MEMORY 0x0002 /* In-memory database */
14812
14813 /*
14814 ** Valid values for the second argument to sqlite3PagerLockingMode().
14815 */
14816 #define PAGER_LOCKINGMODE_QUERY -1
14817 #define PAGER_LOCKINGMODE_NORMAL 0
14818 #define PAGER_LOCKINGMODE_EXCLUSIVE 1
14819
14820 /*
14821 ** Numeric constants that encode the journalmode.
14822 **
14823 ** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
14824 ** are exposed in the API via the "PRAGMA journal_mode" command and
14825 ** therefore cannot be changed without a compatibility break.
14826 */
14827 #define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
14828 #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
14829 #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
14830 #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
14831 #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
14832 #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
14833 #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
14834
14835 /*
14836 ** Flags that make up the mask passed to sqlite3PagerGet().
14837 */
14838 #define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
14839 #define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
14840
14841 /*
14842 ** Flags for sqlite3PagerSetFlags()
14843 **
14844 ** Value constraints (enforced via assert()):
14845 ** PAGER_FULLFSYNC == SQLITE_FullFSync
14846 ** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
14847 ** PAGER_CACHE_SPILL == SQLITE_CacheSpill
14848 */
14849 #define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
14850 #define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
14851 #define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
14852 #define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
14853 #define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
14854 #define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
14855 #define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
14856 #define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
14857 #define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
14858
14859 /*
14860 ** The remainder of this file contains the declarations of the functions
14861 ** that make up the Pager sub-system API. See source code comments for
14862 ** a detailed description of each routine.
14863 */
14864
14865 /* Open and close a Pager connection. */
14866 SQLITE_PRIVATE int sqlite3PagerOpen(
14867 sqlite3_vfs*,
14868 Pager **ppPager,
14869 const char*,
14870 int,
14871 int,
14872 int,
14873 void(*)(DbPage*)
14874 );
14875 SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
14876 SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
14877
14878 /* Functions used to configure a Pager object. */
14879 SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
14880 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
14881 SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
14882 SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
14883 SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
14884 SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
14885 SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
14886 SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
14887 SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
14888 SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
14889 SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
14890 SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
14891 SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
14892 SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
14893 SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
14894
14895 /* Functions used to obtain and release page references. */
14896 SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
14897 SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
14898 SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
14899 SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
14900 SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
14901 SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
14902
14903 /* Operations on page references. */
14904 SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
14905 SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
14906 SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
14907 SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
14908 SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
14909 SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
14910
14911 /* Functions used to manage pager transactions and savepoints. */
14912 SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
14913 SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
14914 SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
14915 SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
14916 SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper);
14917 SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
14918 SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
14919 SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
14920 SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
14921 SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
14922
14923 #ifndef SQLITE_OMIT_WAL
14924 SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
14925 SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
14926 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
14927 SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
14928 SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
14929 # ifdef SQLITE_ENABLE_SNAPSHOT
14930 SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
14931 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
14932 SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
14933 SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
14934 SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
14935 # endif
14936 #endif
14937
14938 #if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
14939 SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
14940 SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
14941 #else
14942 # define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
14943 # define sqlite3PagerWalDb(x,y)
14944 #endif
14945
14946 #ifdef SQLITE_DIRECT_OVERFLOW_READ
14947 SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
14948 #endif
14949
14950 #ifdef SQLITE_ENABLE_ZIPVFS
14951 SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
14952 #endif
14953
14954 /* Functions used to query pager state and configuration. */
14955 SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
14956 SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
14957 #ifdef SQLITE_DEBUG
14958 SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
14959 #endif
14960 SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
14961 SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
14962 SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
14963 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
14964 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
14965 SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
14966 SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
14967 SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
14968 SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
14969 SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
14970 SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
14971
14972 /* Functions used to truncate the database file. */
14973 SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
14974
14975 SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
14976
14977 /* Functions to support testing and debugging. */
14978 #if !defined(NDEBUG) || defined(SQLITE_TEST)
14979 SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
14980 SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
14981 #endif
14982 #ifdef SQLITE_TEST
14983 SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
14984 SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
14985 void disable_simulated_io_errors(void);
14986 void enable_simulated_io_errors(void);
14987 #else
14988 # define disable_simulated_io_errors()
14989 # define enable_simulated_io_errors()
14990 #endif
14991
14992 #endif /* SQLITE_PAGER_H */
14993
14994 /************** End of pager.h ***********************************************/
14995 /************** Continuing where we left off in sqliteInt.h ******************/
14996 /************** Include btree.h in the middle of sqliteInt.h *****************/
14997 /************** Begin file btree.h *******************************************/
14998 /*
14999 ** 2001 September 15
15000 **
@@ -14810,12 +15066,12 @@
15066 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
15067 #endif
15068 SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
15069 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
15070 SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
15071 SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
15072 SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree*);
15073 SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
15074 SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*);
15075 SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
15076 SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
15077 SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
@@ -14823,11 +15079,11 @@
15079 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
15080 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
15081 SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
15082 SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
15083 SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
15084 SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
15085 SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
15086 SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
15087 SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
15088 SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
15089 SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
@@ -14964,11 +15220,11 @@
15220 #define BTREE_WRCSR 0x00000004 /* read-write cursor */
15221 #define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */
15222
15223 SQLITE_PRIVATE int sqlite3BtreeCursor(
15224 Btree*, /* BTree containing table to open */
15225 Pgno iTable, /* Index of root page */
15226 int wrFlag, /* 1 for writing. 0 for read-only */
15227 struct KeyInfo*, /* First argument to compare function */
15228 BtCursor *pCursor /* Space to write cursor structure */
15229 );
15230 SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
@@ -15055,11 +15311,11 @@
15311 SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
15312 SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
15313 SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
15314 SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
15315
15316 SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
15317 SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
15318 SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
15319
15320 #ifndef SQLITE_OMIT_INCRBLOB
15321 SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
@@ -15192,11 +15448,11 @@
15448 sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */
15449 CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
15450 Mem *pMem; /* Used when p4type is P4_MEM */
15451 VTable *pVtab; /* Used when p4type is P4_VTAB */
15452 KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
15453 u32 *ai; /* Used when p4type is P4_INTARRAY */
15454 SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
15455 Table *pTab; /* Used when p4type is P4_TABLE */
15456 #ifdef SQLITE_ENABLE_CURSOR_HINTS
15457 Expr *pExpr; /* Used when p4type is P4_EXPR */
15458 #endif
@@ -15756,257 +16012,10 @@
16012 #endif
16013
16014 #endif /* SQLITE_VDBE_H */
16015
16016 /************** End of vdbe.h ************************************************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16017 /************** Continuing where we left off in sqliteInt.h ******************/
16018 /************** Include pcache.h in the middle of sqliteInt.h ****************/
16019 /************** Begin file pcache.h ******************************************/
16020 /*
16021 ** 2008 August 05
@@ -16843,11 +16852,11 @@
16852 int nChange; /* Value returned by sqlite3_changes() */
16853 int nTotalChange; /* Value returned by sqlite3_total_changes() */
16854 int aLimit[SQLITE_N_LIMIT]; /* Limits */
16855 int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
16856 struct sqlite3InitInfo { /* Information used during initialization */
16857 Pgno newTnum; /* Rootpage of table being initialized */
16858 u8 iDb; /* Which db file is being initialized */
16859 u8 busy; /* TRUE if currently initializing */
16860 unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
16861 unsigned imposterTable : 1; /* Building an imposter table */
16862 unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
@@ -16858,11 +16867,14 @@
16867 int nVdbeWrite; /* Number of active VDBEs that read and write */
16868 int nVdbeExec; /* Number of nested calls to VdbeExec() */
16869 int nVDestroy; /* Number of active OP_VDestroy operations */
16870 int nExtension; /* Number of loaded extensions */
16871 void **aExtension; /* Array of shared library handles */
16872 union {
16873 void (*xLegacy)(void*,const char*); /* Legacy trace function */
16874 int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */
16875 } trace;
16876 void *pTraceArg; /* Argument to the trace function */
16877 #ifndef SQLITE_OMIT_DEPRECATED
16878 void (*xProfile)(void*,const char*,u64); /* Profiling function */
16879 void *pProfileArg; /* Argument to profile function */
16880 #endif
@@ -17482,11 +17494,11 @@
17494 Select *pSelect; /* NULL for tables. Points to definition if a view. */
17495 FKey *pFKey; /* Linked list of all foreign keys in this table */
17496 char *zColAff; /* String defining the affinity of each column */
17497 ExprList *pCheck; /* All CHECK constraints */
17498 /* ... also used as column name list in a VIEW */
17499 Pgno tnum; /* Root BTree page for this table */
17500 u32 nTabRef; /* Number of pointers to this Table */
17501 u32 tabFlags; /* Mask of TF_* values */
17502 i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
17503 i16 nCol; /* Number of columns in this table */
17504 i16 nNVCol; /* Number of columns that are not VIRTUAL */
@@ -17775,11 +17787,11 @@
17787 Schema *pSchema; /* Schema containing this index */
17788 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
17789 const char **azColl; /* Array of collation sequence names for index */
17790 Expr *pPartIdxWhere; /* WHERE clause for partial indices */
17791 ExprList *aColExpr; /* Column expressions */
17792 Pgno tnum; /* DB Page containing root of this index */
17793 LogEst szIdxRow; /* Estimated average row size in bytes */
17794 u16 nKeyCol; /* Number of columns forming the key */
17795 u16 nColumn; /* Number of columns stored in the index */
17796 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
17797 unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
@@ -17901,15 +17913,10 @@
17913 int nFunc; /* Number of entries in aFunc[] */
17914 u32 selId; /* Select to which this AggInfo belongs */
17915 AggInfo *pNext; /* Next in list of them all */
17916 };
17917
 
 
 
 
 
17918 /*
17919 ** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
17920 ** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
17921 ** than 32767 we have to make it 32-bit. 16-bit is preferred because
17922 ** it uses less memory in the Expr object, which is a big memory user
@@ -18744,13 +18751,11 @@
18751
18752 Token sLastToken; /* The last token parsed */
18753 ynVar nVar; /* Number of '?' variables seen in the SQL so far */
18754 u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
18755 u8 explain; /* True if the EXPLAIN flag is found on the query */
 
18756 u8 eParseMode; /* PARSE_MODE_XXX constant */
 
18757 #ifndef SQLITE_OMIT_VIRTUALTABLE
18758 int nVtabLock; /* Number of virtual tables to lock */
18759 #endif
18760 int nHeight; /* Expression tree height of current sub-select */
18761 #ifndef SQLITE_OMIT_EXPLAIN
@@ -18990,10 +18995,11 @@
18995 char **pzErrMsg; /* Error message stored here */
18996 int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
18997 int rc; /* Result code stored here */
18998 u32 mInitFlags; /* Flags controlling error messages */
18999 u32 nInitRow; /* Number of rows processed */
19000 Pgno mxPage; /* Maximum page number. 0 for no limit. */
19001 } InitData;
19002
19003 /*
19004 ** Allowed values for mInitFlags
19005 */
@@ -19823,12 +19829,14 @@
19829 SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
19830 SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
19831 SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
19832 SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
19833 SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
19834 SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*);
19835 SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
19836 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
19837 SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
19838 SQLITE_PRIVATE int sqlite3Atoi(const char*);
19839 #ifndef SQLITE_OMIT_UTF16
19840 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
19841 #endif
19842 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
@@ -19944,19 +19952,19 @@
19952 SQLITE_PRIVATE const char sqlite3StrBINARY[];
19953 SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
19954 SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
19955 SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
19956 SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
19957 SQLITE_API extern u32 sqlite3_unsupported_selecttrace;
19958 #ifndef SQLITE_OMIT_WSD
19959 SQLITE_PRIVATE int sqlite3PendingByte;
19960 #endif
19961 #endif /* SQLITE_AMALGAMATION */
19962 #ifdef VDBE_PROFILE
19963 SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt;
19964 #endif
19965 SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno);
19966 SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
19967 SQLITE_PRIVATE void sqlite3AlterFunctions(void);
19968 SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
19969 SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
19970 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
@@ -20066,11 +20074,11 @@
20074 #else
20075 # define sqlite3CloseExtensions(X)
20076 #endif
20077
20078 #ifndef SQLITE_OMIT_SHARED_CACHE
20079 SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *);
20080 #else
20081 #define sqlite3TableLock(v,w,x,y,z)
20082 #endif
20083
20084 #ifdef SQLITE_TEST
@@ -20661,11 +20669,11 @@
20669 #endif
20670
20671 /*
20672 ** Flags for select tracing and the ".selecttrace" macro of the CLI
20673 */
20674 SQLITE_API u32 sqlite3_unsupported_selecttrace = 0;
20675
20676 /* #include "opcodes.h" */
20677 /*
20678 ** Properties of opcodes. The OPFLG_INITIALIZER macro is
20679 ** created by mkopcodeh.awk during compilation. Data is obtained
@@ -20788,11 +20796,11 @@
20796 Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
20797 Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
20798 Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
20799 Btree *pBtx; /* Separate file holding temporary table */
20800 i64 seqCount; /* Sequence counter */
20801 u32 *aAltMap; /* Mapping from table to index column numbers */
20802
20803 /* Cached OP_Column parse information is only valid if cacheStatus matches
20804 ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
20805 ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
20806 ** the cache is out of date. */
@@ -21184,11 +21192,11 @@
21192 */
21193 SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
21194 SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
21195 void sqliteVdbePopStack(Vdbe*,int);
21196 SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
21197 SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*);
21198 SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
21199 SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
21200 SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
21201 SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
21202 SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
@@ -21660,11 +21668,11 @@
21668 ** pagers the database handle is connected to. *pHighwater is always set
21669 ** to zero.
21670 */
21671 case SQLITE_DBSTATUS_CACHE_SPILL:
21672 op = SQLITE_DBSTATUS_CACHE_WRITE+1;
21673 /* no break */ deliberate_fall_through
21674 case SQLITE_DBSTATUS_CACHE_HIT:
21675 case SQLITE_DBSTATUS_CACHE_MISS:
21676 case SQLITE_DBSTATUS_CACHE_WRITE:{
21677 int i;
21678 int nRet = 0;
@@ -22816,12 +22824,12 @@
22824 break;
22825 }
22826 case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
22827 case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
22828 case 's': {
22829 i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
22830 sqlite3Int64ToText(iS, &z[j]);
22831 j += sqlite3Strlen30(&z[j]);
22832 break;
22833 }
22834 case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
22835 case 'w': {
@@ -28537,15 +28545,15 @@
28545 assert( precision>=(-1) );
28546 switch( xtype ){
28547 case etPOINTER:
28548 flag_long = sizeof(char*)==sizeof(i64) ? 2 :
28549 sizeof(char*)==sizeof(long int) ? 1 : 0;
28550 /* no break */ deliberate_fall_through
28551 case etORDINAL:
28552 case etRADIX:
28553 cThousand = 0;
28554 /* no break */ deliberate_fall_through
28555 case etDECIMAL:
28556 if( infop->flags & FLAG_SIGNED ){
28557 i64 v;
28558 if( bArgList ){
28559 v = getIntArg(pArgList);
@@ -31770,10 +31778,34 @@
31778 #endif /* SQLITE_OMIT_FLOATING_POINT */
31779 }
31780 #if defined(_MSC_VER)
31781 #pragma warning(default : 4756)
31782 #endif
31783
31784 /*
31785 ** Render an signed 64-bit integer as text. Store the result in zOut[].
31786 **
31787 ** The caller must ensure that zOut[] is at least 21 bytes in size.
31788 */
31789 SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){
31790 int i;
31791 u64 x;
31792 char zTemp[22];
31793 if( v<0 ){
31794 x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
31795 }else{
31796 x = v;
31797 }
31798 i = sizeof(zTemp)-2;
31799 zTemp[sizeof(zTemp)-1] = 0;
31800 do{
31801 zTemp[i--] = (x%10) + '0';
31802 x = x/10;
31803 }while( x );
31804 if( v<0 ) zTemp[i--] = '-';
31805 memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
31806 }
31807
31808 /*
31809 ** Compare the 19-character string zNum against the text representation
31810 ** value 2^63: 9223372036854775808. Return negative, zero, or positive
31811 ** if zNum is less than, equal to, or greater than the string.
@@ -32011,13 +32043,31 @@
32043 ** Return a 32-bit integer value extracted from a string. If the
32044 ** string is not an integer, just return 0.
32045 */
32046 SQLITE_PRIVATE int sqlite3Atoi(const char *z){
32047 int x = 0;
32048 sqlite3GetInt32(z, &x);
32049 return x;
32050 }
32051
32052 /*
32053 ** Try to convert z into an unsigned 32-bit integer. Return true on
32054 ** success and false if there is an error.
32055 **
32056 ** Only decimal notation is accepted.
32057 */
32058 SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){
32059 u64 v = 0;
32060 int i;
32061 for(i=0; sqlite3Isdigit(z[i]); i++){
32062 v = v*10 + z[i] - '0';
32063 if( v>4294967296LL ){ *pI = 0; return 0; }
32064 }
32065 if( i==0 || z[i]!=0 ){ *pI = 0; return 0; }
32066 *pI = (u32)v;
32067 return 1;
32068 }
32069
32070 /*
32071 ** The variable-length integer encoding is as follows:
32072 **
32073 ** KEY:
@@ -39188,11 +39238,11 @@
39238 }
39239 #endif
39240 if( rc!=SQLITE_OK ){
39241 if( h>=0 ) robust_close(pNew, h, __LINE__);
39242 }else{
39243 pId->pMethods = pLockingStyle;
39244 OpenCounter(+1);
39245 verifyDbFile(pNew);
39246 }
39247 return rc;
39248 }
@@ -46899,11 +46949,11 @@
46949 {
46950 sqlite3_free(zConverted);
46951 }
46952
46953 sqlite3_free(zTmpname);
46954 id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
46955 pFile->pVfs = pVfs;
46956 pFile->h = h;
46957 if( isReadonly ){
46958 pFile->ctrlFlags |= WINFILE_RDONLY;
46959 }
@@ -48125,11 +48175,11 @@
48175 }
48176 memset(p, 0, sizeof(*p));
48177 p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
48178 assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
48179 *pOutFlags = flags | SQLITE_OPEN_MEMORY;
48180 pFile->pMethods = &memdb_io_methods;
48181 p->szMax = sqlite3GlobalConfig.mxMemdbSize;
48182 return SQLITE_OK;
48183 }
48184
48185 #if 0 /* Only used to delete rollback journals, super-journals, and WAL
@@ -52442,15 +52492,10 @@
52492 # define USEFETCH(x) ((x)->bUseFetch)
52493 #else
52494 # define USEFETCH(x) 0
52495 #endif
52496
 
 
 
 
 
52497 /*
52498 ** The argument to this macro is a file descriptor (type sqlite3_file*).
52499 ** Return 0 if it is not open, or non-zero (but not 1) if it is.
52500 **
52501 ** This is so that expressions can be written as:
@@ -54153,16 +54198,17 @@
54198
54199 /* Allocate space for both the pJournal and pSuper file descriptors.
54200 ** If successful, open the super-journal file for reading.
54201 */
54202 pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
 
54203 if( !pSuper ){
54204 rc = SQLITE_NOMEM_BKPT;
54205 pJournal = 0;
54206 }else{
54207 const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
54208 rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
54209 pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
54210 }
54211 if( rc!=SQLITE_OK ) goto delsuper_out;
54212
54213 /* Load the entire super-journal file into space obtained from
54214 ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
@@ -55419,11 +55465,11 @@
55465 ** Make no changes if mxPage is zero or negative. And never reduce the
55466 ** maximum page count below the current size of the database.
55467 **
55468 ** Regardless of mxPage, return the current maximum page count.
55469 */
55470 SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){
55471 if( mxPage>0 ){
55472 pPager->mxPgno = mxPage;
55473 }
55474 assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
55475 /* assert( pPager->mxPgno>=pPager->dbSize ); */
@@ -57146,22 +57192,22 @@
57192
57193 noContent = (flags & PAGER_GET_NOCONTENT)!=0;
57194 if( pPg->pPager && !noContent ){
57195 /* In this case the pcache already contains an initialized copy of
57196 ** the page. Return without further ado. */
57197 assert( pgno!=PAGER_MJ_PGNO(pPager) );
57198 pPager->aStat[PAGER_STAT_HIT]++;
57199 return SQLITE_OK;
57200
57201 }else{
57202 /* The pager cache has created a new page. Its content needs to
57203 ** be initialized. But first some error checks:
57204 **
57205 ** (*) obsolete. Was: maximum page number is 2^31
57206 ** (2) Never try to fetch the locking page
57207 */
57208 if( pgno==PAGER_MJ_PGNO(pPager) ){
57209 rc = SQLITE_CORRUPT_BKPT;
57210 goto pager_acquire_err;
57211 }
57212
57213 pPg->pPager = pPager;
@@ -59863,11 +59909,11 @@
59909 ** walIteratorFree() - Free an iterator.
59910 **
59911 ** This functionality is used by the checkpoint code (see walCheckpoint()).
59912 */
59913 struct WalIterator {
59914 u32 iPrior; /* Last result returned from the iterator */
59915 int nSegment; /* Number of entries in aSegment[] */
59916 struct WalSegment {
59917 int iNext; /* Next slot in aIndex[] not yet returned */
59918 ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
59919 u32 *aPgno; /* Array of page numbers. */
@@ -59945,11 +59991,13 @@
59991 rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
59992 pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
59993 );
59994 assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
59995 testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
59996 if( rc==SQLITE_OK ){
59997 if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;
59998 }else if( (rc&0xff)==SQLITE_READONLY ){
59999 pWal->readOnly |= WAL_SHM_RDONLY;
60000 if( rc==SQLITE_READONLY ){
60001 rc = SQLITE_OK;
60002 }
60003 }
@@ -60320,10 +60368,11 @@
60368 && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
60369 && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
60370 && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
60371 && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
60372 );
60373 assert( iHash>=0 );
60374 return iHash;
60375 }
60376
60377 /*
60378 ** Return the page number associated with frame iFrame in this WAL.
@@ -60516,16 +60565,10 @@
60565 assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
60566 assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
60567 assert( pWal->writeLock );
60568 iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
60569 rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
 
 
 
 
 
 
60570 if( rc ){
60571 return rc;
60572 }
60573
60574 WALTRACE(("WAL%p: recovery begin...\n", pWal));
@@ -60537,19 +60580,20 @@
60580 goto recovery_error;
60581 }
60582
60583 if( nSize>WAL_HDRSIZE ){
60584 u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
60585 u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */
60586 u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
60587 int szFrame; /* Number of bytes in buffer aFrame[] */
60588 u8 *aData; /* Pointer to data part of aFrame buffer */
 
 
60589 int szPage; /* Page size according to the log */
60590 u32 magic; /* Magic value read from WAL header */
60591 u32 version; /* Magic value read from WAL header */
60592 int isValid; /* True if this frame is valid */
60593 u32 iPg; /* Current 32KB wal-index page */
60594 u32 iLastFrame; /* Last frame in wal, based on nSize alone */
60595
60596 /* Read in the WAL header. */
60597 rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
60598 if( rc!=SQLITE_OK ){
60599 goto recovery_error;
@@ -60592,42 +60636,86 @@
60636 goto finished;
60637 }
60638
60639 /* Malloc a buffer to read frames into. */
60640 szFrame = szPage + WAL_FRAME_HDRSIZE;
60641 aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
60642 if( !aFrame ){
60643 rc = SQLITE_NOMEM_BKPT;
60644 goto recovery_error;
60645 }
60646 aData = &aFrame[WAL_FRAME_HDRSIZE];
60647 aPrivate = (u32*)&aData[szPage];
60648
60649 /* Read all frames from the log file. */
60650 iLastFrame = (nSize - WAL_HDRSIZE) / szFrame;
60651 for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){
60652 u32 *aShare;
60653 u32 iFrame; /* Index of last frame read */
60654 u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
60655 u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE);
60656 u32 nHdr, nHdr32;
60657 rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
60658 if( rc ) break;
60659 pWal->apWiData[iPg] = aPrivate;
60660
60661 for(iFrame=iFirst; iFrame<=iLast; iFrame++){
60662 i64 iOffset = walFrameOffset(iFrame, szPage);
60663 u32 pgno; /* Database page number for frame */
60664 u32 nTruncate; /* dbsize field from frame header */
60665
60666 /* Read and decode the next log frame. */
60667 rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
60668 if( rc!=SQLITE_OK ) break;
60669 isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
60670 if( !isValid ) break;
60671 rc = walIndexAppend(pWal, iFrame, pgno);
60672 if( NEVER(rc!=SQLITE_OK) ) break;
60673
60674 /* If nTruncate is non-zero, this is a commit record. */
60675 if( nTruncate ){
60676 pWal->hdr.mxFrame = iFrame;
60677 pWal->hdr.nPage = nTruncate;
60678 pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
60679 testcase( szPage<=32768 );
60680 testcase( szPage>=65536 );
60681 aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
60682 aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
60683 }
60684 }
60685 pWal->apWiData[iPg] = aShare;
60686 nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
60687 nHdr32 = nHdr / sizeof(u32);
60688 #ifndef SQLITE_SAFER_WALINDEX_RECOVERY
60689 /* Memcpy() should work fine here, on all reasonable implementations.
60690 ** Technically, memcpy() might change the destination to some
60691 ** intermediate value before setting to the final value, and that might
60692 ** cause a concurrent reader to malfunction. Memcpy() is allowed to
60693 ** do that, according to the spec, but no memcpy() implementation that
60694 ** we know of actually does that, which is why we say that memcpy()
60695 ** is safe for this. Memcpy() is certainly a lot faster.
60696 */
60697 memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr);
60698 #else
60699 /* In the event that some platform is found for which memcpy()
60700 ** changes the destination to some intermediate value before
60701 ** setting the final value, this alternative copy routine is
60702 ** provided.
60703 */
60704 {
60705 int i;
60706 for(i=nHdr32; i<WALINDEX_PGSZ/sizeof(u32); i++){
60707 if( aShare[i]!=aPrivate[i] ){
60708 /* Atomic memory operations are not required here because if
60709 ** the value needs to be changed, that means it is not being
60710 ** accessed concurrently. */
60711 aShare[i] = aPrivate[i];
60712 }
60713 }
60714 }
60715 #endif
60716 if( iFrame<=iLast ) break;
60717 }
60718
60719 sqlite3_free(aFrame);
60720 }
60721
@@ -60638,19 +60726,30 @@
60726 pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
60727 pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
60728 walIndexWriteHdr(pWal);
60729
60730 /* Reset the checkpoint-header. This is safe because this thread is
60731 ** currently holding locks that exclude all other writers and
60732 ** checkpointers. Then set the values of read-mark slots 1 through N.
60733 */
60734 pInfo = walCkptInfo(pWal);
60735 pInfo->nBackfill = 0;
60736 pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
60737 pInfo->aReadMark[0] = 0;
60738 for(i=1; i<WAL_NREADER; i++){
60739 rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
60740 if( rc==SQLITE_OK ){
60741 if( i==1 && pWal->hdr.mxFrame ){
60742 pInfo->aReadMark[i] = pWal->hdr.mxFrame;
60743 }else{
60744 pInfo->aReadMark[i] = READMARK_NOT_USED;
60745 }
60746 walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
60747 }else if( rc!=SQLITE_BUSY ){
60748 goto recovery_error;
60749 }
60750 }
60751
60752 /* If more than one frame was recovered from the log file, report an
60753 ** event via sqlite3_log(). This is to help with identifying performance
60754 ** problems caused by applications routinely shutting down without
60755 ** checkpointing the log file.
@@ -60664,11 +60763,10 @@
60763 }
60764
60765 recovery_error:
60766 WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
60767 walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
 
60768 return rc;
60769 }
60770
60771 /*
60772 ** Close an open wal-index.
@@ -61312,14 +61410,22 @@
61410 i64 nReq = ((i64)mxPage * szPage);
61411 i64 nSize; /* Current size of database file */
61412 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
61413 rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
61414 if( rc==SQLITE_OK && nSize<nReq ){
61415 if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)<nReq ){
61416 /* If the size of the final database is larger than the current
61417 ** database plus the amount of data in the wal file, plus the
61418 ** maximum size of the pending-byte page (65536 bytes), then
61419 ** must be corruption somewhere. */
61420 rc = SQLITE_CORRUPT_BKPT;
61421 }else{
61422 sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
61423 }
61424 }
61425
61426 }
 
61427
61428 /* Iterate through the contents of the WAL, copying data to the db file */
61429 while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
61430 i64 iOffset;
61431 assert( walFramePgno(pWal, iFrame)==iDbpage );
@@ -64048,11 +64154,12 @@
64154 Pgno nPage; /* Number of pages in the database */
64155 int mxErr; /* Stop accumulating errors when this reaches zero */
64156 int nErr; /* Number of messages written to zErrMsg so far */
64157 int bOomFault; /* A memory allocation error has occurred */
64158 const char *zPfx; /* Error message prefix */
64159 Pgno v1; /* Value for first %u substitution in zPfx */
64160 int v2; /* Value for second %d substitution in zPfx */
64161 StrAccum errMsg; /* Accumulate the error message text here */
64162 u32 *heap; /* Min-heap used for analyzing cell coverage */
64163 sqlite3 *db; /* Database connection running the check */
64164 };
64165
@@ -66513,16 +66620,15 @@
66620 /*
66621 ** Return the size of the database file in pages. If there is any kind of
66622 ** error, return ((unsigned int)-1).
66623 */
66624 static Pgno btreePagecount(BtShared *pBt){
 
66625 return pBt->nPage;
66626 }
66627 SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){
66628 assert( sqlite3BtreeHoldsMutex(p) );
66629 return btreePagecount(p->pBt);
66630 }
66631
66632 /*
66633 ** Get a page from the pager and initialize it.
66634 **
@@ -67306,12 +67412,12 @@
67412 /*
67413 ** Set the maximum page count for a database if mxPage is positive.
67414 ** No changes are made if mxPage is 0 or negative.
67415 ** Regardless of the value of mxPage, return the maximum page count.
67416 */
67417 SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){
67418 Pgno n;
67419 sqlite3BtreeEnter(p);
67420 n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
67421 sqlite3BtreeLeave(p);
67422 return n;
67423 }
@@ -68746,11 +68852,11 @@
68852 ** It is assumed that the sqlite3BtreeCursorZero() has been called
68853 ** on pCur to initialize the memory space prior to invoking this routine.
68854 */
68855 static int btreeCursor(
68856 Btree *p, /* The btree */
68857 Pgno iTable, /* Root page of table to open */
68858 int wrFlag, /* 1 to write. 0 read-only */
68859 struct KeyInfo *pKeyInfo, /* First arg to comparison function */
68860 BtCursor *pCur /* Space for new cursor */
68861 ){
68862 BtShared *pBt = p->pBt; /* Shared b-tree handle */
@@ -68789,21 +68895,21 @@
68895 }
68896 }
68897
68898 /* Now that no other errors can occur, finish filling in the BtCursor
68899 ** variables and link the cursor into the BtShared list. */
68900 pCur->pgnoRoot = iTable;
68901 pCur->iPage = -1;
68902 pCur->pKeyInfo = pKeyInfo;
68903 pCur->pBtree = p;
68904 pCur->pBt = pBt;
68905 pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
68906 pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
68907 /* If there are two or more cursors on the same btree, then all such
68908 ** cursors *must* have the BTCF_Multiple flag set. */
68909 for(pX=pBt->pCursor; pX; pX=pX->pNext){
68910 if( pX->pgnoRoot==iTable ){
68911 pX->curFlags |= BTCF_Multiple;
68912 pCur->curFlags |= BTCF_Multiple;
68913 }
68914 }
68915 pCur->pNext = pBt->pCursor;
@@ -68811,11 +68917,11 @@
68917 pCur->eState = CURSOR_INVALID;
68918 return SQLITE_OK;
68919 }
68920 static int btreeCursorWithLock(
68921 Btree *p, /* The btree */
68922 Pgno iTable, /* Root page of table to open */
68923 int wrFlag, /* 1 to write. 0 read-only */
68924 struct KeyInfo *pKeyInfo, /* First arg to comparison function */
68925 BtCursor *pCur /* Space for new cursor */
68926 ){
68927 int rc;
@@ -68824,11 +68930,11 @@
68930 sqlite3BtreeLeave(p);
68931 return rc;
68932 }
68933 SQLITE_PRIVATE int sqlite3BtreeCursor(
68934 Btree *p, /* The btree */
68935 Pgno iTable, /* Root page of table to open */
68936 int wrFlag, /* 1 to write. 0 read-only */
68937 struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
68938 BtCursor *pCur /* Write new cursor here */
68939 ){
68940 if( p->sharable ){
@@ -69249,10 +69355,11 @@
69355 }
69356
69357 assert( rc==SQLITE_OK && amt>0 );
69358 while( nextPage ){
69359 /* If required, populate the overflow page-list cache. */
69360 if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
69361 assert( pCur->aOverflow[iIdx]==0
69362 || pCur->aOverflow[iIdx]==nextPage
69363 || CORRUPT_DB );
69364 pCur->aOverflow[iIdx] = nextPage;
69365
@@ -70664,10 +70771,14 @@
70771 */
70772 if( nFree!=0 ){
70773 u32 nLeaf; /* Initial number of leaf cells on trunk page */
70774
70775 iTrunk = get4byte(&pPage1->aData[32]);
70776 if( iTrunk>btreePagecount(pBt) ){
70777 rc = SQLITE_CORRUPT_BKPT;
70778 goto freepage_out;
70779 }
70780 rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
70781 if( rc!=SQLITE_OK ){
70782 goto freepage_out;
70783 }
70784
@@ -73468,11 +73579,11 @@
73579 ** flags might not work:
73580 **
73581 ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
73582 ** BTREE_ZERODATA Used for SQL indices
73583 */
73584 static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
73585 BtShared *pBt = p->pBt;
73586 MemPage *pRoot;
73587 Pgno pgnoRoot;
73588 int rc;
73589 int ptfFlags; /* Page-type flage for the root page of new table */
@@ -73501,21 +73612,23 @@
73612 /* Read the value of meta[3] from the database to determine where the
73613 ** root page of the new table should go. meta[3] is the largest root-page
73614 ** created so far, so the new root-page is (meta[3]+1).
73615 */
73616 sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
73617 if( pgnoRoot>btreePagecount(pBt) ){
73618 return SQLITE_CORRUPT_BKPT;
73619 }
73620 pgnoRoot++;
73621
73622 /* The new root-page may not be allocated on a pointer-map page, or the
73623 ** PENDING_BYTE page.
73624 */
73625 while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
73626 pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
73627 pgnoRoot++;
73628 }
73629 assert( pgnoRoot>=3 );
 
73630
73631 /* Allocate a page. The page that currently resides at pgnoRoot will
73632 ** be moved to the allocated page (unless the allocated page happens
73633 ** to reside at pgnoRoot).
73634 */
@@ -73608,14 +73721,14 @@
73721 ptfFlags = PTF_ZERODATA | PTF_LEAF;
73722 }
73723 zeroPage(pRoot, ptfFlags);
73724 sqlite3PagerUnref(pRoot->pDbPage);
73725 assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
73726 *piTable = pgnoRoot;
73727 return SQLITE_OK;
73728 }
73729 SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){
73730 int rc;
73731 sqlite3BtreeEnter(p);
73732 rc = btreeCreateTable(p, piTable, flags);
73733 sqlite3BtreeLeave(p);
73734 return rc;
@@ -74095,11 +74208,11 @@
74208 ** Verify that the number of pages on the list is N.
74209 */
74210 static void checkList(
74211 IntegrityCk *pCheck, /* Integrity checking context */
74212 int isFreeList, /* True for a freelist. False for overflow page list */
74213 Pgno iPage, /* Page number for first page in the list */
74214 u32 N /* Expected number of pages in the list */
74215 ){
74216 int i;
74217 u32 expected = N;
74218 int nErrAtStart = pCheck->nErr;
@@ -74227,11 +74340,11 @@
74340 ** 4. Recursively call checkTreePage on all children.
74341 ** 5. Verify that the depth of all children is the same.
74342 */
74343 static int checkTreePage(
74344 IntegrityCk *pCheck, /* Context for the sanity check */
74345 Pgno iPage, /* Page number of the page to check */
74346 i64 *piMinKey, /* Write minimum integer primary key here */
74347 i64 maxKey /* Error if integer primary key greater than this */
74348 ){
74349 MemPage *pPage = 0; /* The page being analyzed */
74350 int i; /* Loop counter */
@@ -74263,13 +74376,13 @@
74376 */
74377 pBt = pCheck->pBt;
74378 usableSize = pBt->usableSize;
74379 if( iPage==0 ) return 0;
74380 if( checkRef(pCheck, iPage) ) return 0;
74381 pCheck->zPfx = "Page %u: ";
74382 pCheck->v1 = iPage;
74383 if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
74384 checkAppendMsg(pCheck,
74385 "unable to get the page. error code=%d", rc);
74386 goto end_of_check;
74387 }
74388
@@ -74290,11 +74403,11 @@
74403 }
74404 data = pPage->aData;
74405 hdr = pPage->hdrOffset;
74406
74407 /* Set up for cell analysis */
74408 pCheck->zPfx = "On tree page %u cell %d: ";
74409 contentOffset = get2byteNotZero(&data[hdr+5]);
74410 assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
74411
74412 /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
74413 ** number of cells on the page. */
@@ -74310,11 +74423,11 @@
74423 if( !pPage->leaf ){
74424 /* Analyze the right-child page of internal pages */
74425 pgno = get4byte(&data[hdr+8]);
74426 #ifndef SQLITE_OMIT_AUTOVACUUM
74427 if( pBt->autoVacuum ){
74428 pCheck->zPfx = "On page %u at right child: ";
74429 checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
74430 }
74431 #endif
74432 depth = checkTreePage(pCheck, pgno, &maxKey, maxKey);
74433 keyCanBeEqual = 0;
@@ -74451,11 +74564,11 @@
74564 nFrag = 0;
74565 prev = contentOffset - 1; /* Implied first min-heap entry */
74566 while( btreeHeapPull(heap,&x) ){
74567 if( (prev&0xffff)>=(x>>16) ){
74568 checkAppendMsg(pCheck,
74569 "Multiple uses for byte %u of page %u", x>>16, iPage);
74570 break;
74571 }else{
74572 nFrag += (x>>16) - (prev&0xffff) - 1;
74573 prev = x;
74574 }
@@ -74466,11 +74579,11 @@
74579 ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
74580 ** number of fragmented free bytes within the cell content area.
74581 */
74582 if( heap[0]==0 && nFrag!=data[hdr+7] ){
74583 checkAppendMsg(pCheck,
74584 "Fragmentation of %d bytes reported as %d on page %u",
74585 nFrag, data[hdr+7], iPage);
74586 }
74587 }
74588
74589 end_of_check:
@@ -74494,25 +74607,44 @@
74607 **
74608 ** Write the number of error seen in *pnErr. Except for some memory
74609 ** allocation errors, an error message held in memory obtained from
74610 ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
74611 ** returned. If a memory allocation error occurs, NULL is returned.
74612 **
74613 ** If the first entry in aRoot[] is 0, that indicates that the list of
74614 ** root pages is incomplete. This is a "partial integrity-check". This
74615 ** happens when performing an integrity check on a single table. The
74616 ** zero is skipped, of course. But in addition, the freelist checks
74617 ** and the checks to make sure every page is referenced are also skipped,
74618 ** since obviously it is not possible to know which pages are covered by
74619 ** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
74620 ** checks are still performed.
74621 */
74622 SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
74623 sqlite3 *db, /* Database connection that is running the check */
74624 Btree *p, /* The btree to be checked */
74625 Pgno *aRoot, /* An array of root pages numbers for individual trees */
74626 int nRoot, /* Number of entries in aRoot[] */
74627 int mxErr, /* Stop reporting errors after this many */
74628 int *pnErr /* Write number of errors seen to this variable */
74629 ){
74630 Pgno i;
74631 IntegrityCk sCheck;
74632 BtShared *pBt = p->pBt;
74633 u64 savedDbFlags = pBt->db->flags;
74634 char zErr[100];
74635 int bPartial = 0; /* True if not checking all btrees */
74636 int bCkFreelist = 1; /* True to scan the freelist */
74637 VVA_ONLY( int nRef );
74638 assert( nRoot>0 );
74639
74640 /* aRoot[0]==0 means this is a partial check */
74641 if( aRoot[0]==0 ){
74642 assert( nRoot>1 );
74643 bPartial = 1;
74644 if( aRoot[1]!=1 ) bCkFreelist = 0;
74645 }
74646
74647 sqlite3BtreeEnter(p);
74648 assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
74649 VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
74650 assert( nRef>=0 );
@@ -74548,69 +74680,75 @@
74680 i = PENDING_BYTE_PAGE(pBt);
74681 if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
74682
74683 /* Check the integrity of the freelist
74684 */
74685 if( bCkFreelist ){
74686 sCheck.zPfx = "Main freelist: ";
74687 checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
74688 get4byte(&pBt->pPage1->aData[36]));
74689 sCheck.zPfx = 0;
74690 }
74691
74692 /* Check all the tables.
74693 */
74694 #ifndef SQLITE_OMIT_AUTOVACUUM
74695 if( !bPartial ){
74696 if( pBt->autoVacuum ){
74697 Pgno mx = 0;
74698 Pgno mxInHdr;
74699 for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
74700 mxInHdr = get4byte(&pBt->pPage1->aData[52]);
74701 if( mx!=mxInHdr ){
74702 checkAppendMsg(&sCheck,
74703 "max rootpage (%d) disagrees with header (%d)",
74704 mx, mxInHdr
74705 );
74706 }
74707 }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
74708 checkAppendMsg(&sCheck,
74709 "incremental_vacuum enabled with a max rootpage of zero"
74710 );
74711 }
74712 }
74713 #endif
74714 testcase( pBt->db->flags & SQLITE_CellSizeCk );
74715 pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
74716 for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
74717 i64 notUsed;
74718 if( aRoot[i]==0 ) continue;
74719 #ifndef SQLITE_OMIT_AUTOVACUUM
74720 if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
74721 checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
74722 }
74723 #endif
74724 checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
74725 }
74726 pBt->db->flags = savedDbFlags;
74727
74728 /* Make sure every page in the file is referenced
74729 */
74730 if( !bPartial ){
74731 for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
74732 #ifdef SQLITE_OMIT_AUTOVACUUM
74733 if( getPageReferenced(&sCheck, i)==0 ){
74734 checkAppendMsg(&sCheck, "Page %d is never used", i);
74735 }
74736 #else
74737 /* If the database supports auto-vacuum, make sure no tables contain
74738 ** references to pointer-map pages.
74739 */
74740 if( getPageReferenced(&sCheck, i)==0 &&
74741 (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
74742 checkAppendMsg(&sCheck, "Page %d is never used", i);
74743 }
74744 if( getPageReferenced(&sCheck, i)!=0 &&
74745 (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
74746 checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
74747 }
74748 #endif
74749 }
74750 }
74751
74752 /* Clean up and report errors.
74753 */
74754 integrity_ck_cleanup:
@@ -75794,20 +75932,29 @@
75932 ** into a buffer.
75933 */
75934 static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
75935 StrAccum acc;
75936 assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
75937 assert( sz>22 );
75938 if( p->flags & MEM_Int ){
75939 #if GCC_VERSION>=7000000
75940 /* Work-around for GCC bug
75941 ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
75942 i64 x;
75943 assert( (p->flags&MEM_Int)*2==sizeof(x) );
75944 memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
75945 sqlite3Int64ToText(x, zBuf);
75946 #else
75947 sqlite3Int64ToText(p->u.i, zBuf);
75948 #endif
75949 }else{
75950 sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
75951 sqlite3_str_appendf(&acc, "%!.15g",
75952 (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
75953 assert( acc.zText==zBuf && acc.mxAlloc<=0 );
75954 zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
75955 }
 
 
75956 }
75957
75958 #ifdef SQLITE_DEBUG
75959 /*
75960 ** Validity checks on pMem. pMem holds a string.
@@ -78397,11 +78544,11 @@
78544 /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
78545 ** cases from this switch! */
78546 switch( pOp->opcode ){
78547 case OP_Transaction: {
78548 if( pOp->p2!=0 ) p->readOnly = 0;
78549 /* no break */ deliberate_fall_through
78550 }
78551 case OP_AutoCommit:
78552 case OP_Savepoint: {
78553 p->bIsReader = 1;
78554 break;
@@ -78444,10 +78591,11 @@
78591 assert( (pOp - p->aOp) >= 3 );
78592 assert( pOp[-1].opcode==OP_Integer );
78593 n = pOp[-1].p1;
78594 if( n>nMaxArgs ) nMaxArgs = n;
78595 /* Fall through into the default case */
78596 /* no break */ deliberate_fall_through
78597 }
78598 #endif
78599 default: {
78600 if( pOp->p2<0 ){
78601 /* The mkopcodeh.tcl script has so arranged things that the only
@@ -79301,16 +79449,16 @@
79449 sqlite3_str_appendf(&x, "vtab:%p", pVtab);
79450 break;
79451 }
79452 #endif
79453 case P4_INTARRAY: {
79454 u32 i;
79455 u32 *ai = pOp->p4.ai;
79456 u32 n = ai[0]; /* The first element of an INTARRAY is always the
79457 ** count of the number of elements to follow */
79458 for(i=1; i<=n; i++){
79459 sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]);
79460 }
79461 sqlite3_str_append(&x, "]", 1);
79462 break;
79463 }
79464 case P4_SUBPROGRAM: {
@@ -81150,15 +81298,15 @@
81298 ** a NULL row.
81299 **
81300 ** If the cursor is already pointing to the correct row and that row has
81301 ** not been deleted out from under the cursor, then this routine is a no-op.
81302 */
81303 SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
81304 VdbeCursor *p = *pp;
81305 assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
81306 if( p->deferredMoveto ){
81307 u32 iMap;
81308 if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
81309 *pp = p->pAltCursor;
81310 *piCol = iMap - 1;
81311 return SQLITE_OK;
81312 }
@@ -82910,11 +83058,11 @@
83058 if( db->xProfile ){
83059 db->xProfile(db->pProfileArg, p->zSql, iElapse);
83060 }
83061 #endif
83062 if( db->mTrace & SQLITE_TRACE_PROFILE ){
83063 db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
83064 }
83065 p->startTime = 0;
83066 }
83067 /*
83068 ** The checkProfileCallback(DB,P) macro checks to see if a profile callback
@@ -86210,10 +86358,11 @@
86358 #ifdef SQLITE_DEBUG
86359 if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
86360 #endif
86361 if( (pIn3->flags & MEM_Null)==0 ) break;
86362 /* Fall through into OP_Halt */
86363 /* no break */ deliberate_fall_through
86364 }
86365
86366 /* Opcode: Halt P1 P2 * P4 P5
86367 **
86368 ** Exit immediately. All open cursors, etc are closed
@@ -86380,10 +86529,11 @@
86529 goto too_big;
86530 }
86531 pOp->opcode = OP_String;
86532 assert( rc==SQLITE_OK );
86533 /* Fall through to the next case, OP_String */
86534 /* no break */ deliberate_fall_through
86535 }
86536
86537 /* Opcode: String P1 P2 P3 P4 P5
86538 ** Synopsis: r[P2]='P4' (len=P1)
86539 **
@@ -86691,11 +86841,11 @@
86841 #endif
86842 }
86843 if( db->mallocFailed ) goto no_mem;
86844
86845 if( db->mTrace & SQLITE_TRACE_ROW ){
86846 db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
86847 }
86848
86849
86850 /* Return SQLITE_ROW
86851 */
@@ -87427,14 +87577,14 @@
87577 int n;
87578 int i;
87579 int p1;
87580 int p2;
87581 const KeyInfo *pKeyInfo;
87582 u32 idx;
87583 CollSeq *pColl; /* Collating sequence to use on this term */
87584 int bRev; /* True for DESCENDING sort order */
87585 u32 *aPermute; /* The permutation */
87586
87587 if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
87588 aPermute = 0;
87589 }else{
87590 assert( pOp>aOp );
@@ -87450,20 +87600,20 @@
87600 p1 = pOp->p1;
87601 p2 = pOp->p2;
87602 #ifdef SQLITE_DEBUG
87603 if( aPermute ){
87604 int k, mx = 0;
87605 for(k=0; k<n; k++) if( aPermute[k]>(u32)mx ) mx = aPermute[k];
87606 assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
87607 assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
87608 }else{
87609 assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
87610 assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
87611 }
87612 #endif /* SQLITE_DEBUG */
87613 for(i=0; i<n; i++){
87614 idx = aPermute ? aPermute[i] : (u32)i;
87615 assert( memIsValid(&aMem[p1+idx]) );
87616 assert( memIsValid(&aMem[p2+idx]) );
87617 REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
87618 REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
87619 assert( i<pKeyInfo->nKeyField );
@@ -87770,11 +87920,11 @@
87920 ** the result is guaranteed to only be used as the argument of a length()
87921 ** or typeof() function, respectively. The loading of large blobs can be
87922 ** skipped for length() and all content loading can be skipped for typeof().
87923 */
87924 case OP_Column: {
87925 u32 p2; /* column number to retrieve */
87926 VdbeCursor *pC; /* The VDBE cursor */
87927 BtCursor *pCrsr; /* The BTree cursor */
87928 u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
87929 int len; /* The length of the serialized data for the column */
87930 int i; /* Loop counter */
@@ -87788,11 +87938,11 @@
87938 Mem *pReg; /* PseudoTable input register */
87939
87940 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
87941 pC = p->apCsr[pOp->p1];
87942 assert( pC!=0 );
87943 p2 = (u32)pOp->p2;
87944
87945 /* If the cursor cache is stale (meaning it is not currently point at
87946 ** the correct row) then bring it up-to-date by doing the necessary
87947 ** B-Tree seek. */
87948 rc = sqlite3VdbeCursorMoveto(&pC, &p2);
@@ -87800,11 +87950,11 @@
87950
87951 assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
87952 pDest = &aMem[pOp->p3];
87953 memAboutToChange(p, pDest);
87954 assert( pC!=0 );
87955 assert( p2<(u32)pC->nField );
87956 aOffset = pC->aOffset;
87957 assert( pC->eCurType!=CURTYPE_VTAB );
87958 assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
87959 assert( pC->eCurType!=CURTYPE_SORTER );
87960
@@ -87915,11 +88065,11 @@
88065 zHdr += sqlite3GetVarint32(zHdr, &t);
88066 pC->aType[i] = t;
88067 offset64 += sqlite3VdbeSerialTypeLen(t);
88068 }
88069 aOffset[++i] = (u32)(offset64 & 0xffffffff);
88070 }while( (u32)i<=p2 && zHdr<zEndHdr );
88071
88072 /* The record is corrupt if any of the following are true:
88073 ** (1) the bytes of the header extend past the declared header size
88074 ** (2) the entire header was used but not all data was used
88075 ** (3) the end of the data extends beyond the end of the record.
@@ -88939,11 +89089,11 @@
89089 ** See also: OP_OpenRead, OP_ReopenIdx
89090 */
89091 case OP_ReopenIdx: {
89092 int nField;
89093 KeyInfo *pKeyInfo;
89094 u32 p2;
89095 int iDb;
89096 int wrFlag;
89097 Btree *pX;
89098 VdbeCursor *pCur;
89099 Db *pDb;
@@ -88970,11 +89120,11 @@
89120 goto abort_due_to_error;
89121 }
89122
89123 nField = 0;
89124 pKeyInfo = 0;
89125 p2 = (u32)pOp->p2;
89126 iDb = pOp->p3;
89127 assert( iDb>=0 && iDb<db->nDb );
89128 assert( DbMaskTest(p->btreeMask, iDb) );
89129 pDb = &db->aDb[iDb];
89130 pX = pDb->pBt;
@@ -88989,11 +89139,11 @@
89139 }else{
89140 wrFlag = 0;
89141 }
89142 if( pOp->p5 & OPFLAG_P2ISREG ){
89143 assert( p2>0 );
89144 assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
89145 assert( pOp->opcode==OP_OpenWrite );
89146 pIn2 = &aMem[p2];
89147 assert( memIsValid(pIn2) );
89148 assert( (pIn2->flags & MEM_Int)!=0 );
89149 sqlite3VdbeMemIntegerify(pIn2);
@@ -89142,11 +89292,11 @@
89292 ** opening it. If a transient table is required, just use the
89293 ** automatically created table with root-page 1 (an BLOB_INTKEY table).
89294 */
89295 if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
89296 assert( pOp->p4type==P4_KEYINFO );
89297 rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
89298 BTREE_BLOBKEY | pOp->p5);
89299 if( rc==SQLITE_OK ){
89300 assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
89301 assert( pKeyInfo->db==db );
89302 assert( pKeyInfo->enc==ENC(db) );
@@ -89684,10 +89834,11 @@
89834 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
89835 pC = p->apCsr[pOp->p1];
89836 assert( pC!=0 );
89837 if( pC->seekHit ) break;
89838 /* Fall through into OP_NotFound */
89839 /* no break */ deliberate_fall_through
89840 }
89841 case OP_NoConflict: /* jump, in3 */
89842 case OP_NotFound: /* jump, in3 */
89843 case OP_Found: { /* jump, in3 */
89844 int alreadyExists;
@@ -89838,10 +89989,11 @@
89989 if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
89990 iKey = x.u.i;
89991 goto notExistsWithKey;
89992 }
89993 /* Fall through into OP_NotExists */
89994 /* no break */ deliberate_fall_through
89995 case OP_NotExists: /* jump, in3 */
89996 pIn3 = &aMem[pOp->p3];
89997 assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
89998 assert( pOp->p1>=0 && pOp->p1<p->nCursor );
89999 iKey = pIn3->u.i;
@@ -90406,14 +90558,10 @@
90558 ** generator) then the fix would be to insert a call to
90559 ** sqlite3VdbeCursorMoveto().
90560 */
90561 assert( pC->deferredMoveto==0 );
90562 assert( sqlite3BtreeCursorIsValid(pCrsr) );
 
 
 
 
90563
90564 n = sqlite3BtreePayloadSize(pCrsr);
90565 if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
90566 goto too_big;
90567 }
@@ -90613,10 +90761,11 @@
90761 sqlite3_sort_count++;
90762 sqlite3_search_count--;
90763 #endif
90764 p->aCounter[SQLITE_STMTSTATUS_SORT]++;
90765 /* Fall through into OP_Rewind */
90766 /* no break */ deliberate_fall_through
90767 }
90768 /* Opcode: Rewind P1 P2 * * *
90769 **
90770 ** The next use of the Rowid or Column or Next instruction for P1
90771 ** will refer to the first entry in the database table or index.
@@ -91179,11 +91328,11 @@
91328 sqlite3VdbeIncrWriteCounter(p, 0);
91329 nChange = 0;
91330 assert( p->readOnly==0 );
91331 assert( DbMaskTest(p->btreeMask, pOp->p2) );
91332 rc = sqlite3BtreeClearTable(
91333 db->aDb[pOp->p2].pBt, (u32)pOp->p1, (pOp->p3 ? &nChange : 0)
91334 );
91335 if( pOp->p3 ){
91336 p->nChange += nChange;
91337 if( pOp->p3>0 ){
91338 assert( memIsValid(&aMem[pOp->p3]) );
@@ -91228,11 +91377,11 @@
91377 ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
91378 ** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table.
91379 ** The root page number of the new b-tree is stored in register P2.
91380 */
91381 case OP_CreateBtree: { /* out2 */
91382 Pgno pgno;
91383 Db *pDb;
91384
91385 sqlite3VdbeIncrWriteCounter(p, 0);
91386 pOut = out2Prerelease(p, pOp);
91387 pgno = 0;
@@ -91303,10 +91452,11 @@
91452 zSchema = DFLT_SCHEMA_TABLE;
91453 initData.db = db;
91454 initData.iDb = iDb;
91455 initData.pzErrMsg = &p->zErrMsg;
91456 initData.mInitFlags = 0;
91457 initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt);
91458 zSql = sqlite3MPrintf(db,
91459 "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
91460 db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
91461 if( zSql==0 ){
91462 rc = SQLITE_NOMEM_BKPT;
@@ -91416,20 +91566,20 @@
91566 **
91567 ** This opcode is used to implement the integrity_check pragma.
91568 */
91569 case OP_IntegrityCk: {
91570 int nRoot; /* Number of tables to check. (Number of root pages.) */
91571 Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */
91572 int nErr; /* Number of errors reported */
91573 char *z; /* Text of the error report */
91574 Mem *pnErr; /* Register keeping track of errors remaining */
91575
91576 assert( p->bIsReader );
91577 nRoot = pOp->p2;
91578 aRoot = pOp->p4.ai;
91579 assert( nRoot>0 );
91580 assert( aRoot[0]==(Pgno)nRoot );
91581 assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
91582 pnErr = &aMem[pOp->p3];
91583 assert( (pnErr->flags & MEM_Int)!=0 );
91584 assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
91585 pIn1 = &aMem[pOp->p1];
@@ -91965,10 +92115,11 @@
92115 /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
92116 assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
92117
92118 pOp->opcode = OP_AggStep1;
92119 /* Fall through into OP_AggStep */
92120 /* no break */ deliberate_fall_through
92121 }
92122 case OP_AggStep1: {
92123 int i;
92124 sqlite3_context *pCtx;
92125 Mem *pMem;
@@ -92954,22 +93105,21 @@
93105 && !p->doingRerun
93106 && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
93107 ){
93108 #ifndef SQLITE_OMIT_DEPRECATED
93109 if( db->mTrace & SQLITE_TRACE_LEGACY ){
 
93110 char *z = sqlite3VdbeExpandSql(p, zTrace);
93111 db->trace.xLegacy(db->pTraceArg, z);
93112 sqlite3_free(z);
93113 }else
93114 #endif
93115 if( db->nVdbeExec>1 ){
93116 char *z = sqlite3MPrintf(db, "-- %s", zTrace);
93117 (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
93118 sqlite3DbFree(db, z);
93119 }else{
93120 (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
93121 }
93122 }
93123 #ifdef SQLITE_USE_FCNTL_TRACE
93124 zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
93125 if( zTrace ){
@@ -96701,11 +96851,11 @@
96851 }else{
96852 if( i<=2 && pCur->zType==0 ){
96853 Schema *pSchema;
96854 HashElem *k;
96855 int iDb = pOp->p3;
96856 Pgno iRoot = (Pgno)pOp->p2;
96857 sqlite3 *db = pVTab->db;
96858 pSchema = db->aDb[iDb].pSchema;
96859 pCur->zSchema = db->aDb[iDb].zDbSName;
96860 for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
96861 Table *pTab = (Table*)sqliteHashData(k);
@@ -97288,11 +97438,11 @@
97438 }else{
97439 p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
97440 assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
97441 }
97442
97443 pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
97444 p->nSpill = nSpill;
97445 p->flags = flags;
97446 p->zJournal = zName;
97447 p->pVfs = pVfs;
97448 return SQLITE_OK;
@@ -97314,11 +97464,11 @@
97464 ** file has not yet been created, create it now.
97465 */
97466 SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
97467 int rc = SQLITE_OK;
97468 MemJournal *p = (MemJournal*)pJfd;
97469 if( pJfd->pMethods==&MemJournalMethods && (
97470 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
97471 p->nSpill>0
97472 #else
97473 /* While this appears to not be possible without ATOMIC_WRITE, the
97474 ** paths are complex, so it seems prudent to leave the test in as
@@ -98687,11 +98837,11 @@
98837 pExpr->op2 = pExpr->op;
98838 pExpr->op = TK_TRUTH;
98839 return WRC_Continue;
98840 }
98841 }
98842 /* no break */ deliberate_fall_through
98843 }
98844 case TK_BETWEEN:
98845 case TK_EQ:
98846 case TK_NE:
98847 case TK_LT:
@@ -101591,11 +101741,11 @@
101741 /* Convert "true" or "false" in a DEFAULT clause into the
101742 ** appropriate TK_TRUEFALSE operator */
101743 if( sqlite3ExprIdToTrueFalse(pExpr) ){
101744 return WRC_Prune;
101745 }
101746 /* no break */ deliberate_fall_through
101747 case TK_COLUMN:
101748 case TK_AGG_FUNCTION:
101749 case TK_AGG_COLUMN:
101750 testcase( pExpr->op==TK_ID );
101751 testcase( pExpr->op==TK_COLUMN );
@@ -101605,11 +101755,11 @@
101755 return WRC_Continue;
101756 }
101757 if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
101758 return WRC_Continue;
101759 }
101760 /* no break */ deliberate_fall_through
101761 case TK_IF_NULL_ROW:
101762 case TK_REGISTER:
101763 case TK_DOT:
101764 testcase( pExpr->op==TK_REGISTER );
101765 testcase( pExpr->op==TK_IF_NULL_ROW );
@@ -101626,11 +101776,11 @@
101776 /* A bound parameter in a CREATE statement that originates from
101777 ** sqlite3_prepare() causes an error */
101778 pWalker->eCode = 0;
101779 return WRC_Abort;
101780 }
101781 /* no break */ deliberate_fall_through
101782 default:
101783 testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
101784 testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
101785 return WRC_Continue;
101786 }
@@ -103398,10 +103548,11 @@
103548 }
103549 }
103550 return target;
103551 }
103552 /* Otherwise, fall thru into the TK_COLUMN case */
103553 /* no break */ deliberate_fall_through
103554 }
103555 case TK_COLUMN: {
103556 int iTab = pExpr->iTable;
103557 int iReg;
103558 if( ExprHasProperty(pExpr, EP_FixedCol) ){
@@ -104463,11 +104614,11 @@
104614 case TK_ISNOT:
104615 testcase( op==TK_IS );
104616 testcase( op==TK_ISNOT );
104617 op = (op==TK_IS) ? TK_EQ : TK_NE;
104618 jumpIfNull = SQLITE_NULLEQ;
104619 /* no break */ deliberate_fall_through
104620 case TK_LT:
104621 case TK_LE:
104622 case TK_GT:
104623 case TK_GE:
104624 case TK_NE:
@@ -104639,11 +104790,11 @@
104790 case TK_ISNOT:
104791 testcase( pExpr->op==TK_IS );
104792 testcase( pExpr->op==TK_ISNOT );
104793 op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
104794 jumpIfNull = SQLITE_NULLEQ;
104795 /* no break */ deliberate_fall_through
104796 case TK_LT:
104797 case TK_LE:
104798 case TK_GT:
104799 case TK_GE:
104800 case TK_NE:
@@ -104951,17 +105102,17 @@
105102 case TK_BITOR:
105103 case TK_LSHIFT:
105104 case TK_RSHIFT:
105105 case TK_CONCAT:
105106 seenNot = 1;
105107 /* no break */ deliberate_fall_through
105108 case TK_STAR:
105109 case TK_REM:
105110 case TK_BITAND:
105111 case TK_SLASH: {
105112 if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
105113 /* no break */ deliberate_fall_through
105114 }
105115 case TK_SPAN:
105116 case TK_COLLATE:
105117 case TK_UPLUS:
105118 case TK_UMINUS: {
@@ -105106,10 +105257,11 @@
105257 || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0)
105258 && IsVirtual(pRight->y.pTab))
105259 ){
105260 return WRC_Prune;
105261 }
105262 /* no break */ deliberate_fall_through
105263 }
105264 default:
105265 return WRC_Continue;
105266 }
105267 }
@@ -106839,11 +106991,11 @@
106991 }
106992 if( rc==SQLITE_OK && pStep->zTarget ){
106993 SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
106994 if( pSrc ){
106995 int i;
106996 for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
106997 struct SrcList_item *p = &pSrc->a[i];
106998 p->pTab = sqlite3LocateTableItem(pParse, 0, p);
106999 p->iCursor = pParse->nTab++;
107000 if( p->pTab==0 ){
107001 rc = SQLITE_ERROR;
@@ -107581,11 +107733,11 @@
107733 };
107734 int i;
107735 sqlite3 *db = pParse->db;
107736 Db *pDb;
107737 Vdbe *v = sqlite3GetVdbe(pParse);
107738 u32 aRoot[ArraySize(aTable)];
107739 u8 aCreateTbl[ArraySize(aTable)];
107740 #ifdef SQLITE_ENABLE_STAT4
107741 const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
107742 #else
107743 const int nToOpen = 1;
@@ -107610,11 +107762,11 @@
107762 ** of the new table in register pParse->regRoot. This is important
107763 ** because the OpenWrite opcode below will be needing it. */
107764 sqlite3NestedParse(pParse,
107765 "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
107766 );
107767 aRoot[i] = (u32)pParse->regRoot;
107768 aCreateTbl[i] = OPFLAG_P2ISREG;
107769 }
107770 }else{
107771 /* The table already exists. If zWhere is not NULL, delete all entries
107772 ** associated with the table zWhere. If zWhere is NULL, delete the
@@ -107630,19 +107782,19 @@
107782 }else if( db->xPreUpdateCallback ){
107783 sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
107784 #endif
107785 }else{
107786 /* The sqlite_stat[134] table already exists. Delete all rows. */
107787 sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
107788 }
107789 }
107790 }
107791
107792 /* Open the sqlite_stat[134] tables for writing. */
107793 for(i=0; i<nToOpen; i++){
107794 assert( i<ArraySize(aTable) );
107795 sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
107796 sqlite3VdbeChangeP5(v, aCreateTbl[i]);
107797 VdbeComment((v, aTable[i].zName));
107798 }
107799 }
107800
@@ -110271,11 +110423,11 @@
110423 ** The TableLock structure is only used by the sqlite3TableLock() and
110424 ** codeTableLocks() functions.
110425 */
110426 struct TableLock {
110427 int iDb; /* The database containing the table to be locked */
110428 Pgno iTab; /* The root page of the table to be locked */
110429 u8 isWriteLock; /* True for write lock. False for a read lock */
110430 const char *zLockName; /* Name of the table */
110431 };
110432
110433 /*
@@ -110289,11 +110441,11 @@
110441 ** codeTableLocks() which occurs during sqlite3FinishCoding().
110442 */
110443 SQLITE_PRIVATE void sqlite3TableLock(
110444 Parse *pParse, /* Parsing context */
110445 int iDb, /* Index of the database containing the table to lock */
110446 Pgno iTab, /* Root page number of the table to be locked */
110447 u8 isWriteLock, /* True for a write lock */
110448 const char *zName /* Name of the table to be locked */
110449 ){
110450 Parse *pToplevel = sqlite3ParseToplevel(pParse);
110451 int i;
@@ -111128,23 +111280,24 @@
111280 const char *zName, /* Name of the object to check */
111281 const char *zType, /* Type of this object */
111282 const char *zTblName /* Parent table name for triggers and indexes */
111283 ){
111284 sqlite3 *db = pParse->db;
111285 if( sqlite3WritableSchema(db)
111286 || db->init.imposterTable
111287 || !sqlite3Config.bExtraSchemaChecks
111288 ){
111289 /* Skip these error checks for writable_schema=ON */
111290 return SQLITE_OK;
111291 }
111292 if( db->init.busy ){
111293 if( sqlite3_stricmp(zType, db->init.azInit[0])
111294 || sqlite3_stricmp(zName, db->init.azInit[1])
111295 || sqlite3_stricmp(zTblName, db->init.azInit[2])
111296 ){
111297 sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
111298 return SQLITE_ERROR;
 
 
111299 }
111300 }else{
111301 if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
111302 || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
111303 ){
@@ -112354,11 +112507,11 @@
112507 ** table entry. This is only required if currently generating VDBE
112508 ** code for a CREATE TABLE (not when parsing one as part of reading
112509 ** a database schema). */
112510 if( v && pPk->tnum>0 ){
112511 assert( db->init.busy==0 );
112512 sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto);
112513 }
112514
112515 /* The root page of the PRIMARY KEY is the table root page */
112516 pPk->tnum = pTab->tnum;
112517
@@ -112942,14 +113095,12 @@
113095 ** statement that defines the view.
113096 */
113097 assert( pTable->pSelect );
113098 pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
113099 if( pSel ){
 
113100 u8 eParseMode = pParse->eParseMode;
113101 pParse->eParseMode = PARSE_MODE_NORMAL;
 
113102 n = pParse->nTab;
113103 sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
113104 pTable->nCol = -1;
113105 DisableLookaside;
113106 #ifndef SQLITE_OMIT_AUTHORIZATION
@@ -112993,13 +113144,11 @@
113144 }
113145 pTable->nNVCol = pTable->nCol;
113146 sqlite3DeleteTable(db, pSelTab);
113147 sqlite3SelectDelete(db, pSel);
113148 EnableLookaside;
 
113149 pParse->eParseMode = eParseMode;
 
113150 } else {
113151 nErr++;
113152 }
113153 pTable->pSchema->schemaFlags |= DB_UnresetViews;
113154 if( db->mallocFailed ){
@@ -113050,11 +113199,11 @@
113199 ** We must continue looping until all tables and indices with
113200 ** rootpage==iFrom have been converted to have a rootpage of iTo
113201 ** in order to be certain that we got the right one.
113202 */
113203 #ifndef SQLITE_OMIT_AUTOVACUUM
113204 SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
113205 HashElem *pElem;
113206 Hash *pHash;
113207 Db *pDb;
113208
113209 assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
@@ -113127,22 +113276,22 @@
113276 ** and root page 5 happened to be the largest root-page number in the
113277 ** database, then root page 5 would be moved to page 4 by the
113278 ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
113279 ** a free-list page.
113280 */
113281 Pgno iTab = pTab->tnum;
113282 Pgno iDestroyed = 0;
113283
113284 while( 1 ){
113285 Index *pIdx;
113286 Pgno iLargest = 0;
113287
113288 if( iDestroyed==0 || iTab<iDestroyed ){
113289 iLargest = iTab;
113290 }
113291 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
113292 Pgno iIdx = pIdx->tnum;
113293 assert( pIdx->pSchema==pTab->pSchema );
113294 if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
113295 iLargest = iIdx;
113296 }
113297 }
@@ -113561,11 +113710,11 @@
113710 int iTab = pParse->nTab++; /* Btree cursor used for pTab */
113711 int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
113712 int iSorter; /* Cursor opened by OpenSorter (if in use) */
113713 int addr1; /* Address of top of loop */
113714 int addr2; /* Address to jump to for next iteration */
113715 Pgno tnum; /* Root page of index */
113716 int iPartIdxLabel; /* Jump to this label to skip a row */
113717 Vdbe *v; /* Generate code into this virtual machine */
113718 KeyInfo *pKey; /* KeyInfo for index */
113719 int regRecord; /* Register holding assembled index record */
113720 sqlite3 *db = pParse->db; /* The database connection */
@@ -113582,11 +113731,11 @@
113731 sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
113732
113733 v = sqlite3GetVdbe(pParse);
113734 if( v==0 ) return;
113735 if( memRootPage>=0 ){
113736 tnum = (Pgno)memRootPage;
113737 }else{
113738 tnum = pIndex->tnum;
113739 }
113740 pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
113741 assert( pKey!=0 || db->mallocFailed || pParse->nErr );
@@ -113607,11 +113756,11 @@
113756 sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
113757 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
113758 sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
113759 sqlite3VdbeJumpHere(v, addr1);
113760 if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
113761 sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb,
113762 (char *)pKey, P4_KEYINFO);
113763 sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
113764
113765 addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
113766 if( IsUniqueIndex(pIndex) ){
@@ -114216,11 +114365,11 @@
114365 ** doing so, code a Noop instruction and store its address in
114366 ** Index.tnum. This is required in case this index is actually a
114367 ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
114368 ** that case the convertToWithoutRowidTable() routine will replace
114369 ** the Noop with a Goto to jump over the VDBE code generated below. */
114370 pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop);
114371 sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
114372
114373 /* Gather the complete text of the CREATE INDEX statement into
114374 ** the zStmt variable
114375 */
@@ -114258,11 +114407,11 @@
114407 sqlite3VdbeAddParseSchemaOp(v, iDb,
114408 sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
114409 sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
114410 }
114411
114412 sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
114413 }
114414 }
114415 if( db->init.busy || pTblName==0 ){
114416 pIndex->pNext = pTab->pIndex;
114417 pTab->pIndex = pIndex;
@@ -114333,11 +114482,11 @@
114482 **
114483 ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
114484 ** table but other parts we are having to guess at, then do not let the
114485 ** estimated number of rows in the table be less than 1000 (LogEst 99).
114486 ** Failure to do this can cause the indexes for which we do not have
114487 ** stat1 data to be ignored by the query planner.
114488 */
114489 x = pIdx->pTable->nRowLogEst;
114490 assert( 99==sqlite3LogEst(1000) );
114491 if( x<99 ){
114492 pIdx->pTable->nRowLogEst = x = 99;
@@ -120309,10 +120458,11 @@
120458 case OE_Cascade:
120459 if( !pChanges ){
120460 pStep->op = TK_DELETE;
120461 break;
120462 }
120463 /* no break */ deliberate_fall_through
120464 default:
120465 pStep->op = TK_UPDATE;
120466 }
120467 pStep->pTrig = pTrigger;
120468 pTrigger->pSchema = pTab->pSchema;
@@ -120581,11 +120731,11 @@
120731 for(i=1; i<iEnd; i++){
120732 VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
120733 assert( pOp!=0 );
120734 if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
120735 Index *pIndex;
120736 Pgno tnum = pOp->p2;
120737 if( tnum==pTab->tnum ){
120738 return 1;
120739 }
120740 for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
120741 if( tnum==pIndex->tnum ){
@@ -122013,11 +122163,11 @@
122163 sqlite3VdbeJumpHere(v, addr1);
122164 break;
122165 }
122166 case OE_Abort:
122167 sqlite3MayAbort(pParse);
122168 /* no break */ deliberate_fall_through
122169 case OE_Rollback:
122170 case OE_Fail: {
122171 char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
122172 pCol->zName);
122173 sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
@@ -122241,11 +122391,11 @@
122391 VdbeCoverage(v);
122392
122393 switch( onError ){
122394 default: {
122395 onError = OE_Abort;
122396 /* no break */ deliberate_fall_through
122397 }
122398 case OE_Rollback:
122399 case OE_Abort:
122400 case OE_Fail: {
122401 testcase( onError==OE_Rollback );
@@ -122302,11 +122452,11 @@
122452 break;
122453 }
122454 #ifndef SQLITE_OMIT_UPSERT
122455 case OE_Update: {
122456 sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
122457 /* no break */ deliberate_fall_through
122458 }
122459 #endif
122460 case OE_Ignore: {
122461 testcase( onError==OE_Ignore );
122462 sqlite3VdbeGoto(v, ignoreDest);
@@ -122523,11 +122673,11 @@
122673 break;
122674 }
122675 #ifndef SQLITE_OMIT_UPSERT
122676 case OE_Update: {
122677 sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
122678 /* no break */ deliberate_fall_through
122679 }
122680 #endif
122681 case OE_Ignore: {
122682 testcase( onError==OE_Ignore );
122683 sqlite3VdbeGoto(v, ignoreDest);
@@ -126204,17 +126354,23 @@
126354 **
126355 ** Return the number of pages in the specified database.
126356 */
126357 case PragTyp_PAGE_COUNT: {
126358 int iReg;
126359 i64 x = 0;
126360 sqlite3CodeVerifySchema(pParse, iDb);
126361 iReg = ++pParse->nMem;
126362 if( sqlite3Tolower(zLeft[0])=='p' ){
126363 sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
126364 }else{
126365 if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){
126366 if( x<0 ) x = 0;
126367 else if( x>0xfffffffe ) x = 0xfffffffe;
126368 }else{
126369 x = 0;
126370 }
126371 sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x);
126372 }
126373 sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
126374 break;
126375 }
126376
@@ -127113,13 +127269,26 @@
127269 **
127270 ** The "quick_check" is reduced version of
127271 ** integrity_check designed to detect most database corruption
127272 ** without the overhead of cross-checking indexes. Quick_check
127273 ** is linear time wherease integrity_check is O(NlogN).
127274 **
127275 ** The maximum nubmer of errors is 100 by default. A different default
127276 ** can be specified using a numeric parameter N.
127277 **
127278 ** Or, the parameter N can be the name of a table. In that case, only
127279 ** the one table named is verified. The freelist is only verified if
127280 ** the named table is "sqlite_schema" (or one of its aliases).
127281 **
127282 ** All schemas are checked by default. To check just a single
127283 ** schema, use the form:
127284 **
127285 ** PRAGMA schema.integrity_check;
127286 */
127287 case PragTyp_INTEGRITY_CHECK: {
127288 int i, j, addr, mxErr;
127289 Table *pObjTab = 0; /* Check only this one table, if not NULL */
127290
127291 int isQuick = (sqlite3Tolower(zLeft[0])=='q');
127292
127293 /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
127294 ** then iDb is set to the index of the database identified by <db>.
@@ -127138,13 +127307,17 @@
127307 pParse->nMem = 6;
127308
127309 /* Set the maximum error count */
127310 mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
127311 if( zRight ){
127312 if( sqlite3GetInt32(zRight, &mxErr) ){
127313 if( mxErr<=0 ){
127314 mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
127315 }
127316 }else{
127317 pObjTab = sqlite3LocateTable(pParse, 0, zRight,
127318 iDb>=0 ? db->aDb[iDb].zDbSName : 0);
127319 }
127320 }
127321 sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
127322
127323 /* Do an integrity check on each database file */
@@ -127169,19 +127342,25 @@
127342 pTbls = &db->aDb[i].pSchema->tblHash;
127343 for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
127344 Table *pTab = sqliteHashData(x); /* Current table */
127345 Index *pIdx; /* An index on pTab */
127346 int nIdx; /* Number of indexes on pTab */
127347 if( pObjTab && pObjTab!=pTab ) continue;
127348 if( HasRowid(pTab) ) cnt++;
127349 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
127350 if( nIdx>mxIdx ) mxIdx = nIdx;
127351 }
127352 if( cnt==0 ) continue;
127353 if( pObjTab ) cnt++;
127354 aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
127355 if( aRoot==0 ) break;
127356 cnt = 0;
127357 if( pObjTab ) aRoot[++cnt] = 0;
127358 for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
127359 Table *pTab = sqliteHashData(x);
127360 Index *pIdx;
127361 if( pObjTab && pObjTab!=pTab ) continue;
127362 if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
127363 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
127364 aRoot[++cnt] = pIdx->tnum;
127365 }
127366 }
@@ -127211,10 +127390,11 @@
127390 int loopTop;
127391 int iDataCur, iIdxCur;
127392 int r1 = -1;
127393
127394 if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
127395 if( pObjTab && pObjTab!=pTab ) continue;
127396 pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
127397 sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
127398 1, 0, &iDataCur, &iIdxCur);
127399 /* reg[7] counts the number of entries in the table.
127400 ** reg[8+i] counts the number of entries in the i-th index
@@ -128272,11 +128452,17 @@
128452 sqlite3_stmt *pStmt;
128453 TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
128454
128455 assert( db->init.busy );
128456 db->init.iDb = iDb;
128457 if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0
128458 || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
128459 ){
128460 if( sqlite3Config.bExtraSchemaChecks ){
128461 corruptSchema(pData, argv[1], "invalid rootpage");
128462 }
128463 }
128464 db->init.orphanTrigger = 0;
128465 db->init.azInit = argv;
128466 pStmt = 0;
128467 TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
128468 rc = db->errCode;
@@ -128305,16 +128491,21 @@
128491 ** been created when we processed the CREATE TABLE. All we have
128492 ** to do here is record the root page number for that index.
128493 */
128494 Index *pIndex;
128495 pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
128496 if( pIndex==0 ){
128497 corruptSchema(pData, argv[1], "orphan index");
128498 }else
128499 if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
128500 || pIndex->tnum<2
128501 || pIndex->tnum>pData->mxPage
128502 || sqlite3IndexHasDuplicateRootPage(pIndex)
128503 ){
128504 if( sqlite3Config.bExtraSchemaChecks ){
128505 corruptSchema(pData, argv[1], "invalid rootpage");
128506 }
128507 }
128508 }
128509 return 0;
128510 }
128511
@@ -128364,10 +128555,11 @@
128555 initData.iDb = iDb;
128556 initData.rc = SQLITE_OK;
128557 initData.pzErrMsg = pzErrMsg;
128558 initData.mInitFlags = mFlags;
128559 initData.nInitRow = 0;
128560 initData.mxPage = 0;
128561 sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
128562 db->mDbFlags &= mask;
128563 if( initData.rc ){
128564 rc = initData.rc;
128565 goto error_out;
@@ -128486,10 +128678,11 @@
128678 }
128679
128680 /* Read the schema information out of the schema tables
128681 */
128682 assert( db->init.busy );
128683 initData.mxPage = sqlite3BtreeLastPage(pDb->pBt);
128684 {
128685 char *zSql;
128686 zSql = sqlite3MPrintf(db,
128687 "SELECT*FROM\"%w\".%s ORDER BY rowid",
128688 db->aDb[iDb].zDbSName, zSchemaTabName);
@@ -129368,12 +129561,14 @@
129561 ** Return the index of a column in a table. Return -1 if the column
129562 ** is not contained in the table.
129563 */
129564 static int columnIndex(Table *pTab, const char *zCol){
129565 int i;
129566 u8 h = sqlite3StrIHash(zCol);
129567 Column *pCol;
129568 for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
129569 if( pCol->hName==h && sqlite3StrICmp(pCol->zName, zCol)==0 ) return i;
129570 }
129571 return -1;
129572 }
129573
129574 /*
@@ -130231,20 +130426,24 @@
130426 sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
130427 break;
130428 }
130429
130430 case SRT_Upfrom: {
 
130431 if( pSort ){
130432 pushOntoSorter(
130433 pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
130434 }else{
 
 
130435 int i2 = pDest->iSDParm2;
130436 int r1 = sqlite3GetTempReg(pParse);
130437
130438 /* If the UPDATE FROM join is an aggregate that matches no rows, it
130439 ** might still be trying to return one row, because that is what
130440 ** aggregates do. Don't record that empty row in the output table. */
130441 sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v);
130442
130443 sqlite3VdbeAddOp3(v, OP_MakeRecord,
130444 regResult+(i2<0), nResultCol-(i2<0), r1);
130445 if( i2<0 ){
130446 sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
130447 }else{
130448 sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
130449 }
@@ -130682,11 +130881,10 @@
130881 case SRT_Mem: {
130882 /* The LIMIT clause will terminate the loop for us */
130883 break;
130884 }
130885 #endif
 
130886 case SRT_Upfrom: {
130887 int i2 = pDest->iSDParm2;
130888 int r1 = sqlite3GetTempReg(pParse);
130889 sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
130890 if( i2<0 ){
@@ -130694,11 +130892,10 @@
130892 }else{
130893 sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
130894 }
130895 break;
130896 }
 
130897 default: {
130898 assert( eDest==SRT_Output || eDest==SRT_Coroutine );
130899 testcase( eDest==SRT_Output );
130900 testcase( eDest==SRT_Coroutine );
130901 if( eDest==SRT_Output ){
@@ -132281,11 +132478,11 @@
132478 KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
132479 KeyInfo *pKeyMerge; /* Comparison information for merging rows */
132480 sqlite3 *db; /* Database connection */
132481 ExprList *pOrderBy; /* The ORDER BY clause */
132482 int nOrderBy; /* Number of terms in the ORDER BY clause */
132483 u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */
132484
132485 assert( p->pOrderBy!=0 );
132486 assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
132487 db = pParse->db;
132488 v = pParse->pVdbe;
@@ -132330,11 +132527,11 @@
132527 ** row of results comes from selectA or selectB. Also add explicit
132528 ** collations to the ORDER BY clause terms so that when the subqueries
132529 ** to the right and the left are evaluated, they use the correct
132530 ** collation.
132531 */
132532 aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
132533 if( aPermute ){
132534 struct ExprList_item *pItem;
132535 aPermute[0] = nOrderBy;
132536 for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
132537 assert( pItem->u.x.iOrderByCol>0 );
@@ -133286,11 +133483,11 @@
133483 sqlite3AggInfoPersistWalkerInit(&w, pParse);
133484 sqlite3WalkSelect(&w,pSub1);
133485 sqlite3SelectDelete(db, pSub1);
133486
133487 #if SELECTTRACE_ENABLED
133488 if( sqlite3_unsupported_selecttrace & 0x100 ){
133489 SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
133490 sqlite3TreeViewSelect(0, p, 0);
133491 }
133492 #endif
133493
@@ -134724,11 +134921,11 @@
134921 sWalker.pParse = pParse;
134922 sWalker.xExprCallback = havingToWhereExprCb;
134923 sWalker.u.pSelect = p;
134924 sqlite3WalkExpr(&sWalker, p->pHaving);
134925 #if SELECTTRACE_ENABLED
134926 if( sWalker.eCode && (sqlite3_unsupported_selecttrace & 0x100)!=0 ){
134927 SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
134928 sqlite3TreeViewSelect(0, p, 0);
134929 }
134930 #endif
134931 }
@@ -134846,11 +135043,11 @@
135043 }
135044 p->pEList->a[0].pExpr = pExpr;
135045 p->selFlags &= ~SF_Aggregate;
135046
135047 #if SELECTTRACE_ENABLED
135048 if( sqlite3_unsupported_selecttrace & 0x400 ){
135049 SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
135050 sqlite3TreeViewSelect(0, p, 0);
135051 }
135052 #endif
135053 return 1;
@@ -134899,11 +135096,11 @@
135096 return 1;
135097 }
135098 if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
135099 #if SELECTTRACE_ENABLED
135100 SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
135101 if( sqlite3_unsupported_selecttrace & 0x100 ){
135102 sqlite3TreeViewSelect(0, p, 0);
135103 }
135104 #endif
135105
135106 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
@@ -134926,11 +135123,11 @@
135123 if( pParse->nErr || db->mallocFailed ){
135124 goto select_end;
135125 }
135126 assert( p->pEList!=0 );
135127 #if SELECTTRACE_ENABLED
135128 if( sqlite3_unsupported_selecttrace & 0x104 ){
135129 SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
135130 sqlite3TreeViewSelect(0, p, 0);
135131 }
135132 #endif
135133
@@ -134961,11 +135158,11 @@
135158 if( rc ){
135159 assert( db->mallocFailed || pParse->nErr>0 );
135160 goto select_end;
135161 }
135162 #if SELECTTRACE_ENABLED
135163 if( p->pWin && (sqlite3_unsupported_selecttrace & 0x108)!=0 ){
135164 SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
135165 sqlite3TreeViewSelect(0, p, 0);
135166 }
135167 #endif
135168 #endif /* SQLITE_OMIT_WINDOWFUNC */
@@ -135068,11 +135265,11 @@
135265 */
135266 if( p->pPrior ){
135267 rc = multiSelect(pParse, p, pDest);
135268 #if SELECTTRACE_ENABLED
135269 SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
135270 if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
135271 sqlite3TreeViewSelect(0, p, 0);
135272 }
135273 #endif
135274 if( p->pNext==0 ) ExplainQueryPlanPop(pParse);
135275 return rc;
@@ -135087,11 +135284,11 @@
135284 if( pTabList->nSrc>1
135285 && OptimizationEnabled(db, SQLITE_PropagateConst)
135286 && propagateConstants(pParse, p)
135287 ){
135288 #if SELECTTRACE_ENABLED
135289 if( sqlite3_unsupported_selecttrace & 0x100 ){
135290 SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
135291 sqlite3TreeViewSelect(0, p, 0);
135292 }
135293 #endif
135294 }else{
@@ -135175,11 +135372,11 @@
135372 if( OptimizationEnabled(db, SQLITE_PushDown)
135373 && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
135374 (pItem->fg.jointype & JT_OUTER)!=0)
135375 ){
135376 #if SELECTTRACE_ENABLED
135377 if( sqlite3_unsupported_selecttrace & 0x100 ){
135378 SELECTTRACE(0x100,pParse,p,
135379 ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
135380 sqlite3TreeViewSelect(0, p, 0);
135381 }
135382 #endif
@@ -135275,11 +135472,11 @@
135472 pGroupBy = p->pGroupBy;
135473 pHaving = p->pHaving;
135474 sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
135475
135476 #if SELECTTRACE_ENABLED
135477 if( sqlite3_unsupported_selecttrace & 0x400 ){
135478 SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
135479 sqlite3TreeViewSelect(0, p, 0);
135480 }
135481 #endif
135482
@@ -135311,11 +135508,11 @@
135508 ** the sDistinct.isTnct is still set. Hence, isTnct represents the
135509 ** original setting of the SF_Distinct flag, not the current setting */
135510 assert( sDistinct.isTnct );
135511
135512 #if SELECTTRACE_ENABLED
135513 if( sqlite3_unsupported_selecttrace & 0x400 ){
135514 SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
135515 sqlite3TreeViewSelect(0, p, 0);
135516 }
135517 #endif
135518 }
@@ -135559,11 +135756,11 @@
135756 sNC.ncFlags &= ~NC_InAggFunc;
135757 }
135758 pAggInfo->mxReg = pParse->nMem;
135759 if( db->mallocFailed ) goto select_end;
135760 #if SELECTTRACE_ENABLED
135761 if( sqlite3_unsupported_selecttrace & 0x400 ){
135762 int ii;
135763 SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
135764 sqlite3TreeViewSelect(0, p, 0);
135765 for(ii=0; ii<pAggInfo->nColumn; ii++){
135766 sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
@@ -135823,11 +136020,11 @@
136020 const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
136021 const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
136022 Index *pIdx; /* Iterator variable */
136023 KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
136024 Index *pBest = 0; /* Best index found so far */
136025 Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */
136026
136027 sqlite3CodeVerifySchema(pParse, iDb);
136028 sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
136029
136030 /* Search for the index that has the lowest scan cost.
@@ -135855,11 +136052,11 @@
136052 iRoot = pBest->tnum;
136053 pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
136054 }
136055
136056 /* Open a read-only cursor, execute the OP_Count, close the cursor. */
136057 sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1);
136058 if( pKeyInfo ){
136059 sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
136060 }
136061 sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
136062 sqlite3VdbeAddOp1(v, OP_Close, iCsr);
@@ -135978,11 +136175,11 @@
136175 }
136176 #endif
136177
136178 #if SELECTTRACE_ENABLED
136179 SELECTTRACE(0x1,pParse,p,("end processing\n"));
136180 if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
136181 sqlite3TreeViewSelect(0, p, 0);
136182 }
136183 #endif
136184 ExplainQueryPlanPop(pParse);
136185 return rc;
@@ -142375,11 +142572,11 @@
142572 if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
142573 && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
142574 ){
142575 int i;
142576 Table *pTab = pIdx->pTable;
142577 u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
142578 if( ai ){
142579 ai[0] = pTab->nCol;
142580 for(i=0; i<pIdx->nColumn-1; i++){
142581 int x1, x2;
142582 assert( pIdx->aiColumn[i]<pTab->nCol );
@@ -151749,11 +151946,11 @@
151946 assert( pWin->pOwner==pExpr );
151947 return WRC_Prune;
151948 }
151949 }
151950 }
151951 /* no break */ deliberate_fall_through
151952
151953 case TK_AGG_FUNCTION:
151954 case TK_COLUMN: {
151955 int iCol = -1;
151956 if( p->pSub ){
@@ -159966,10 +160163,11 @@
160163 *tokenType = TK_DOT;
160164 return 1;
160165 }
160166 /* If the next character is a digit, this is a floating point
160167 ** number that begins with ".". Fall thru into the next case */
160168 /* no break */ deliberate_fall_through
160169 }
160170 case CC_DIGIT: {
160171 testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
160172 testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
160173 testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
@@ -160070,10 +160268,11 @@
160268 return i;
160269 }
160270 #endif
160271 /* If it is not a BLOB literal, then it must be an ID, since no
160272 ** SQL keywords start with the letter 'x'. Fall through */
160273 /* no break */ deliberate_fall_through
160274 }
160275 case CC_ID: {
160276 i = 1;
160277 break;
160278 }
@@ -162000,11 +162199,11 @@
162199 if( !sqlite3SafetyCheckSickOrOk(db) ){
162200 return SQLITE_MISUSE_BKPT;
162201 }
162202 sqlite3_mutex_enter(db->mutex);
162203 if( db->mTrace & SQLITE_TRACE_CLOSE ){
162204 db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
162205 }
162206
162207 /* Force xDisconnect calls on all virtual tables */
162208 disconnectAllVtab(db);
162209
@@ -162889,11 +163088,11 @@
163088 }
163089 #endif
163090 sqlite3_mutex_enter(db->mutex);
163091 pOld = db->pTraceArg;
163092 db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
163093 db->trace.xLegacy = xTrace;
163094 db->pTraceArg = pArg;
163095 sqlite3_mutex_leave(db->mutex);
163096 return pOld;
163097 }
163098 #endif /* SQLITE_OMIT_DEPRECATED */
@@ -162913,11 +163112,11 @@
163112 #endif
163113 sqlite3_mutex_enter(db->mutex);
163114 if( mTrace==0 ) xTrace = 0;
163115 if( xTrace==0 ) mTrace = 0;
163116 db->mTrace = mTrace;
163117 db->trace.xV2 = xTrace;
163118 db->pTraceArg = pArg;
163119 sqlite3_mutex_leave(db->mutex);
163120 return SQLITE_OK;
163121 }
163122
@@ -164889,10 +165088,16 @@
165088 /* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
165089 **
165090 ** Set or clear a flag that causes SQLite to verify that type, name,
165091 ** and tbl_name fields of the sqlite_schema table. This is normally
165092 ** on, but it is sometimes useful to turn it off for testing.
165093 **
165094 ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
165095 ** verification of rootpage numbers when parsing the schema. This
165096 ** is useful to make it easier to reach strange internal error states
165097 ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
165098 ** in production.
165099 */
165100 case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
165101 sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
165102 break;
165103 }
@@ -166503,10 +166708,12 @@
166708 # define TESTONLY(X)
166709 #endif
166710
166711 #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
166712 #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
166713
166714 #define deliberate_fall_through
166715
166716 #endif /* SQLITE_AMALGAMATION */
166717
166718 #ifdef SQLITE_DEBUG
166719 SQLITE_PRIVATE int sqlite3Fts3Corrupt(void);
@@ -170146,11 +170353,11 @@
170353 }else if( p->zLanguageid==0 ){
170354 sqlite3_result_int(pCtx, 0);
170355 break;
170356 }else{
170357 iCol = p->nColumn;
170358 /* no break */ deliberate_fall_through
170359 }
170360
170361 default:
170362 /* A user column. Or, if this is a full-table scan, possibly the
170363 ** language-id column. Seek the cursor. */
@@ -170389,13 +170596,17 @@
170596 }
170597 if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return;
170598
170599 switch( nVal ){
170600 case 6: nToken = sqlite3_value_int(apVal[5]);
170601 /* no break */ deliberate_fall_through
170602 case 5: iCol = sqlite3_value_int(apVal[4]);
170603 /* no break */ deliberate_fall_through
170604 case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
170605 /* no break */ deliberate_fall_through
170606 case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
170607 /* no break */ deliberate_fall_through
170608 case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
170609 }
170610 if( !zEllipsis || !zEnd || !zStart ){
170611 sqlite3_result_error_nomem(pContext);
170612 }else if( nToken==0 ){
@@ -172498,11 +172709,12 @@
172709 ** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK );
172710 */
172711 fts3EvalRestart(pCsr, pRoot, &rc);
172712 do {
172713 fts3EvalNextRow(pCsr, pRoot, &rc);
172714 assert_fts3_nc( pRoot->bEof==0 );
172715 if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
172716 }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
172717 }
172718 }
172719 return rc;
172720 }
@@ -176607,11 +176819,12 @@
176819 rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr);
176820 }
176821
176822 assert( (rc==SQLITE_OK)==(pMod!=0) );
176823 if( rc==SQLITE_OK ){
176824 const char * const *azArg = 0;
176825 if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
176826 rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
176827 }
176828
176829 if( rc==SQLITE_OK ){
176830 pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable));
@@ -185252,10 +185465,14 @@
185465 #ifndef LARGEST_INT64
185466 # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
185467 # define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
185468 #endif
185469
185470 #ifndef deliberate_fall_through
185471 # define deliberate_fall_through
185472 #endif
185473
185474 /*
185475 ** Versions of isspace(), isalnum() and isdigit() to which it is safe
185476 ** to pass signed char values.
185477 */
185478 #ifdef sqlite3Isdigit
@@ -185670,11 +185887,11 @@
185887 case JSON_STRING: {
185888 if( pNode->jnFlags & JNODE_RAW ){
185889 jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
185890 break;
185891 }
185892 /* no break */ deliberate_fall_through
185893 }
185894 case JSON_REAL:
185895 case JSON_INT: {
185896 jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
185897 break;
@@ -185811,11 +186028,11 @@
186028 }
186029 if( pNode->u.zJContent[0]=='-' ){ i = -i; }
186030 sqlite3_result_int64(pCtx, i);
186031 int_done:
186032 break;
186033 int_as_real: i=0; /* no break */ deliberate_fall_through
186034 }
186035 case JSON_REAL: {
186036 double r;
186037 #ifdef SQLITE_AMALGAMATION
186038 const char *z = pNode->u.zJContent;
@@ -187514,10 +187731,11 @@
187731 jsonResult(&x);
187732 break;
187733 }
187734 /* For json_each() path and root are the same so fall through
187735 ** into the root case */
187736 /* no break */ deliberate_fall_through
187737 }
187738 default: {
187739 const char *zRoot = p->zRoot;
187740 if( zRoot==0 ) zRoot = "$";
187741 sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
@@ -187921,10 +188139,11 @@
188139 #endif
188140
188141 /* #include <string.h> */
188142 /* #include <stdio.h> */
188143 /* #include <assert.h> */
188144 /* #include <stdlib.h> */
188145
188146 /* The following macro is used to suppress compiler warnings.
188147 */
188148 #ifndef UNUSED_PARAMETER
188149 # define UNUSED_PARAMETER(x) (void)(x)
@@ -188258,10 +188477,27 @@
188477 */
188478 #ifndef SQLITE_AMALGAMATION
188479 # define testcase(X)
188480 #endif
188481
188482 /*
188483 ** Make sure that the compiler intrinsics we desire are enabled when
188484 ** compiling with an appropriate version of MSVC unless prevented by
188485 ** the SQLITE_DISABLE_INTRINSIC define.
188486 */
188487 #if !defined(SQLITE_DISABLE_INTRINSIC)
188488 # if defined(_MSC_VER) && _MSC_VER>=1400
188489 # if !defined(_WIN32_WCE)
188490 /* # include <intrin.h> */
188491 # pragma intrinsic(_byteswap_ulong)
188492 # pragma intrinsic(_byteswap_uint64)
188493 # else
188494 /* # include <cmnintrin.h> */
188495 # endif
188496 # endif
188497 #endif
188498
188499 /*
188500 ** Macros to determine whether the machine is big or little endian,
188501 ** and whether or not that determination is run-time or compile-time.
188502 **
188503 ** For best performance, an attempt is made to guess at the byte-order
@@ -205152,12 +205388,17 @@
205388 memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
205389 p->in.iNext += nCopy;
205390 }
205391
205392 p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
205393 if( p->apValue==0 ){
205394 p->abPK = 0;
205395 p->zTab = 0;
205396 }else{
205397 p->abPK = (u8*)&p->apValue[p->nCol*2];
205398 p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
205399 }
205400 return (p->rc = rc);
205401 }
205402
205403 /*
205404 ** Advance the changeset iterator to the next change.
@@ -225482,11 +225723,11 @@
225723 int nArg, /* Number of args */
225724 sqlite3_value **apUnused /* Function arguments */
225725 ){
225726 assert( nArg==0 );
225727 UNUSED_PARAM2(nArg, apUnused);
225728 sqlite3_result_text(pCtx, "fts5: 2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f", -1, SQLITE_TRANSIENT);
225729 }
225730
225731 /*
225732 ** Return true if zName is the extension on one of the shadow tables used
225733 ** by this module.
@@ -230265,12 +230506,12 @@
230506 }
230507 #endif /* SQLITE_CORE */
230508 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
230509
230510 /************** End of stmt.c ************************************************/
230511 #if __LINE__!=230511
230512 #undef SQLITE_SOURCE_ID
230513 #define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0alt2"
230514 #endif
230515 /* Return the source-id for this library */
230516 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
230517 /************************** End of sqlite3.c ******************************/
230518
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123123
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124124
** [sqlite_version()] and [sqlite_source_id()].
125125
*/
126126
#define SQLITE_VERSION "3.33.0"
127127
#define SQLITE_VERSION_NUMBER 3033000
128
-#define SQLITE_SOURCE_ID "2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829b9c3"
128
+#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f"
129129
130130
/*
131131
** CAPI3REF: Run-Time Library Version Numbers
132132
** KEYWORDS: sqlite3_version sqlite3_sourceid
133133
**
134134
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.33.0"
127 #define SQLITE_VERSION_NUMBER 3033000
128 #define SQLITE_SOURCE_ID "2020-07-18 18:59:11 020dbfa2aef20e5872cc3e785d99f45903843401292114b5092b9c8aa829b9c3"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.33.0"
127 #define SQLITE_VERSION_NUMBER 3033000
128 #define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
-13
--- src/stash.c
+++ src/stash.c
@@ -559,23 +559,10 @@
559559
** > fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
560560
**
561561
** Show diffs of the current working directory and what that
562562
** directory would be if STASHID were applied. With gdiff,
563563
** gdiff-command is used instead of internal diff logic.
564
-**
565
-** SUMMARY:
566
-** * fossil stash
567
-** * fossil stash save ?-m|--comment COMMENT? ?FILES...?
568
-** * fossil stash snapshot ?-m|--comment COMMENT? ?FILES...?
569
-** * fossil stash list|ls ?-v|--verbose? ?-W|--width <num>?
570
-** * fossil stash show|cat ?STASHID? ?DIFF-OPTIONS?
571
-** * fossil stash gshow|gcat ?STASHID? ?DIFF-OPTIONS?
572
-** * fossil stash pop
573
-** * fossil stash apply|goto ?STASHID?
574
-** * fossil stash drop|rm ?STASHID? ?-a|--all?
575
-** * fossil stash diff ?STASHID? ?DIFF-OPTIONS?
576
-** * fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
577564
*/
578565
void stash_cmd(void){
579566
const char *zCmd;
580567
int nCmd;
581568
int stashid = 0;
582569
--- src/stash.c
+++ src/stash.c
@@ -559,23 +559,10 @@
559 ** > fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
560 **
561 ** Show diffs of the current working directory and what that
562 ** directory would be if STASHID were applied. With gdiff,
563 ** gdiff-command is used instead of internal diff logic.
564 **
565 ** SUMMARY:
566 ** * fossil stash
567 ** * fossil stash save ?-m|--comment COMMENT? ?FILES...?
568 ** * fossil stash snapshot ?-m|--comment COMMENT? ?FILES...?
569 ** * fossil stash list|ls ?-v|--verbose? ?-W|--width <num>?
570 ** * fossil stash show|cat ?STASHID? ?DIFF-OPTIONS?
571 ** * fossil stash gshow|gcat ?STASHID? ?DIFF-OPTIONS?
572 ** * fossil stash pop
573 ** * fossil stash apply|goto ?STASHID?
574 ** * fossil stash drop|rm ?STASHID? ?-a|--all?
575 ** * fossil stash diff ?STASHID? ?DIFF-OPTIONS?
576 ** * fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
577 */
578 void stash_cmd(void){
579 const char *zCmd;
580 int nCmd;
581 int stashid = 0;
582
--- src/stash.c
+++ src/stash.c
@@ -559,23 +559,10 @@
559 ** > fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
560 **
561 ** Show diffs of the current working directory and what that
562 ** directory would be if STASHID were applied. With gdiff,
563 ** gdiff-command is used instead of internal diff logic.
 
 
 
 
 
 
 
 
 
 
 
 
 
564 */
565 void stash_cmd(void){
566 const char *zCmd;
567 int nCmd;
568 int stashid = 0;
569
+28 -10
--- src/stat.c
+++ src/stat.c
@@ -292,21 +292,25 @@
292292
@ </table>
293293
style_footer();
294294
}
295295
296296
/*
297
-** COMMAND: dbstat*
297
+** COMMAND: dbstat
298298
**
299299
** Usage: %fossil dbstat OPTIONS
300300
**
301
-** Shows statistics and global information about the repository.
301
+** Shows statistics and global information about the repository and/or
302
+** verify the integrity of a repository.
302303
**
303304
** Options:
304305
**
305
-** --brief|-b Only show essential elements
306
-** --db-check Run a PRAGMA quick_check on the repository database
307
-** --omit-version-info Omit the SQLite and Fossil version information
306
+** --brief|-b Only show essential elements.
307
+** --db-check Run "PRAGMA quick_check" on the repository database.
308
+** --db-verify Run a full verification of the repository integrity.
309
+** This involves decoding and reparsing all artifacts
310
+** and can take significant time.
311
+** --omit-version-info Omit the SQLite and Fossil version information.
308312
*/
309313
void dbstat_cmd(void){
310314
i64 t, fsize;
311315
int n, m;
312316
int szMax, szAvg;
@@ -317,10 +321,11 @@
317321
const char *p, *z;
318322
319323
brief = find_option("brief", "b",0)!=0;
320324
omitVers = find_option("omit-version-info", 0, 0)!=0;
321325
dbCheck = find_option("db-check",0,0)!=0;
326
+ if( find_option("db-verify",0,0)!=0 ) dbCheck = 2;
322327
db_find_and_open_repository(0,0);
323328
324329
/* We should be done with options.. */
325330
verify_all_options();
326331
@@ -384,13 +389,15 @@
384389
}
385390
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
386391
" + 0.99");
387392
fossil_print("%*s%,d days or approximately %.2f years.\n",
388393
colWidth, "project-age:", n, n/365.2425);
389
- p = db_get("project-code", 0);
390
- if( p ){
391
- fossil_print("%*s%s\n", colWidth, "project-id:", p);
394
+ if( !brief ){
395
+ p = db_get("project-code", 0);
396
+ if( p ){
397
+ fossil_print("%*s%s\n", colWidth, "project-id:", p);
398
+ }
392399
}
393400
#if 0
394401
/* Server-id is not useful information any more */
395402
fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0));
396403
#endif
@@ -412,12 +419,23 @@
412419
db_int(0, "PRAGMA repository.page_size"),
413420
db_int(0, "PRAGMA repository.freelist_count"),
414421
db_text(0, "PRAGMA repository.encoding"),
415422
db_text(0, "PRAGMA repository.journal_mode"));
416423
if( dbCheck ){
417
- fossil_print("%*s%s\n", colWidth, "database-check:",
418
- db_text(0, "PRAGMA quick_check(1)"));
424
+ if( dbCheck<2 ){
425
+ char *zRes = db_text(0, "PRAGMA repository.quick_check(1)");
426
+ fossil_print("%*s%s\n", colWidth, "database-check:", zRes);
427
+ }else{
428
+ char *newArgv[3];
429
+ newArgv[0] = g.argv[0];
430
+ newArgv[1] = "test-integrity";
431
+ newArgv[2] = 0;
432
+ g.argv = newArgv;
433
+ g.argc = 2;
434
+ fossil_print("Full repository verification follows:\n");
435
+ test_integrity();
436
+ }
419437
}
420438
}
421439
422440
/*
423441
** WEBPAGE: urllist
424442
--- src/stat.c
+++ src/stat.c
@@ -292,21 +292,25 @@
292 @ </table>
293 style_footer();
294 }
295
296 /*
297 ** COMMAND: dbstat*
298 **
299 ** Usage: %fossil dbstat OPTIONS
300 **
301 ** Shows statistics and global information about the repository.
 
302 **
303 ** Options:
304 **
305 ** --brief|-b Only show essential elements
306 ** --db-check Run a PRAGMA quick_check on the repository database
307 ** --omit-version-info Omit the SQLite and Fossil version information
 
 
 
308 */
309 void dbstat_cmd(void){
310 i64 t, fsize;
311 int n, m;
312 int szMax, szAvg;
@@ -317,10 +321,11 @@
317 const char *p, *z;
318
319 brief = find_option("brief", "b",0)!=0;
320 omitVers = find_option("omit-version-info", 0, 0)!=0;
321 dbCheck = find_option("db-check",0,0)!=0;
 
322 db_find_and_open_repository(0,0);
323
324 /* We should be done with options.. */
325 verify_all_options();
326
@@ -384,13 +389,15 @@
384 }
385 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
386 " + 0.99");
387 fossil_print("%*s%,d days or approximately %.2f years.\n",
388 colWidth, "project-age:", n, n/365.2425);
389 p = db_get("project-code", 0);
390 if( p ){
391 fossil_print("%*s%s\n", colWidth, "project-id:", p);
 
 
392 }
393 #if 0
394 /* Server-id is not useful information any more */
395 fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0));
396 #endif
@@ -412,12 +419,23 @@
412 db_int(0, "PRAGMA repository.page_size"),
413 db_int(0, "PRAGMA repository.freelist_count"),
414 db_text(0, "PRAGMA repository.encoding"),
415 db_text(0, "PRAGMA repository.journal_mode"));
416 if( dbCheck ){
417 fossil_print("%*s%s\n", colWidth, "database-check:",
418 db_text(0, "PRAGMA quick_check(1)"));
 
 
 
 
 
 
 
 
 
 
 
419 }
420 }
421
422 /*
423 ** WEBPAGE: urllist
424
--- src/stat.c
+++ src/stat.c
@@ -292,21 +292,25 @@
292 @ </table>
293 style_footer();
294 }
295
296 /*
297 ** COMMAND: dbstat
298 **
299 ** Usage: %fossil dbstat OPTIONS
300 **
301 ** Shows statistics and global information about the repository and/or
302 ** verify the integrity of a repository.
303 **
304 ** Options:
305 **
306 ** --brief|-b Only show essential elements.
307 ** --db-check Run "PRAGMA quick_check" on the repository database.
308 ** --db-verify Run a full verification of the repository integrity.
309 ** This involves decoding and reparsing all artifacts
310 ** and can take significant time.
311 ** --omit-version-info Omit the SQLite and Fossil version information.
312 */
313 void dbstat_cmd(void){
314 i64 t, fsize;
315 int n, m;
316 int szMax, szAvg;
@@ -317,10 +321,11 @@
321 const char *p, *z;
322
323 brief = find_option("brief", "b",0)!=0;
324 omitVers = find_option("omit-version-info", 0, 0)!=0;
325 dbCheck = find_option("db-check",0,0)!=0;
326 if( find_option("db-verify",0,0)!=0 ) dbCheck = 2;
327 db_find_and_open_repository(0,0);
328
329 /* We should be done with options.. */
330 verify_all_options();
331
@@ -384,13 +389,15 @@
389 }
390 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
391 " + 0.99");
392 fossil_print("%*s%,d days or approximately %.2f years.\n",
393 colWidth, "project-age:", n, n/365.2425);
394 if( !brief ){
395 p = db_get("project-code", 0);
396 if( p ){
397 fossil_print("%*s%s\n", colWidth, "project-id:", p);
398 }
399 }
400 #if 0
401 /* Server-id is not useful information any more */
402 fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0));
403 #endif
@@ -412,12 +419,23 @@
419 db_int(0, "PRAGMA repository.page_size"),
420 db_int(0, "PRAGMA repository.freelist_count"),
421 db_text(0, "PRAGMA repository.encoding"),
422 db_text(0, "PRAGMA repository.journal_mode"));
423 if( dbCheck ){
424 if( dbCheck<2 ){
425 char *zRes = db_text(0, "PRAGMA repository.quick_check(1)");
426 fossil_print("%*s%s\n", colWidth, "database-check:", zRes);
427 }else{
428 char *newArgv[3];
429 newArgv[0] = g.argv[0];
430 newArgv[1] = "test-integrity";
431 newArgv[2] = 0;
432 g.argv = newArgv;
433 g.argc = 2;
434 fossil_print("Full repository verification follows:\n");
435 test_integrity();
436 }
437 }
438 }
439
440 /*
441 ** WEBPAGE: urllist
442
+69 -231
--- src/style.c
+++ src/style.c
@@ -88,14 +88,10 @@
8888
8989
/*
9090
** Flags for various javascript files needed prior to </body>
9191
*/
9292
static int needHrefJs = 0; /* href.js */
93
-static int needSortJs = 0; /* sorttable.js */
94
-static int needGraphJs = 0; /* graph.js */
95
-static int needCopyBtnJs = 0; /* copybtn.js */
96
-static int needAccordionJs = 0; /* accordion.js */
9793
9894
/*
9995
** Extra JS added to the end of the file.
10096
*/
10197
static Blob blobOnLoad = BLOB_INITIALIZER;
@@ -484,11 +480,11 @@
484480
zBtnFmt/*works-like:"%h%s%h%h%d"*/,
485481
zTargetId,zText,zTargetId,zTargetId,cchLength);
486482
}
487483
}
488484
free(zText);
489
- style_copybutton_control();
485
+ builtin_request_js("copybtn.js");
490486
return zResult;
491487
}
492488
493489
/*
494490
** Return a random nonce that is stored in static space. For a particular
@@ -694,66 +690,17 @@
694690
695691
/*
696692
** Indicate that the table-sorting javascript is needed.
697693
*/
698694
void style_table_sorter(void){
699
- needSortJs = 1;
700
-}
701
-
702
-/*
703
-** Indicate that the accordion javascript is needed.
704
-*/
705
-void style_accordion(void){
706
- needAccordionJs = 1;
707
-}
708
-
709
-/*
710
-** Indicate that the timeline graph javascript is needed.
711
-*/
712
-void style_graph_generator(void){
713
- needGraphJs = 1;
714
-}
715
-
716
-/*
717
-** Indicate that the copy button javascript is needed.
718
-*/
719
-void style_copybutton_control(void){
720
- needCopyBtnJs = 1;
721
-}
722
-
723
-/*
724
-** Generate code to load a single javascript file
725
-*/
726
-void style_load_one_js_file(const char *zFile){
727
- @ <script src='%R/builtin/%s(zFile)?id=%S(fossil_exe_id())'></script>
728
-}
729
-
730
-/*
731
-** All extra JS files to load.
732
-*/
733
-static const char *azJsToLoad[4];
734
-static int nJsToLoad = 0;
735
-
736
-/*
737
-** Register a new JS file to load at the end of the document.
738
-*/
739
-void style_load_js(const char *zName){
740
- int i;
741
- for(i=0; i<nJsToLoad; i++){
742
- if( fossil_strcmp(zName, azJsToLoad[i])==0 ) return;
743
- }
744
- if( nJsToLoad>=sizeof(azJsToLoad)/sizeof(azJsToLoad[0]) ){
745
- fossil_panic("too many JS files");
746
- }
747
- azJsToLoad[nJsToLoad++] = zName;
695
+ builtin_request_js("sorttable.js");
748696
}
749697
750698
/*
751699
** Generate code to load all required javascript files.
752700
*/
753701
static void style_load_all_js_files(void){
754
- int i;
755702
if( needHrefJs ){
756703
int nDelay = db_get_int("auto-hyperlink-delay",0);
757704
int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0);
758705
@ <script id='href-data' type='application/json'>\
759706
@ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script>
@@ -762,43 +709,20 @@
762709
@ function debugMsg(msg){
763710
@ var n = document.getElementById("debugMsg");
764711
@ if(n){n.textContent=msg;}
765712
@ }
766713
if( needHrefJs ){
714
+ @ /* href.js */
767715
cgi_append_content(builtin_text("href.js"),-1);
768716
}
769
- if( needSortJs ){
770
- cgi_append_content(builtin_text("sorttable.js"),-1);
771
- }
772
- if( needGraphJs ){
773
- cgi_append_content(builtin_text("graph.js"),-1);
774
- }
775
- if( needCopyBtnJs ){
776
- cgi_append_content(builtin_text("copybtn.js"),-1);
777
- }
778
- if( needAccordionJs ){
779
- cgi_append_content(builtin_text("accordion.js"),-1);
780
- }
781
- for(i=0; i<nJsToLoad; i++){
782
- cgi_append_content(builtin_text(azJsToLoad[i]),-1);
783
- }
784717
if( blob_size(&blobOnLoad)>0 ){
785718
@ window.onload = function(){
786719
cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad));
787720
cgi_append_content("\n}\n", -1);
788721
}
789722
@ </script>
790
-}
791
-
792
-/*
793
-** Extra JS to run after all content is loaded.
794
-*/
795
-void style_js_onload(const char *zFormat, ...){
796
- va_list ap;
797
- va_start(ap, zFormat);
798
- blob_vappendf(&blobOnLoad, zFormat, ap);
799
- va_end(ap);
723
+ builtin_fulfill_js_requests();
800724
}
801725
802726
/*
803727
** Draw the footer at the bottom of the page.
804728
*/
@@ -916,11 +840,11 @@
916840
@ </div>
917841
if( nSubmenuCtrl ){
918842
cgi_query_parameters_to_hidden();
919843
cgi_tag_query_parameter(0);
920844
@ </form>
921
- style_load_one_js_file("menu.js");
845
+ builtin_request_js("menu.js");
922846
}
923847
}
924848
925849
zAd = style_adunit_text(&mAdFlags);
926850
if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
@@ -1102,10 +1026,11 @@
11021026
Blob css = empty_blob;
11031027
int i;
11041028
const char * zDefaults;
11051029
11061030
cgi_set_content_type("text/css");
1031
+ etag_check(0, 0);
11071032
/* Emit all default rules... */
11081033
zDefaults = (const char*)builtin_file("default.css", &i);
11091034
blob_append(&css, zDefaults, i);
11101035
/* Page-specific CSS, if any... */
11111036
page_style_css_append_page_style(&css);
@@ -1127,46 +1052,10 @@
11271052
11281053
/* Tell CGI that the content returned by this page is considered cacheable */
11291054
g.isConst = 1;
11301055
}
11311056
1132
-/*
1133
-** WEBPAGE: builtin
1134
-** URL: builtin/FILENAME
1135
-**
1136
-** Return the built-in text given by FILENAME. This is used internally
1137
-** by many Fossil web pages to load built-in javascript files.
1138
-**
1139
-** If the id= query parameter is present, then Fossil assumes that the
1140
-** result is immutable and sets a very large cache retention time (1 year).
1141
-*/
1142
-void page_builtin_text(void){
1143
- Blob out;
1144
- const char *zName = P("name");
1145
- const char *zTxt = 0;
1146
- const char *zId = P("id");
1147
- int nId;
1148
- if( zName ) zTxt = builtin_text(zName);
1149
- if( zTxt==0 ){
1150
- cgi_set_status(404, "Not Found");
1151
- @ File "%h(zName)" not found
1152
- return;
1153
- }
1154
- if( sqlite3_strglob("*.js", zName)==0 ){
1155
- cgi_set_content_type("application/javascript");
1156
- }else{
1157
- cgi_set_content_type("text/plain");
1158
- }
1159
- if( zId && (nId = (int)strlen(zId))>=8 && strncmp(zId,MANIFEST_UUID,nId)==0 ){
1160
- g.isConst = 1;
1161
- }else{
1162
- etag_check(0,0);
1163
- }
1164
- blob_init(&out, zTxt, -1);
1165
- cgi_set_content(&out);
1166
-}
1167
-
11681057
/*
11691058
** All possible capabilities
11701059
*/
11711060
static const char allCap[] =
11721061
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKL";
@@ -1535,35 +1424,51 @@
15351424
** bootstrap the window.fossil object, using the built-in file
15361425
** fossil.bootstrap.js (not to be confused with bootstrap.js).
15371426
**
15381427
** Subsequent calls are no-ops.
15391428
**
1540
-** If passed a true value, it emits the contents directly to the page
1541
-** output, else it emits a script tag with a src=builtin/... to load
1542
-** the script. It always outputs a small pre-bootstrap element in its
1543
-** own script tag to initialize parts which need C-runtime-level
1544
-** information, before loading the main fossil.bootstrap.js either
1545
-** inline or via a <script src=...>, as specified by the first
1546
-** argument.
1429
+** It emits 2 parts:
1430
+**
1431
+** 1) window.fossil core object, some of which depends on C-level
1432
+** runtime data. That part of the script is always emitted inline. If
1433
+** addScriptTag is true then it is wrapped in its own SCRIPT tag, else
1434
+** it is assumed that the caller already opened a tag.
1435
+**
1436
+** 2) Emits the static fossil.bootstrap.js using builtin_request_js().
15471437
*/
1548
-void style_emit_script_fossil_bootstrap(int asInline){
1438
+void style_emit_script_fossil_bootstrap(int addScriptTag){
15491439
static int once = 0;
15501440
if(0==once++){
15511441
/* Set up the generic/app-agnostic parts of window.fossil
15521442
** which require C-level state... */
1553
- style_emit_script_tag(0,0);
1554
- CX("(function(){\n"
1555
- "if(!window.fossil) window.fossil={};\n"
1443
+ if(addScriptTag!=0){
1444
+ style_emit_script_tag(0,0);
1445
+ }
1446
+ CX("(function(){\n");
1447
+ CX(/*MSIE NodeList.forEach polyfill, courtesy of Mozilla:
1448
+ https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#Polyfill
1449
+ */
1450
+ "if(window.NodeList && !NodeList.prototype.forEach){"
1451
+ "NodeList.prototype.forEach = Array.prototype.forEach;"
1452
+ "}\n");
1453
+ CX("if(!window.fossil) window.fossil={};\n"
15561454
"window.fossil.version = %!j;\n"
15571455
/* fossil.rootPath is the top-most CGI/server path,
15581456
** including a trailing slash. */
15591457
"window.fossil.rootPath = %!j+'/';\n",
15601458
get_version(), g.zTop);
15611459
/* fossil.config = {...various config-level options...} */
1562
- CX("window.fossil.config = {"
1563
- "hashDigits: %d, hashDigitsUrl: %d"
1564
- "};\n", hash_digits(0), hash_digits(1));
1460
+ CX("window.fossil.config = {");
1461
+ CX("/* Length of UUID hashes for display purposes. */");
1462
+ CX("hashDigits: %d, hashDigitsUrl: %d,\n",
1463
+ hash_digits(0), hash_digits(1));
1464
+ CX("editStateMarkers: {"
1465
+ "/*Symbolic markers to denote certain edit states.*/"
1466
+ "isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
1467
+ CX("confirmerButtonTicks: 3 "
1468
+ "/*default fossil.confirmer tick count.*/\n");
1469
+ CX("};\n"/* fossil.config */);
15651470
#if 0
15661471
/* Is it safe to emit the CSRF token here? Some pages add it
15671472
** as a hidden form field. */
15681473
if(g.zCsrfToken[0]!=0){
15691474
CX("window.fossil.csrfToken = %!j;\n",
@@ -1577,19 +1482,16 @@
15771482
*/
15781483
CX("window.fossil.page = {"
15791484
"name:\"%T\""
15801485
"};\n", g.zPath);
15811486
CX("})();\n");
1582
- /* The remaining fossil object bootstrap code is not dependent on
1583
- ** C-runtime state... */
1584
- if(asInline){
1585
- CX("%s\n", builtin_text("fossil.bootstrap.js"));
1586
- }
1587
- style_emit_script_tag(1,0);
1588
- if(asInline==0){
1589
- style_emit_script_builtin(0, "fossil.bootstrap.js");
1590
- }
1487
+ if(addScriptTag!=0){
1488
+ style_emit_script_tag(1,0);
1489
+ }
1490
+ /* The remaining window.fossil bootstrap code is not dependent on
1491
+ ** C-runtime state... */
1492
+ builtin_request_js("fossil.bootstrap.js");
15911493
}
15921494
}
15931495
15941496
/*
15951497
** If passed 0 as its first argument, it emits a script opener tag
@@ -1620,97 +1522,33 @@
16201522
CX("</script>\n");
16211523
}
16221524
}
16231525
16241526
/*
1625
-** Emits a script tag which uses content from a builtin script file.
1626
-**
1627
-** If asInline is true, it is emitted directly as an opening tag, the
1628
-** content of the zName builtin file, and a closing tag.
1629
-**
1630
-** If it is false, a script tag loading it via
1631
-** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
1632
-** build-time-dependent cache-buster value.
1633
-*/
1634
-void style_emit_script_builtin(int asInline, char const * zName){
1635
- if(asInline){
1636
- style_emit_script_tag(0,0);
1637
- CX("%s", builtin_text(zName));
1638
- style_emit_script_tag(1,0);
1639
- }else{
1640
- char * zFullName = mprintf("builtin/%s",zName);
1641
- const char * zHash = fossil_exe_id();
1642
- CX("<script src='%R/%T?cache=%.8s'></script>\n",
1643
- zFullName, zHash);
1644
- fossil_free(zFullName);
1645
- }
1646
-}
1647
-
1648
-/*
1649
-** The first time this is called it emits the JS code from the
1650
-** built-in file fossil.fossil.js. Subsequent calls are no-ops.
1651
-**
1652
-** If passed a true value, it emits the contents directly
1653
-** to the page output, else it emits a script tag with a
1654
-** src=builtin/... to load the script.
1655
-**
1656
-** Note that this code relies on that loaded via
1657
-** style_emit_script_fossil_bootstrap() but it does not call that
1658
-** routine.
1659
-*/
1660
-void style_emit_script_fetch(int asInline){
1661
- static int once = 0;
1662
- if(0==once++){
1663
- style_emit_script_builtin(asInline, "fossil.fetch.js");
1664
- }
1665
-}
1666
-
1667
-/*
1668
-** The first time this is called it emits the JS code from the
1669
-** built-in file fossil.dom.js. Subsequent calls are no-ops.
1670
-**
1671
-** If passed a true value, it emits the contents directly
1672
-** to the page output, else it emits a script tag with a
1673
-** src=builtin/... to load the script.
1674
-**
1675
-** Note that this code relies on that loaded via
1676
-** style_emit_script_fossil_bootstrap(), but it does not call that
1677
-** routine.
1678
-*/
1679
-void style_emit_script_dom(int asInline){
1680
- static int once = 0;
1681
- if(0==once++){
1682
- style_emit_script_builtin(asInline, "fossil.dom.js");
1683
- }
1684
-}
1685
-
1686
-/*
1687
-** The first time this is called, it calls style_emit_script_dom(),
1688
-** passing it the given asInline value, and emits the JS code from the
1689
-** built-in file fossil.tabs.js. Subsequent calls are no-ops.
1690
-**
1691
-** If passed a true value, it emits the contents directly
1692
-** to the page output, else it emits a script tag with a
1693
-** src=builtin/... to load the script.
1694
-*/
1695
-void style_emit_script_tabs(int asInline){
1696
- static int once = 0;
1697
- if(0==once++){
1698
- style_emit_script_dom(asInline);
1699
- style_emit_script_builtin(asInline, "fossil.tabs.js");
1700
- }
1701
-}
1702
-
1703
-/*
1704
-** The first time this is called it emits the JS code from the
1705
-** built-in file fossil.confirmer.js. Subsequent calls are no-ops.
1706
-**
1707
-** If passed a true value, it emits the contents directly
1708
-** to the page output, else it emits a script tag with a
1709
-** src=builtin/... to load the script.
1710
-*/
1711
-void style_emit_script_confirmer(int asInline){
1712
- static int once = 0;
1713
- if(0==once++){
1714
- style_emit_script_builtin(asInline, "fossil.confirmer.js");
1715
- }
1527
+** Convenience wrapper which calls builtin_request_js() for a series
1528
+** of builtin scripts named fossil.NAME.js. The first time it is
1529
+** called, it also calls style_emit_script_fossil_bootstrap() to
1530
+** initialize the window.fossil JS API. The first argument is a
1531
+** no-meaning dummy required by the va_start() interface. All
1532
+** subsequent arguments must be strings of the NAME part of
1533
+** fossil.NAME.js, followed by a NULL argument to terminate the list.
1534
+**
1535
+** e.g. pass it (0, "fetch", "dom", "tabs", 0) to load those 3
1536
+** APIs. Do not forget the trailing 0!
1537
+*/
1538
+void style_emit_fossil_js_apis( int dummy, ... ) {
1539
+ static int once = 0;
1540
+ const char *zArg;
1541
+ char * zName;
1542
+ va_list vargs;
1543
+
1544
+ if(0==once++){
1545
+ style_emit_script_fossil_bootstrap(1);
1546
+ }
1547
+ va_start(vargs,dummy);
1548
+ while( (zArg = va_arg (vargs, const char *))!=0 ){
1549
+ zName = mprintf("fossil.%s.js", zArg);
1550
+ builtin_request_js(zName);
1551
+ fossil_free(zName);
1552
+ }
1553
+ va_end(vargs);
17161554
}
17171555
--- src/style.c
+++ src/style.c
@@ -88,14 +88,10 @@
88
89 /*
90 ** Flags for various javascript files needed prior to </body>
91 */
92 static int needHrefJs = 0; /* href.js */
93 static int needSortJs = 0; /* sorttable.js */
94 static int needGraphJs = 0; /* graph.js */
95 static int needCopyBtnJs = 0; /* copybtn.js */
96 static int needAccordionJs = 0; /* accordion.js */
97
98 /*
99 ** Extra JS added to the end of the file.
100 */
101 static Blob blobOnLoad = BLOB_INITIALIZER;
@@ -484,11 +480,11 @@
484 zBtnFmt/*works-like:"%h%s%h%h%d"*/,
485 zTargetId,zText,zTargetId,zTargetId,cchLength);
486 }
487 }
488 free(zText);
489 style_copybutton_control();
490 return zResult;
491 }
492
493 /*
494 ** Return a random nonce that is stored in static space. For a particular
@@ -694,66 +690,17 @@
694
695 /*
696 ** Indicate that the table-sorting javascript is needed.
697 */
698 void style_table_sorter(void){
699 needSortJs = 1;
700 }
701
702 /*
703 ** Indicate that the accordion javascript is needed.
704 */
705 void style_accordion(void){
706 needAccordionJs = 1;
707 }
708
709 /*
710 ** Indicate that the timeline graph javascript is needed.
711 */
712 void style_graph_generator(void){
713 needGraphJs = 1;
714 }
715
716 /*
717 ** Indicate that the copy button javascript is needed.
718 */
719 void style_copybutton_control(void){
720 needCopyBtnJs = 1;
721 }
722
723 /*
724 ** Generate code to load a single javascript file
725 */
726 void style_load_one_js_file(const char *zFile){
727 @ <script src='%R/builtin/%s(zFile)?id=%S(fossil_exe_id())'></script>
728 }
729
730 /*
731 ** All extra JS files to load.
732 */
733 static const char *azJsToLoad[4];
734 static int nJsToLoad = 0;
735
736 /*
737 ** Register a new JS file to load at the end of the document.
738 */
739 void style_load_js(const char *zName){
740 int i;
741 for(i=0; i<nJsToLoad; i++){
742 if( fossil_strcmp(zName, azJsToLoad[i])==0 ) return;
743 }
744 if( nJsToLoad>=sizeof(azJsToLoad)/sizeof(azJsToLoad[0]) ){
745 fossil_panic("too many JS files");
746 }
747 azJsToLoad[nJsToLoad++] = zName;
748 }
749
750 /*
751 ** Generate code to load all required javascript files.
752 */
753 static void style_load_all_js_files(void){
754 int i;
755 if( needHrefJs ){
756 int nDelay = db_get_int("auto-hyperlink-delay",0);
757 int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0);
758 @ <script id='href-data' type='application/json'>\
759 @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script>
@@ -762,43 +709,20 @@
762 @ function debugMsg(msg){
763 @ var n = document.getElementById("debugMsg");
764 @ if(n){n.textContent=msg;}
765 @ }
766 if( needHrefJs ){
 
767 cgi_append_content(builtin_text("href.js"),-1);
768 }
769 if( needSortJs ){
770 cgi_append_content(builtin_text("sorttable.js"),-1);
771 }
772 if( needGraphJs ){
773 cgi_append_content(builtin_text("graph.js"),-1);
774 }
775 if( needCopyBtnJs ){
776 cgi_append_content(builtin_text("copybtn.js"),-1);
777 }
778 if( needAccordionJs ){
779 cgi_append_content(builtin_text("accordion.js"),-1);
780 }
781 for(i=0; i<nJsToLoad; i++){
782 cgi_append_content(builtin_text(azJsToLoad[i]),-1);
783 }
784 if( blob_size(&blobOnLoad)>0 ){
785 @ window.onload = function(){
786 cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad));
787 cgi_append_content("\n}\n", -1);
788 }
789 @ </script>
790 }
791
792 /*
793 ** Extra JS to run after all content is loaded.
794 */
795 void style_js_onload(const char *zFormat, ...){
796 va_list ap;
797 va_start(ap, zFormat);
798 blob_vappendf(&blobOnLoad, zFormat, ap);
799 va_end(ap);
800 }
801
802 /*
803 ** Draw the footer at the bottom of the page.
804 */
@@ -916,11 +840,11 @@
916 @ </div>
917 if( nSubmenuCtrl ){
918 cgi_query_parameters_to_hidden();
919 cgi_tag_query_parameter(0);
920 @ </form>
921 style_load_one_js_file("menu.js");
922 }
923 }
924
925 zAd = style_adunit_text(&mAdFlags);
926 if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
@@ -1102,10 +1026,11 @@
1102 Blob css = empty_blob;
1103 int i;
1104 const char * zDefaults;
1105
1106 cgi_set_content_type("text/css");
 
1107 /* Emit all default rules... */
1108 zDefaults = (const char*)builtin_file("default.css", &i);
1109 blob_append(&css, zDefaults, i);
1110 /* Page-specific CSS, if any... */
1111 page_style_css_append_page_style(&css);
@@ -1127,46 +1052,10 @@
1127
1128 /* Tell CGI that the content returned by this page is considered cacheable */
1129 g.isConst = 1;
1130 }
1131
1132 /*
1133 ** WEBPAGE: builtin
1134 ** URL: builtin/FILENAME
1135 **
1136 ** Return the built-in text given by FILENAME. This is used internally
1137 ** by many Fossil web pages to load built-in javascript files.
1138 **
1139 ** If the id= query parameter is present, then Fossil assumes that the
1140 ** result is immutable and sets a very large cache retention time (1 year).
1141 */
1142 void page_builtin_text(void){
1143 Blob out;
1144 const char *zName = P("name");
1145 const char *zTxt = 0;
1146 const char *zId = P("id");
1147 int nId;
1148 if( zName ) zTxt = builtin_text(zName);
1149 if( zTxt==0 ){
1150 cgi_set_status(404, "Not Found");
1151 @ File "%h(zName)" not found
1152 return;
1153 }
1154 if( sqlite3_strglob("*.js", zName)==0 ){
1155 cgi_set_content_type("application/javascript");
1156 }else{
1157 cgi_set_content_type("text/plain");
1158 }
1159 if( zId && (nId = (int)strlen(zId))>=8 && strncmp(zId,MANIFEST_UUID,nId)==0 ){
1160 g.isConst = 1;
1161 }else{
1162 etag_check(0,0);
1163 }
1164 blob_init(&out, zTxt, -1);
1165 cgi_set_content(&out);
1166 }
1167
1168 /*
1169 ** All possible capabilities
1170 */
1171 static const char allCap[] =
1172 "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKL";
@@ -1535,35 +1424,51 @@
1535 ** bootstrap the window.fossil object, using the built-in file
1536 ** fossil.bootstrap.js (not to be confused with bootstrap.js).
1537 **
1538 ** Subsequent calls are no-ops.
1539 **
1540 ** If passed a true value, it emits the contents directly to the page
1541 ** output, else it emits a script tag with a src=builtin/... to load
1542 ** the script. It always outputs a small pre-bootstrap element in its
1543 ** own script tag to initialize parts which need C-runtime-level
1544 ** information, before loading the main fossil.bootstrap.js either
1545 ** inline or via a <script src=...>, as specified by the first
1546 ** argument.
 
1547 */
1548 void style_emit_script_fossil_bootstrap(int asInline){
1549 static int once = 0;
1550 if(0==once++){
1551 /* Set up the generic/app-agnostic parts of window.fossil
1552 ** which require C-level state... */
1553 style_emit_script_tag(0,0);
1554 CX("(function(){\n"
1555 "if(!window.fossil) window.fossil={};\n"
 
 
 
 
 
 
 
 
1556 "window.fossil.version = %!j;\n"
1557 /* fossil.rootPath is the top-most CGI/server path,
1558 ** including a trailing slash. */
1559 "window.fossil.rootPath = %!j+'/';\n",
1560 get_version(), g.zTop);
1561 /* fossil.config = {...various config-level options...} */
1562 CX("window.fossil.config = {"
1563 "hashDigits: %d, hashDigitsUrl: %d"
1564 "};\n", hash_digits(0), hash_digits(1));
 
 
 
 
 
 
 
1565 #if 0
1566 /* Is it safe to emit the CSRF token here? Some pages add it
1567 ** as a hidden form field. */
1568 if(g.zCsrfToken[0]!=0){
1569 CX("window.fossil.csrfToken = %!j;\n",
@@ -1577,19 +1482,16 @@
1577 */
1578 CX("window.fossil.page = {"
1579 "name:\"%T\""
1580 "};\n", g.zPath);
1581 CX("})();\n");
1582 /* The remaining fossil object bootstrap code is not dependent on
1583 ** C-runtime state... */
1584 if(asInline){
1585 CX("%s\n", builtin_text("fossil.bootstrap.js"));
1586 }
1587 style_emit_script_tag(1,0);
1588 if(asInline==0){
1589 style_emit_script_builtin(0, "fossil.bootstrap.js");
1590 }
1591 }
1592 }
1593
1594 /*
1595 ** If passed 0 as its first argument, it emits a script opener tag
@@ -1620,97 +1522,33 @@
1620 CX("</script>\n");
1621 }
1622 }
1623
1624 /*
1625 ** Emits a script tag which uses content from a builtin script file.
1626 **
1627 ** If asInline is true, it is emitted directly as an opening tag, the
1628 ** content of the zName builtin file, and a closing tag.
1629 **
1630 ** If it is false, a script tag loading it via
1631 ** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
1632 ** build-time-dependent cache-buster value.
1633 */
1634 void style_emit_script_builtin(int asInline, char const * zName){
1635 if(asInline){
1636 style_emit_script_tag(0,0);
1637 CX("%s", builtin_text(zName));
1638 style_emit_script_tag(1,0);
1639 }else{
1640 char * zFullName = mprintf("builtin/%s",zName);
1641 const char * zHash = fossil_exe_id();
1642 CX("<script src='%R/%T?cache=%.8s'></script>\n",
1643 zFullName, zHash);
1644 fossil_free(zFullName);
1645 }
1646 }
1647
1648 /*
1649 ** The first time this is called it emits the JS code from the
1650 ** built-in file fossil.fossil.js. Subsequent calls are no-ops.
1651 **
1652 ** If passed a true value, it emits the contents directly
1653 ** to the page output, else it emits a script tag with a
1654 ** src=builtin/... to load the script.
1655 **
1656 ** Note that this code relies on that loaded via
1657 ** style_emit_script_fossil_bootstrap() but it does not call that
1658 ** routine.
1659 */
1660 void style_emit_script_fetch(int asInline){
1661 static int once = 0;
1662 if(0==once++){
1663 style_emit_script_builtin(asInline, "fossil.fetch.js");
1664 }
1665 }
1666
1667 /*
1668 ** The first time this is called it emits the JS code from the
1669 ** built-in file fossil.dom.js. Subsequent calls are no-ops.
1670 **
1671 ** If passed a true value, it emits the contents directly
1672 ** to the page output, else it emits a script tag with a
1673 ** src=builtin/... to load the script.
1674 **
1675 ** Note that this code relies on that loaded via
1676 ** style_emit_script_fossil_bootstrap(), but it does not call that
1677 ** routine.
1678 */
1679 void style_emit_script_dom(int asInline){
1680 static int once = 0;
1681 if(0==once++){
1682 style_emit_script_builtin(asInline, "fossil.dom.js");
1683 }
1684 }
1685
1686 /*
1687 ** The first time this is called, it calls style_emit_script_dom(),
1688 ** passing it the given asInline value, and emits the JS code from the
1689 ** built-in file fossil.tabs.js. Subsequent calls are no-ops.
1690 **
1691 ** If passed a true value, it emits the contents directly
1692 ** to the page output, else it emits a script tag with a
1693 ** src=builtin/... to load the script.
1694 */
1695 void style_emit_script_tabs(int asInline){
1696 static int once = 0;
1697 if(0==once++){
1698 style_emit_script_dom(asInline);
1699 style_emit_script_builtin(asInline, "fossil.tabs.js");
1700 }
1701 }
1702
1703 /*
1704 ** The first time this is called it emits the JS code from the
1705 ** built-in file fossil.confirmer.js. Subsequent calls are no-ops.
1706 **
1707 ** If passed a true value, it emits the contents directly
1708 ** to the page output, else it emits a script tag with a
1709 ** src=builtin/... to load the script.
1710 */
1711 void style_emit_script_confirmer(int asInline){
1712 static int once = 0;
1713 if(0==once++){
1714 style_emit_script_builtin(asInline, "fossil.confirmer.js");
1715 }
1716 }
1717
--- src/style.c
+++ src/style.c
@@ -88,14 +88,10 @@
88
89 /*
90 ** Flags for various javascript files needed prior to </body>
91 */
92 static int needHrefJs = 0; /* href.js */
 
 
 
 
93
94 /*
95 ** Extra JS added to the end of the file.
96 */
97 static Blob blobOnLoad = BLOB_INITIALIZER;
@@ -484,11 +480,11 @@
480 zBtnFmt/*works-like:"%h%s%h%h%d"*/,
481 zTargetId,zText,zTargetId,zTargetId,cchLength);
482 }
483 }
484 free(zText);
485 builtin_request_js("copybtn.js");
486 return zResult;
487 }
488
489 /*
490 ** Return a random nonce that is stored in static space. For a particular
@@ -694,66 +690,17 @@
690
691 /*
692 ** Indicate that the table-sorting javascript is needed.
693 */
694 void style_table_sorter(void){
695 builtin_request_js("sorttable.js");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
696 }
697
698 /*
699 ** Generate code to load all required javascript files.
700 */
701 static void style_load_all_js_files(void){
 
702 if( needHrefJs ){
703 int nDelay = db_get_int("auto-hyperlink-delay",0);
704 int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0);
705 @ <script id='href-data' type='application/json'>\
706 @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script>
@@ -762,43 +709,20 @@
709 @ function debugMsg(msg){
710 @ var n = document.getElementById("debugMsg");
711 @ if(n){n.textContent=msg;}
712 @ }
713 if( needHrefJs ){
714 @ /* href.js */
715 cgi_append_content(builtin_text("href.js"),-1);
716 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717 if( blob_size(&blobOnLoad)>0 ){
718 @ window.onload = function(){
719 cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad));
720 cgi_append_content("\n}\n", -1);
721 }
722 @ </script>
723 builtin_fulfill_js_requests();
 
 
 
 
 
 
 
 
 
724 }
725
726 /*
727 ** Draw the footer at the bottom of the page.
728 */
@@ -916,11 +840,11 @@
840 @ </div>
841 if( nSubmenuCtrl ){
842 cgi_query_parameters_to_hidden();
843 cgi_tag_query_parameter(0);
844 @ </form>
845 builtin_request_js("menu.js");
846 }
847 }
848
849 zAd = style_adunit_text(&mAdFlags);
850 if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
@@ -1102,10 +1026,11 @@
1026 Blob css = empty_blob;
1027 int i;
1028 const char * zDefaults;
1029
1030 cgi_set_content_type("text/css");
1031 etag_check(0, 0);
1032 /* Emit all default rules... */
1033 zDefaults = (const char*)builtin_file("default.css", &i);
1034 blob_append(&css, zDefaults, i);
1035 /* Page-specific CSS, if any... */
1036 page_style_css_append_page_style(&css);
@@ -1127,46 +1052,10 @@
1052
1053 /* Tell CGI that the content returned by this page is considered cacheable */
1054 g.isConst = 1;
1055 }
1056
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1057 /*
1058 ** All possible capabilities
1059 */
1060 static const char allCap[] =
1061 "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKL";
@@ -1535,35 +1424,51 @@
1424 ** bootstrap the window.fossil object, using the built-in file
1425 ** fossil.bootstrap.js (not to be confused with bootstrap.js).
1426 **
1427 ** Subsequent calls are no-ops.
1428 **
1429 ** It emits 2 parts:
1430 **
1431 ** 1) window.fossil core object, some of which depends on C-level
1432 ** runtime data. That part of the script is always emitted inline. If
1433 ** addScriptTag is true then it is wrapped in its own SCRIPT tag, else
1434 ** it is assumed that the caller already opened a tag.
1435 **
1436 ** 2) Emits the static fossil.bootstrap.js using builtin_request_js().
1437 */
1438 void style_emit_script_fossil_bootstrap(int addScriptTag){
1439 static int once = 0;
1440 if(0==once++){
1441 /* Set up the generic/app-agnostic parts of window.fossil
1442 ** which require C-level state... */
1443 if(addScriptTag!=0){
1444 style_emit_script_tag(0,0);
1445 }
1446 CX("(function(){\n");
1447 CX(/*MSIE NodeList.forEach polyfill, courtesy of Mozilla:
1448 https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#Polyfill
1449 */
1450 "if(window.NodeList && !NodeList.prototype.forEach){"
1451 "NodeList.prototype.forEach = Array.prototype.forEach;"
1452 "}\n");
1453 CX("if(!window.fossil) window.fossil={};\n"
1454 "window.fossil.version = %!j;\n"
1455 /* fossil.rootPath is the top-most CGI/server path,
1456 ** including a trailing slash. */
1457 "window.fossil.rootPath = %!j+'/';\n",
1458 get_version(), g.zTop);
1459 /* fossil.config = {...various config-level options...} */
1460 CX("window.fossil.config = {");
1461 CX("/* Length of UUID hashes for display purposes. */");
1462 CX("hashDigits: %d, hashDigitsUrl: %d,\n",
1463 hash_digits(0), hash_digits(1));
1464 CX("editStateMarkers: {"
1465 "/*Symbolic markers to denote certain edit states.*/"
1466 "isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
1467 CX("confirmerButtonTicks: 3 "
1468 "/*default fossil.confirmer tick count.*/\n");
1469 CX("};\n"/* fossil.config */);
1470 #if 0
1471 /* Is it safe to emit the CSRF token here? Some pages add it
1472 ** as a hidden form field. */
1473 if(g.zCsrfToken[0]!=0){
1474 CX("window.fossil.csrfToken = %!j;\n",
@@ -1577,19 +1482,16 @@
1482 */
1483 CX("window.fossil.page = {"
1484 "name:\"%T\""
1485 "};\n", g.zPath);
1486 CX("})();\n");
1487 if(addScriptTag!=0){
1488 style_emit_script_tag(1,0);
1489 }
1490 /* The remaining window.fossil bootstrap code is not dependent on
1491 ** C-runtime state... */
1492 builtin_request_js("fossil.bootstrap.js");
 
 
 
1493 }
1494 }
1495
1496 /*
1497 ** If passed 0 as its first argument, it emits a script opener tag
@@ -1620,97 +1522,33 @@
1522 CX("</script>\n");
1523 }
1524 }
1525
1526 /*
1527 ** Convenience wrapper which calls builtin_request_js() for a series
1528 ** of builtin scripts named fossil.NAME.js. The first time it is
1529 ** called, it also calls style_emit_script_fossil_bootstrap() to
1530 ** initialize the window.fossil JS API. The first argument is a
1531 ** no-meaning dummy required by the va_start() interface. All
1532 ** subsequent arguments must be strings of the NAME part of
1533 ** fossil.NAME.js, followed by a NULL argument to terminate the list.
1534 **
1535 ** e.g. pass it (0, "fetch", "dom", "tabs", 0) to load those 3
1536 ** APIs. Do not forget the trailing 0!
1537 */
1538 void style_emit_fossil_js_apis( int dummy, ... ) {
1539 static int once = 0;
1540 const char *zArg;
1541 char * zName;
1542 va_list vargs;
1543
1544 if(0==once++){
1545 style_emit_script_fossil_bootstrap(1);
1546 }
1547 va_start(vargs,dummy);
1548 while( (zArg = va_arg (vargs, const char *))!=0 ){
1549 zName = mprintf("fossil.%s.js", zArg);
1550 builtin_request_js(zName);
1551 fossil_free(zName);
1552 }
1553 va_end(vargs);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1554 }
1555
--- src/style.fileedit.css
+++ src/style.fileedit.css
@@ -15,15 +15,16 @@
1515
height: initial/*undo damage from some skins*/;
1616
max-width: initial /* default.css pins it at 95% */;
1717
}
1818
body.fileedit textarea:focus,
1919
body.fileedit input:focus{
20
- /* The sudden appearance of a border (as in the Ardoise skin)
21
- shifts the layout in unsightly ways */
22
- border: initial;
20
+ /* Depending on the skin, it might be useful to add one or both of
21
+ the following... */
22
+ /*border-width: 1px;*/
23
+ /*border: initial; */
2324
}
24
-body.fileedit fieldset {
25
+body.fileedit fieldset:not(.tab-wrapper) {
2526
margin: 0.5em 0 0.5em 0;
2627
padding: 0.25em 0;
2728
border-radius: 0.5em;
2829
border-color: inherit;
2930
border-width: 1px;
@@ -65,11 +66,11 @@
6566
body.fileedit div.fileedit-preview {
6667
margin: 0;
6768
padding: 0;
6869
}
6970
body.fileedit #fileedit-tabs {
70
- margin: 1em 0 0 0;
71
+ margin: 0.5em 0 0 0;
7172
}
7273
body.fileedit #fileedit-tab-preview-wrapper {
7374
overflow: auto;
7475
}
7576
body.fileedit #fileedit-tab-fileselect > h1 {
@@ -114,27 +115,28 @@
114115
}
115116
body.fileedit #fileedit-file-selector {
116117
display: flex;
117118
flex-direction: column;
118119
align-content: flex-start;
119
- border-color: inherit;
120
- border-width: 1px;
121
- border-style: inset;
122
- border-radius: 0.5em;
123120
padding: 0 0.25em;
124121
margin: 0;
125122
min-height: 12em;
126123
}
127124
body.fileedit #fileedit-file-selector select {
128125
margin: 0 0 0.5em 0;
129126
height: initial;
130127
font-family: monospace;
128
+ border: initial;
131129
}
132130
body.fileedit select:focus {
133
- border: none;
131
+ border: initial;
132
+}
133
+body.fileedit #fileedit-file-selector select option {
134
+ margin: 0 0 0.5em 0.55em;
134135
}
135
-body.fileedit option:focus {
136
+body.fileedit select option,
137
+body.fileedit select option:focus {
136138
border: none;
137139
}
138140
body.fileedit #fileedit-file-selector > div {
139141
padding: 0;
140142
margin: 0;
@@ -184,185 +186,40 @@
184186
}
185187
body.fileedit .sbsdiffcols div.difftxtcol pre {
186188
max-width: 44em;
187189
}
188190
189
-/**
190
- Styles for fossil.tabs.js. As of this writing, currently
191
- only used by /fileedit, but it is anticipated that these
192
- will eventually need to migrate to default_css.txt for use
193
- in the wiki and/or forum pages when implementing tabbed
194
- ajax-based previews.
195
-*/
196
-.tab-container {
197
- width: 100%;
198
- display: flex;
199
- flex-direction: column;
200
- align-items: stretch;
201
-}
202
-.tab-container > #fossil-status-bar {
203
- margin-top: 0;
204
-}
205
-.tab-container > .tabs {
206
- padding: 0.25em;
207
- margin: 0;
208
- display: flex;
209
- flex-direction: column;
210
- border-width: 1px;
211
- border-style: outset;
212
- border-color: inherit;
213
-}
214
-.tab-container > .tabs > .tab-panel {
215
- align-self: stretch;
216
- flex: 10 1 auto;
217
- display: block;
218
-}
219
-.tab-container > .tab-bar {
220
- display: flex;
221
- flex-direction: row;
222
- flex: 1 10 auto;
223
- align-self: stretch;
224
- flex-wrap: wrap;
225
-}
226
-.tab-container > .tab-bar > .tab-button {
227
- display: inline-block;
228
- border-radius: 0.5em 0.5em 0 0;
229
- margin: 0 0.1em;
230
- padding: 0.25em 0.75em;
231
- align-self: baseline;
232
- border-color: inherit;
233
- border-width: 1px;
234
- border-bottom: none;
235
- border-top-style: inset;
236
- border-left-style: inset;
237
- border-right-style: inset;
238
- cursor: pointer;
239
- opacity: 0.6;
240
-}
241
-.tab-container > .tab-bar > .tab-button.selected {
242
- text-decoration: underline;
243
- opacity: 1.0;
244
- border-top-style: outset;
245
- border-left-style: outset;
246
- border-right-style: outset;
247
-}
248
-
249
-/**
250
- Styles developed for /fileedit but which have wider
251
- applicability...
252
-
253
- As of this writing, these are only used by /fileedit, but it is
254
- anticipated that they will eventually need to be migrated over to
255
- default_css.txt for use in other pages (specifically wiki and forum
256
- page/post editors).
257
-*/
258
-.flex-container {
259
- display: flex;
260
-}
261
-.flex-container.flex-row {
262
- flex-direction: row;
263
- flex-wrap: wrap;
264
- justify-content: center;
265
- align-items: center;
266
-}
267
-.flex-container .flex-grow {
268
- flex-grow: 10;
269
- flex-shrink: 0;
270
-}
271
-.flex-container .flex-shrink {
272
- flex-grow: 0;
273
- flex-shrink: 10;
274
-}
275
-.flex-container.flex-row.stretch {
276
- flex-wrap: wrap;
277
- align-items: baseline;
278
- justify-content: stretch;
279
- margin: 0;
280
-}
281
-.flex-container.flex-column {
282
- flex-direction: column;
283
- flex-wrap: wrap;
284
- justify-content: center;
285
- align-items: center;
286
-}
287
-.flex-container.flex-column.stretch {
288
- align-items: stretch;
289
- margin: 0;
290
-}
291
-.flex-container.child-gap-small > * {
292
- margin: 0.25em;
293
-}
294
-#fossil-status-bar {
295
- display: block;
296
- font-family: monospace;
297
- border-width: 1px;
298
- border-style: inset;
299
- border-color: inherit;
300
- min-height: 1.5em;
301
- font-size: 1.2em;
302
- padding: 0.2em;
303
- margin: 0.25em 0;
304
- flex: 0 0 auto;
305
-}
306
-.font-size-100 {
307
- font-size: 100%;
308
-}
309
-.font-size-125 {
310
- font-size: 125%;
311
-}
312
-.font-size-150 {
313
- font-size: 150%;
314
-}
315
-.font-size-175 {
316
- font-size: 175%;
317
-}
318
-.font-size-200 {
319
- font-size: 200%;
320
-}
321
-
322
-/**
323
- .input-with-label is intended to be a wrapper element which
324
- contain both a LABEL tag and an INPUT or SELECT control.
325
- The wrapper is "necessary", as opposed to placing the INPUT
326
- in the LABEL, so that we can include multiple INPUT
327
- elements (e.g. a set of radio buttons).
328
-*/
329
-.input-with-label {
330
- border: 1px inset #808080;
331
- border-radius: 0.5em;
332
- padding: 0.25em 0.4em;
333
- margin: 0 0.5em;
334
- display: inline-block;
335
- cursor: default;
336
-}
337
-.input-with-label > * {
338
- vertical-align: middle;
339
-}
340
-.input-with-label > label {
341
- display: inline; /* some skins set label display to block! */
342
-}
343
-.input-with-label > input {
344
- margin: 0;
345
-}
346
-.input-with-label > button {
347
- margin: 0;
348
-}
349
-.input-with-label > select {
350
- margin: 0;
351
-}
352
-.input-with-label > input[type=text] {
353
- margin: 0;
354
-}
355
-.input-with-label > textarea {
356
- margin: 0;
357
-}
358
-.input-with-label > input[type=checkbox] {
359
- vertical-align: sub;
360
-}
361
-.input-with-label > input[type=radio] {
362
- vertical-align: sub;
363
-}
364
-.input-with-label > label {
365
- font-weight: initial;
366
- margin: 0 0.25em 0 0.25em;
367
- vertical-align: middle;
191
+body.fileedit #fileedit-edit-status {
192
+ border-radius: 0.25em 0.25em 0 0;
193
+ margin: 0;
194
+ padding: 0;
195
+ width: 100%;
196
+ cursor: initial;
197
+ display: flex;
198
+ flex-direction: row;
199
+ flex-wrap: wrap;
200
+ justify-content: space-between;
201
+ font-family: monospace;
202
+}
203
+body.fileedit #fileedit-edit-status > span.name > a {
204
+ display: block;
205
+ word-break: break-word /* needed for long paths */;
206
+}
207
+body.fileedit #fileedit-edit-status > span.links {
208
+ display: flex;
209
+ flex-wrap: wrap;
210
+ flex-direction: row;
211
+}
212
+body.fileedit #fileedit-file-selector span.is-new,
213
+body.fileedit #fileedit-file-selector span.is-modified {
214
+ font-family: monospace;
215
+}
216
+body.fileedit #fileedit-edit-status span.links > * {
217
+ margin: 0 0.25em;
218
+ white-space: nowrap;
219
+}
220
+body.fileedit #fileedit-edit-status span.links > *::before {
221
+ content: "[";
222
+}
223
+body.fileedit #fileedit-edit-status span.links > *::after {
224
+ content: "]";
368225
}
369226
370227
ADDED src/style.wikiedit.css
--- src/style.fileedit.css
+++ src/style.fileedit.css
@@ -15,15 +15,16 @@
15 height: initial/*undo damage from some skins*/;
16 max-width: initial /* default.css pins it at 95% */;
17 }
18 body.fileedit textarea:focus,
19 body.fileedit input:focus{
20 /* The sudden appearance of a border (as in the Ardoise skin)
21 shifts the layout in unsightly ways */
22 border: initial;
 
23 }
24 body.fileedit fieldset {
25 margin: 0.5em 0 0.5em 0;
26 padding: 0.25em 0;
27 border-radius: 0.5em;
28 border-color: inherit;
29 border-width: 1px;
@@ -65,11 +66,11 @@
65 body.fileedit div.fileedit-preview {
66 margin: 0;
67 padding: 0;
68 }
69 body.fileedit #fileedit-tabs {
70 margin: 1em 0 0 0;
71 }
72 body.fileedit #fileedit-tab-preview-wrapper {
73 overflow: auto;
74 }
75 body.fileedit #fileedit-tab-fileselect > h1 {
@@ -114,27 +115,28 @@
114 }
115 body.fileedit #fileedit-file-selector {
116 display: flex;
117 flex-direction: column;
118 align-content: flex-start;
119 border-color: inherit;
120 border-width: 1px;
121 border-style: inset;
122 border-radius: 0.5em;
123 padding: 0 0.25em;
124 margin: 0;
125 min-height: 12em;
126 }
127 body.fileedit #fileedit-file-selector select {
128 margin: 0 0 0.5em 0;
129 height: initial;
130 font-family: monospace;
 
131 }
132 body.fileedit select:focus {
133 border: none;
 
 
 
134 }
135 body.fileedit option:focus {
 
136 border: none;
137 }
138 body.fileedit #fileedit-file-selector > div {
139 padding: 0;
140 margin: 0;
@@ -184,185 +186,40 @@
184 }
185 body.fileedit .sbsdiffcols div.difftxtcol pre {
186 max-width: 44em;
187 }
188
189 /**
190 Styles for fossil.tabs.js. As of this writing, currently
191 only used by /fileedit, but it is anticipated that these
192 will eventually need to migrate to default_css.txt for use
193 in the wiki and/or forum pages when implementing tabbed
194 ajax-based previews.
195 */
196 .tab-container {
197 width: 100%;
198 display: flex;
199 flex-direction: column;
200 align-items: stretch;
201 }
202 .tab-container > #fossil-status-bar {
203 margin-top: 0;
204 }
205 .tab-container > .tabs {
206 padding: 0.25em;
207 margin: 0;
208 display: flex;
209 flex-direction: column;
210 border-width: 1px;
211 border-style: outset;
212 border-color: inherit;
213 }
214 .tab-container > .tabs > .tab-panel {
215 align-self: stretch;
216 flex: 10 1 auto;
217 display: block;
218 }
219 .tab-container > .tab-bar {
220 display: flex;
221 flex-direction: row;
222 flex: 1 10 auto;
223 align-self: stretch;
224 flex-wrap: wrap;
225 }
226 .tab-container > .tab-bar > .tab-button {
227 display: inline-block;
228 border-radius: 0.5em 0.5em 0 0;
229 margin: 0 0.1em;
230 padding: 0.25em 0.75em;
231 align-self: baseline;
232 border-color: inherit;
233 border-width: 1px;
234 border-bottom: none;
235 border-top-style: inset;
236 border-left-style: inset;
237 border-right-style: inset;
238 cursor: pointer;
239 opacity: 0.6;
240 }
241 .tab-container > .tab-bar > .tab-button.selected {
242 text-decoration: underline;
243 opacity: 1.0;
244 border-top-style: outset;
245 border-left-style: outset;
246 border-right-style: outset;
247 }
248
249 /**
250 Styles developed for /fileedit but which have wider
251 applicability...
252
253 As of this writing, these are only used by /fileedit, but it is
254 anticipated that they will eventually need to be migrated over to
255 default_css.txt for use in other pages (specifically wiki and forum
256 page/post editors).
257 */
258 .flex-container {
259 display: flex;
260 }
261 .flex-container.flex-row {
262 flex-direction: row;
263 flex-wrap: wrap;
264 justify-content: center;
265 align-items: center;
266 }
267 .flex-container .flex-grow {
268 flex-grow: 10;
269 flex-shrink: 0;
270 }
271 .flex-container .flex-shrink {
272 flex-grow: 0;
273 flex-shrink: 10;
274 }
275 .flex-container.flex-row.stretch {
276 flex-wrap: wrap;
277 align-items: baseline;
278 justify-content: stretch;
279 margin: 0;
280 }
281 .flex-container.flex-column {
282 flex-direction: column;
283 flex-wrap: wrap;
284 justify-content: center;
285 align-items: center;
286 }
287 .flex-container.flex-column.stretch {
288 align-items: stretch;
289 margin: 0;
290 }
291 .flex-container.child-gap-small > * {
292 margin: 0.25em;
293 }
294 #fossil-status-bar {
295 display: block;
296 font-family: monospace;
297 border-width: 1px;
298 border-style: inset;
299 border-color: inherit;
300 min-height: 1.5em;
301 font-size: 1.2em;
302 padding: 0.2em;
303 margin: 0.25em 0;
304 flex: 0 0 auto;
305 }
306 .font-size-100 {
307 font-size: 100%;
308 }
309 .font-size-125 {
310 font-size: 125%;
311 }
312 .font-size-150 {
313 font-size: 150%;
314 }
315 .font-size-175 {
316 font-size: 175%;
317 }
318 .font-size-200 {
319 font-size: 200%;
320 }
321
322 /**
323 .input-with-label is intended to be a wrapper element which
324 contain both a LABEL tag and an INPUT or SELECT control.
325 The wrapper is "necessary", as opposed to placing the INPUT
326 in the LABEL, so that we can include multiple INPUT
327 elements (e.g. a set of radio buttons).
328 */
329 .input-with-label {
330 border: 1px inset #808080;
331 border-radius: 0.5em;
332 padding: 0.25em 0.4em;
333 margin: 0 0.5em;
334 display: inline-block;
335 cursor: default;
336 }
337 .input-with-label > * {
338 vertical-align: middle;
339 }
340 .input-with-label > label {
341 display: inline; /* some skins set label display to block! */
342 }
343 .input-with-label > input {
344 margin: 0;
345 }
346 .input-with-label > button {
347 margin: 0;
348 }
349 .input-with-label > select {
350 margin: 0;
351 }
352 .input-with-label > input[type=text] {
353 margin: 0;
354 }
355 .input-with-label > textarea {
356 margin: 0;
357 }
358 .input-with-label > input[type=checkbox] {
359 vertical-align: sub;
360 }
361 .input-with-label > input[type=radio] {
362 vertical-align: sub;
363 }
364 .input-with-label > label {
365 font-weight: initial;
366 margin: 0 0.25em 0 0.25em;
367 vertical-align: middle;
368 }
369
370 DDED src/style.wikiedit.css
--- src/style.fileedit.css
+++ src/style.fileedit.css
@@ -15,15 +15,16 @@
15 height: initial/*undo damage from some skins*/;
16 max-width: initial /* default.css pins it at 95% */;
17 }
18 body.fileedit textarea:focus,
19 body.fileedit input:focus{
20 /* Depending on the skin, it might be useful to add one or both of
21 the following... */
22 /*border-width: 1px;*/
23 /*border: initial; */
24 }
25 body.fileedit fieldset:not(.tab-wrapper) {
26 margin: 0.5em 0 0.5em 0;
27 padding: 0.25em 0;
28 border-radius: 0.5em;
29 border-color: inherit;
30 border-width: 1px;
@@ -65,11 +66,11 @@
66 body.fileedit div.fileedit-preview {
67 margin: 0;
68 padding: 0;
69 }
70 body.fileedit #fileedit-tabs {
71 margin: 0.5em 0 0 0;
72 }
73 body.fileedit #fileedit-tab-preview-wrapper {
74 overflow: auto;
75 }
76 body.fileedit #fileedit-tab-fileselect > h1 {
@@ -114,27 +115,28 @@
115 }
116 body.fileedit #fileedit-file-selector {
117 display: flex;
118 flex-direction: column;
119 align-content: flex-start;
 
 
 
 
120 padding: 0 0.25em;
121 margin: 0;
122 min-height: 12em;
123 }
124 body.fileedit #fileedit-file-selector select {
125 margin: 0 0 0.5em 0;
126 height: initial;
127 font-family: monospace;
128 border: initial;
129 }
130 body.fileedit select:focus {
131 border: initial;
132 }
133 body.fileedit #fileedit-file-selector select option {
134 margin: 0 0 0.5em 0.55em;
135 }
136 body.fileedit select option,
137 body.fileedit select option:focus {
138 border: none;
139 }
140 body.fileedit #fileedit-file-selector > div {
141 padding: 0;
142 margin: 0;
@@ -184,185 +186,40 @@
186 }
187 body.fileedit .sbsdiffcols div.difftxtcol pre {
188 max-width: 44em;
189 }
190
191 body.fileedit #fileedit-edit-status {
192 border-radius: 0.25em 0.25em 0 0;
193 margin: 0;
194 padding: 0;
195 width: 100%;
196 cursor: initial;
197 display: flex;
198 flex-direction: row;
199 flex-wrap: wrap;
200 justify-content: space-between;
201 font-family: monospace;
202 }
203 body.fileedit #fileedit-edit-status > span.name > a {
204 display: block;
205 word-break: break-word /* needed for long paths */;
206 }
207 body.fileedit #fileedit-edit-status > span.links {
208 display: flex;
209 flex-wrap: wrap;
210 flex-direction: row;
211 }
212 body.fileedit #fileedit-file-selector span.is-new,
213 body.fileedit #fileedit-file-selector span.is-modified {
214 font-family: monospace;
215 }
216 body.fileedit #fileedit-edit-status span.links > * {
217 margin: 0 0.25em;
218 white-space: nowrap;
219 }
220 body.fileedit #fileedit-edit-status span.links > *::before {
221 content: "[";
222 }
223 body.fileedit #fileedit-edit-status span.links > *::after {
224 content: "]";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225 }
226
227 DDED src/style.wikiedit.css
--- a/src/style.wikiedit.css
+++ b/src/style.wikiedit.css
@@ -0,0 +1,185 @@
1
+body.wikieedit.waiting * {
2
+ /* Triggered during AJAX requests. */
3
+ cursor: wait;
4
+}
5
+body.wikiedit textarea,
6
+body.wikiedit textarea:focus,
7
+body.wikiedit input,
8
+body.wikiedit input:focus,
9
+body.wikiedit select,
10
+body.wikiedit select:focus{
11
+ /* Depending on the skin, it might be useful to add one or both of
12
+ the following... */
13
+ /*border-width: 1px;*/
14
+ /*border: initial; */
15
+}
16
+body.wikiedit div.wikiedit-preview {
17
+ margin: 0;
18
+ padding: 0;
19
+}
20
+body.wikiedit #wikiedit-tabs {
21
+ margin: 0.5em 0 0 0;
22
+}
23
+body.wikiedit #wikiedit-tab-preview-wrapper {
24
+ overflow: auto;
25
+}
26
+body.wikiedit .tab-container > .tabs > .tab{
27
+ margin-top: 0;
28
+ border: none;
29
+ border-radius: 0;
30
+ border-bottom-width: 1px;
31
+ border-bottom-style: dotted;
32
+}
33
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > button {
34
+ vertical-align: middle;
35
+ margin: 0.5em;
36
+}
37
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
38
+ vertical-align: middle;
39
+ margin: 0.5em;
40
+}
41
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-optiovertical-align: middle;
42
+ margin: 0ut-with-label {
43
+ margin: 0iting * {
44
+ /* Triggered during AJAX requests. */
45
+ cursor: wait;
46
+}
47
+body.wikiedit textarea,
48
+body.wikiedit textarea:focus,
49
+body.wikiedit input,
50
+body.wikiedit input:focus,
51
+body.wikiedit select,
52
+body.wikiedit select:focus{
53
+ /* Depending on the skin, it might be useful to add one or both of
54
+ the following... */
55
+ /*border-width: 1px;*/
56
+ /*border: initial; */
57
+}
58
+body.wikiedit div.wikiedit-preview {
59
+ margin: 0;
60
+ padding: 0;
61
+}
62
+body.wikiedit #wikiedit-tabs {
63
+ margin: 0.5em 0 0 0;
64
+}
65
+body.wikiedit #wikiedit-tab-preview-wrapper {
66
+ overflow: auto;
67
+}
68
+body.wikiedit .tab-container > .tabs > .tab{
69
+ margin-top: 0;
70
+ border: none;
71
+ border-radius: 0;
72
+ border-bottom-width: 1px;
73
+ border-bottom-style: dotted;
74
+}
75
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > button {
76
+ vertical-align: middle;
77
+ margin: 0.5em;
78
+}
79
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
80
+ vertical-align: middle;
81
+ margin: 0.5em;
82
+}
83
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-optiovertical-align: middle;
84
+ margin: 0ut-with-label {
85
+ margin: 0 0.5em 0.25em 0.5em;
86
+}
87
+body.wikiedit label {
88
+ display: inline; /* some skins set label display to block! */
89
+}
90
+body.wikiedit .wikiedit-options > div > * {
91
+ margin: 0.25em;
92
+}
93
+body.wikiedit .wikiedit-options.flex-container.flex-row {
94
+ align-items: first baseline;
95
+}
96
+body.wikiedit .WikiList {
97
+ display: flex;
98
+ flex-direction: column;
99
+ align-items: start;
100
+}
101
+body.wikiedit .WikiList select {
102
+ font-size: 110%;
103
+ margin: initial;
104
+ height: initial /* some skins set these to a fixed height */;
105
+ font-family: monospace;
106
+ border: initial;
107
+}
108
+body.wikiedit select:focus {
109
+ border: initial;
110
+}
111
+body.wikiedit .WikiList select option {
112
+ margin: 0 0 0.5em 0.55em;
113
+}
114
+body.wikiedit select option,
115
+body.wikiedit select option:focus {
116
+ border: none;
117
+}
118
+body.wikiedit .WikiList select option.stashed,
119
+body.wikiedit .WikiList select option.stashed-new,
120
+body.wikiedit .WikiList select option.deleted {
121
+ marginbody.wikieedit.waiting * {
122
+ /* Triggered during AJAX requests. */
123
+ cursor: wait;
124
+}
125
+body.wikiedit textarea,
126
+body.wikiedit textarea:focus,
127
+body.wikiedit input,
128
+body.wikiedit input:focus,
129
+body.wikiedit select,
130
+body.wikiedit select:focus{
131
+ /* Depending on the skin, it might be useful to add one or both of
132
+ the following... */
133
+ /*border-width: 1px;*/
134
+ /*border: initial; */
135
+}
136
+body.wikiedit div.wikiedit-preview {
137
+ margin: 0;
138
+ padding: 0;
139
+}
140
+body.wikiedit #wikiedit-tabs {
141
+ margin: 0.5em 0 0 0;
142
+}
143
+body.wikiedit #wikiedit-tab-preview-wrapper {
144
+ overflow: auto;
145
+}
146
+body.wikiedit .tab-container > .tabs > .tab{
147
+ margin-top: 0;
148
+ border: none;
149
+ border-radius: 0;
150
+ border-bottom-width: 1px;
151
+ border-bottom-style: dotted;
152
+}
153
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > button {
154
+ vertical-align: middle;
155
+ margin: 0.5em;
156
+}
157
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
158
+ vertical-align: middle;
159
+ margin: 0.5em;
160
+}
161
+body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-optiovertical-align: middle;
162
+ margin: 0ut-with-label {
163
+ margin: 0 0.5em 0.25em 0.5em;
164
+}
165
+body.wikiedit label {
166
+ display: inline; /* some skins set label display to block! */
167
+}
168
+body.wikiedit .wikiedit-options > div > * {
169
+ margin: 0.25em;
170
+}
171
+body.wikiedit .wikiedit-options.flex-container.flex-row {
172
+ align-items: first baseline;
173
+}
174
+body.wikiedit .WikiList {
175
+ display: flex;
176
+ flex-direction: column;
177
+ align-items: start;
178
+}
179
+body.wikiedit .WikiList select {
180
+ font-size: 110%;
181
+ margin: initial;
182
+edit #wikiedit-tabsns > input {
183
+ vertical-alig flex: 10 1 auto;
184
+}
185
+
--- a/src/style.wikiedit.css
+++ b/src/style.wikiedit.css
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/style.wikiedit.css
+++ b/src/style.wikiedit.css
@@ -0,0 +1,185 @@
1 body.wikieedit.waiting * {
2 /* Triggered during AJAX requests. */
3 cursor: wait;
4 }
5 body.wikiedit textarea,
6 body.wikiedit textarea:focus,
7 body.wikiedit input,
8 body.wikiedit input:focus,
9 body.wikiedit select,
10 body.wikiedit select:focus{
11 /* Depending on the skin, it might be useful to add one or both of
12 the following... */
13 /*border-width: 1px;*/
14 /*border: initial; */
15 }
16 body.wikiedit div.wikiedit-preview {
17 margin: 0;
18 padding: 0;
19 }
20 body.wikiedit #wikiedit-tabs {
21 margin: 0.5em 0 0 0;
22 }
23 body.wikiedit #wikiedit-tab-preview-wrapper {
24 overflow: auto;
25 }
26 body.wikiedit .tab-container > .tabs > .tab{
27 margin-top: 0;
28 border: none;
29 border-radius: 0;
30 border-bottom-width: 1px;
31 border-bottom-style: dotted;
32 }
33 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > button {
34 vertical-align: middle;
35 margin: 0.5em;
36 }
37 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
38 vertical-align: middle;
39 margin: 0.5em;
40 }
41 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-optiovertical-align: middle;
42 margin: 0ut-with-label {
43 margin: 0iting * {
44 /* Triggered during AJAX requests. */
45 cursor: wait;
46 }
47 body.wikiedit textarea,
48 body.wikiedit textarea:focus,
49 body.wikiedit input,
50 body.wikiedit input:focus,
51 body.wikiedit select,
52 body.wikiedit select:focus{
53 /* Depending on the skin, it might be useful to add one or both of
54 the following... */
55 /*border-width: 1px;*/
56 /*border: initial; */
57 }
58 body.wikiedit div.wikiedit-preview {
59 margin: 0;
60 padding: 0;
61 }
62 body.wikiedit #wikiedit-tabs {
63 margin: 0.5em 0 0 0;
64 }
65 body.wikiedit #wikiedit-tab-preview-wrapper {
66 overflow: auto;
67 }
68 body.wikiedit .tab-container > .tabs > .tab{
69 margin-top: 0;
70 border: none;
71 border-radius: 0;
72 border-bottom-width: 1px;
73 border-bottom-style: dotted;
74 }
75 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > button {
76 vertical-align: middle;
77 margin: 0.5em;
78 }
79 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
80 vertical-align: middle;
81 margin: 0.5em;
82 }
83 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-optiovertical-align: middle;
84 margin: 0ut-with-label {
85 margin: 0 0.5em 0.25em 0.5em;
86 }
87 body.wikiedit label {
88 display: inline; /* some skins set label display to block! */
89 }
90 body.wikiedit .wikiedit-options > div > * {
91 margin: 0.25em;
92 }
93 body.wikiedit .wikiedit-options.flex-container.flex-row {
94 align-items: first baseline;
95 }
96 body.wikiedit .WikiList {
97 display: flex;
98 flex-direction: column;
99 align-items: start;
100 }
101 body.wikiedit .WikiList select {
102 font-size: 110%;
103 margin: initial;
104 height: initial /* some skins set these to a fixed height */;
105 font-family: monospace;
106 border: initial;
107 }
108 body.wikiedit select:focus {
109 border: initial;
110 }
111 body.wikiedit .WikiList select option {
112 margin: 0 0 0.5em 0.55em;
113 }
114 body.wikiedit select option,
115 body.wikiedit select option:focus {
116 border: none;
117 }
118 body.wikiedit .WikiList select option.stashed,
119 body.wikiedit .WikiList select option.stashed-new,
120 body.wikiedit .WikiList select option.deleted {
121 marginbody.wikieedit.waiting * {
122 /* Triggered during AJAX requests. */
123 cursor: wait;
124 }
125 body.wikiedit textarea,
126 body.wikiedit textarea:focus,
127 body.wikiedit input,
128 body.wikiedit input:focus,
129 body.wikiedit select,
130 body.wikiedit select:focus{
131 /* Depending on the skin, it might be useful to add one or both of
132 the following... */
133 /*border-width: 1px;*/
134 /*border: initial; */
135 }
136 body.wikiedit div.wikiedit-preview {
137 margin: 0;
138 padding: 0;
139 }
140 body.wikiedit #wikiedit-tabs {
141 margin: 0.5em 0 0 0;
142 }
143 body.wikiedit #wikiedit-tab-preview-wrapper {
144 overflow: auto;
145 }
146 body.wikiedit .tab-container > .tabs > .tab{
147 margin-top: 0;
148 border: none;
149 border-radius: 0;
150 border-bottom-width: 1px;
151 border-bottom-style: dotted;
152 }
153 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > button {
154 vertical-align: middle;
155 margin: 0.5em;
156 }
157 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input {
158 vertical-align: middle;
159 margin: 0.5em;
160 }
161 body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-optiovertical-align: middle;
162 margin: 0ut-with-label {
163 margin: 0 0.5em 0.25em 0.5em;
164 }
165 body.wikiedit label {
166 display: inline; /* some skins set label display to block! */
167 }
168 body.wikiedit .wikiedit-options > div > * {
169 margin: 0.25em;
170 }
171 body.wikiedit .wikiedit-options.flex-container.flex-row {
172 align-items: first baseline;
173 }
174 body.wikiedit .WikiList {
175 display: flex;
176 flex-direction: column;
177 align-items: start;
178 }
179 body.wikiedit .WikiList select {
180 font-size: 110%;
181 margin: initial;
182 edit #wikiedit-tabsns > input {
183 vertical-alig flex: 10 1 auto;
184 }
185
+5 -4
--- src/sync.c
+++ src/sync.c
@@ -217,11 +217,11 @@
217217
** --ssh-command SSH Use SSH as the "ssh" command
218218
** -v|--verbose Additional (debugging) output
219219
** --verily Exchange extra information with the remote
220220
** to ensure no content is overlooked
221221
**
222
-** See also: clone, config pull, push, remote-url, sync
222
+** See also: [[clone]], [[config]], [[push]], [[remote-url]], [[sync]]
223223
*/
224224
void pull_cmd(void){
225225
unsigned configFlags = 0;
226226
unsigned syncFlags = SYNC_PULL;
227227
unsigned urlOmitFlags = 0;
@@ -266,11 +266,11 @@
266266
** --ssh-command SSH Use SSH as the "ssh" command
267267
** -v|--verbose Additional (debugging) output
268268
** --verily Exchange extra information with the remote
269269
** to ensure no content is overlooked
270270
**
271
-** See also: clone, config push, pull, remote-url, sync
271
+** See also: [[clone]], [[config]], [[pull]], [[remote-url]], [[sync]]
272272
*/
273273
void push_cmd(void){
274274
unsigned configFlags = 0;
275275
unsigned syncFlags = SYNC_PUSH;
276276
process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -312,11 +312,11 @@
312312
** -u|--unversioned Also sync unversioned content
313313
** -v|--verbose Additional (debugging) output
314314
** --verily Exchange extra information with the remote
315315
** to ensure no content is overlooked
316316
**
317
-** See also: clone, pull, push, remote-url
317
+** See also: [[clone]], [[pull]], [[push]], [[remote-url]]
318318
*/
319319
void sync_cmd(void){
320320
unsigned configFlags = 0;
321321
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322322
if( find_option("unversioned","u",0)!=0 ){
@@ -345,11 +345,12 @@
345345
verify_all_options();
346346
client_sync(syncFlags, 0, 0, 0);
347347
}
348348
349349
/*
350
-** COMMAND: remote-url
350
+** COMMAND: remote
351
+** COMMAND: remote-url*
351352
**
352353
** Usage: %fossil remote-url ?URL|off?
353354
**
354355
** Query and/or change the default server URL used by the "pull", "push",
355356
** and "sync" commands.
356357
--- src/sync.c
+++ src/sync.c
@@ -217,11 +217,11 @@
217 ** --ssh-command SSH Use SSH as the "ssh" command
218 ** -v|--verbose Additional (debugging) output
219 ** --verily Exchange extra information with the remote
220 ** to ensure no content is overlooked
221 **
222 ** See also: clone, config pull, push, remote-url, sync
223 */
224 void pull_cmd(void){
225 unsigned configFlags = 0;
226 unsigned syncFlags = SYNC_PULL;
227 unsigned urlOmitFlags = 0;
@@ -266,11 +266,11 @@
266 ** --ssh-command SSH Use SSH as the "ssh" command
267 ** -v|--verbose Additional (debugging) output
268 ** --verily Exchange extra information with the remote
269 ** to ensure no content is overlooked
270 **
271 ** See also: clone, config push, pull, remote-url, sync
272 */
273 void push_cmd(void){
274 unsigned configFlags = 0;
275 unsigned syncFlags = SYNC_PUSH;
276 process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -312,11 +312,11 @@
312 ** -u|--unversioned Also sync unversioned content
313 ** -v|--verbose Additional (debugging) output
314 ** --verily Exchange extra information with the remote
315 ** to ensure no content is overlooked
316 **
317 ** See also: clone, pull, push, remote-url
318 */
319 void sync_cmd(void){
320 unsigned configFlags = 0;
321 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322 if( find_option("unversioned","u",0)!=0 ){
@@ -345,11 +345,12 @@
345 verify_all_options();
346 client_sync(syncFlags, 0, 0, 0);
347 }
348
349 /*
350 ** COMMAND: remote-url
 
351 **
352 ** Usage: %fossil remote-url ?URL|off?
353 **
354 ** Query and/or change the default server URL used by the "pull", "push",
355 ** and "sync" commands.
356
--- src/sync.c
+++ src/sync.c
@@ -217,11 +217,11 @@
217 ** --ssh-command SSH Use SSH as the "ssh" command
218 ** -v|--verbose Additional (debugging) output
219 ** --verily Exchange extra information with the remote
220 ** to ensure no content is overlooked
221 **
222 ** See also: [[clone]], [[config]], [[push]], [[remote-url]], [[sync]]
223 */
224 void pull_cmd(void){
225 unsigned configFlags = 0;
226 unsigned syncFlags = SYNC_PULL;
227 unsigned urlOmitFlags = 0;
@@ -266,11 +266,11 @@
266 ** --ssh-command SSH Use SSH as the "ssh" command
267 ** -v|--verbose Additional (debugging) output
268 ** --verily Exchange extra information with the remote
269 ** to ensure no content is overlooked
270 **
271 ** See also: [[clone]], [[config]], [[pull]], [[remote-url]], [[sync]]
272 */
273 void push_cmd(void){
274 unsigned configFlags = 0;
275 unsigned syncFlags = SYNC_PUSH;
276 process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -312,11 +312,11 @@
312 ** -u|--unversioned Also sync unversioned content
313 ** -v|--verbose Additional (debugging) output
314 ** --verily Exchange extra information with the remote
315 ** to ensure no content is overlooked
316 **
317 ** See also: [[clone]], [[pull]], [[push]], [[remote-url]]
318 */
319 void sync_cmd(void){
320 unsigned configFlags = 0;
321 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322 if( find_option("unversioned","u",0)!=0 ){
@@ -345,11 +345,12 @@
345 verify_all_options();
346 client_sync(syncFlags, 0, 0, 0);
347 }
348
349 /*
350 ** COMMAND: remote
351 ** COMMAND: remote-url*
352 **
353 ** Usage: %fossil remote-url ?URL|off?
354 **
355 ** Query and/or change the default server URL used by the "pull", "push",
356 ** and "sync" commands.
357
+5 -4
--- src/sync.c
+++ src/sync.c
@@ -217,11 +217,11 @@
217217
** --ssh-command SSH Use SSH as the "ssh" command
218218
** -v|--verbose Additional (debugging) output
219219
** --verily Exchange extra information with the remote
220220
** to ensure no content is overlooked
221221
**
222
-** See also: clone, config pull, push, remote-url, sync
222
+** See also: [[clone]], [[config]], [[push]], [[remote-url]], [[sync]]
223223
*/
224224
void pull_cmd(void){
225225
unsigned configFlags = 0;
226226
unsigned syncFlags = SYNC_PULL;
227227
unsigned urlOmitFlags = 0;
@@ -266,11 +266,11 @@
266266
** --ssh-command SSH Use SSH as the "ssh" command
267267
** -v|--verbose Additional (debugging) output
268268
** --verily Exchange extra information with the remote
269269
** to ensure no content is overlooked
270270
**
271
-** See also: clone, config push, pull, remote-url, sync
271
+** See also: [[clone]], [[config]], [[pull]], [[remote-url]], [[sync]]
272272
*/
273273
void push_cmd(void){
274274
unsigned configFlags = 0;
275275
unsigned syncFlags = SYNC_PUSH;
276276
process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -312,11 +312,11 @@
312312
** -u|--unversioned Also sync unversioned content
313313
** -v|--verbose Additional (debugging) output
314314
** --verily Exchange extra information with the remote
315315
** to ensure no content is overlooked
316316
**
317
-** See also: clone, pull, push, remote-url
317
+** See also: [[clone]], [[pull]], [[push]], [[remote-url]]
318318
*/
319319
void sync_cmd(void){
320320
unsigned configFlags = 0;
321321
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322322
if( find_option("unversioned","u",0)!=0 ){
@@ -345,11 +345,12 @@
345345
verify_all_options();
346346
client_sync(syncFlags, 0, 0, 0);
347347
}
348348
349349
/*
350
-** COMMAND: remote-url
350
+** COMMAND: remote
351
+** COMMAND: remote-url*
351352
**
352353
** Usage: %fossil remote-url ?URL|off?
353354
**
354355
** Query and/or change the default server URL used by the "pull", "push",
355356
** and "sync" commands.
356357
--- src/sync.c
+++ src/sync.c
@@ -217,11 +217,11 @@
217 ** --ssh-command SSH Use SSH as the "ssh" command
218 ** -v|--verbose Additional (debugging) output
219 ** --verily Exchange extra information with the remote
220 ** to ensure no content is overlooked
221 **
222 ** See also: clone, config pull, push, remote-url, sync
223 */
224 void pull_cmd(void){
225 unsigned configFlags = 0;
226 unsigned syncFlags = SYNC_PULL;
227 unsigned urlOmitFlags = 0;
@@ -266,11 +266,11 @@
266 ** --ssh-command SSH Use SSH as the "ssh" command
267 ** -v|--verbose Additional (debugging) output
268 ** --verily Exchange extra information with the remote
269 ** to ensure no content is overlooked
270 **
271 ** See also: clone, config push, pull, remote-url, sync
272 */
273 void push_cmd(void){
274 unsigned configFlags = 0;
275 unsigned syncFlags = SYNC_PUSH;
276 process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -312,11 +312,11 @@
312 ** -u|--unversioned Also sync unversioned content
313 ** -v|--verbose Additional (debugging) output
314 ** --verily Exchange extra information with the remote
315 ** to ensure no content is overlooked
316 **
317 ** See also: clone, pull, push, remote-url
318 */
319 void sync_cmd(void){
320 unsigned configFlags = 0;
321 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322 if( find_option("unversioned","u",0)!=0 ){
@@ -345,11 +345,12 @@
345 verify_all_options();
346 client_sync(syncFlags, 0, 0, 0);
347 }
348
349 /*
350 ** COMMAND: remote-url
 
351 **
352 ** Usage: %fossil remote-url ?URL|off?
353 **
354 ** Query and/or change the default server URL used by the "pull", "push",
355 ** and "sync" commands.
356
--- src/sync.c
+++ src/sync.c
@@ -217,11 +217,11 @@
217 ** --ssh-command SSH Use SSH as the "ssh" command
218 ** -v|--verbose Additional (debugging) output
219 ** --verily Exchange extra information with the remote
220 ** to ensure no content is overlooked
221 **
222 ** See also: [[clone]], [[config]], [[push]], [[remote-url]], [[sync]]
223 */
224 void pull_cmd(void){
225 unsigned configFlags = 0;
226 unsigned syncFlags = SYNC_PULL;
227 unsigned urlOmitFlags = 0;
@@ -266,11 +266,11 @@
266 ** --ssh-command SSH Use SSH as the "ssh" command
267 ** -v|--verbose Additional (debugging) output
268 ** --verily Exchange extra information with the remote
269 ** to ensure no content is overlooked
270 **
271 ** See also: [[clone]], [[config]], [[pull]], [[remote-url]], [[sync]]
272 */
273 void push_cmd(void){
274 unsigned configFlags = 0;
275 unsigned syncFlags = SYNC_PUSH;
276 process_sync_args(&configFlags, &syncFlags, 0, 0);
@@ -312,11 +312,11 @@
312 ** -u|--unversioned Also sync unversioned content
313 ** -v|--verbose Additional (debugging) output
314 ** --verily Exchange extra information with the remote
315 ** to ensure no content is overlooked
316 **
317 ** See also: [[clone]], [[pull]], [[push]], [[remote-url]]
318 */
319 void sync_cmd(void){
320 unsigned configFlags = 0;
321 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
322 if( find_option("unversioned","u",0)!=0 ){
@@ -345,11 +345,12 @@
345 verify_all_options();
346 client_sync(syncFlags, 0, 0, 0);
347 }
348
349 /*
350 ** COMMAND: remote
351 ** COMMAND: remote-url*
352 **
353 ** Usage: %fossil remote-url ?URL|off?
354 **
355 ** Query and/or change the default server URL used by the "pull", "push",
356 ** and "sync" commands.
357
+6 -2
--- src/timeline.c
+++ src/timeline.c
@@ -1083,12 +1083,12 @@
10831083
cgi_printf("\"br\":\"%j\",", pRow->zBranch ? pRow->zBranch : "");
10841084
cgi_printf("\"h\":\"%!S\"}%s",
10851085
pRow->zUuid, pRow->pNext ? ",\n" : "]\n");
10861086
}
10871087
@ }</script>
1088
- style_graph_generator();
1089
- style_copybutton_control(); /* Dependency: graph.js requires copybtn.js. */
1088
+ builtin_request_js("graph.js");
1089
+ builtin_request_js("copybtn.js"); /* Required by graph.js */
10901090
graph_free(pGraph);
10911091
}
10921092
}
10931093
10941094
/*
@@ -1741,10 +1741,14 @@
17411741
}
17421742
}else{
17431743
z = "50";
17441744
nEntry = 50;
17451745
}
1746
+
1747
+ /* Undocumented query parameter to set JS mode */
1748
+ builtin_set_js_delivery_mode(P("jsmode"),1);
1749
+
17461750
secondaryRid = name_to_typed_rid(P("sel2"),"ci");
17471751
selectedRid = name_to_typed_rid(P("sel1"),"ci");
17481752
cgi_replace_query_parameter("n",z);
17491753
cookie_write_parameter("n","n",0);
17501754
tmFlags |= timeline_ss_submenu();
17511755
--- src/timeline.c
+++ src/timeline.c
@@ -1083,12 +1083,12 @@
1083 cgi_printf("\"br\":\"%j\",", pRow->zBranch ? pRow->zBranch : "");
1084 cgi_printf("\"h\":\"%!S\"}%s",
1085 pRow->zUuid, pRow->pNext ? ",\n" : "]\n");
1086 }
1087 @ }</script>
1088 style_graph_generator();
1089 style_copybutton_control(); /* Dependency: graph.js requires copybtn.js. */
1090 graph_free(pGraph);
1091 }
1092 }
1093
1094 /*
@@ -1741,10 +1741,14 @@
1741 }
1742 }else{
1743 z = "50";
1744 nEntry = 50;
1745 }
 
 
 
 
1746 secondaryRid = name_to_typed_rid(P("sel2"),"ci");
1747 selectedRid = name_to_typed_rid(P("sel1"),"ci");
1748 cgi_replace_query_parameter("n",z);
1749 cookie_write_parameter("n","n",0);
1750 tmFlags |= timeline_ss_submenu();
1751
--- src/timeline.c
+++ src/timeline.c
@@ -1083,12 +1083,12 @@
1083 cgi_printf("\"br\":\"%j\",", pRow->zBranch ? pRow->zBranch : "");
1084 cgi_printf("\"h\":\"%!S\"}%s",
1085 pRow->zUuid, pRow->pNext ? ",\n" : "]\n");
1086 }
1087 @ }</script>
1088 builtin_request_js("graph.js");
1089 builtin_request_js("copybtn.js"); /* Required by graph.js */
1090 graph_free(pGraph);
1091 }
1092 }
1093
1094 /*
@@ -1741,10 +1741,14 @@
1741 }
1742 }else{
1743 z = "50";
1744 nEntry = 50;
1745 }
1746
1747 /* Undocumented query parameter to set JS mode */
1748 builtin_set_js_delivery_mode(P("jsmode"),1);
1749
1750 secondaryRid = name_to_typed_rid(P("sel2"),"ci");
1751 selectedRid = name_to_typed_rid(P("sel1"),"ci");
1752 cgi_replace_query_parameter("n",z);
1753 cookie_write_parameter("n","n",0);
1754 tmFlags |= timeline_ss_submenu();
1755
+1 -1
--- src/undo.c
+++ src/undo.c
@@ -462,11 +462,11 @@
462462
** that are undoable.
463463
**
464464
** Options:
465465
** -n|--dry-run do not make changes but show what would be done
466466
**
467
-** See also: commit, status
467
+** See also: [[commit]], [[status]]
468468
*/
469469
void undo_cmd(void){
470470
int isRedo = g.argv[1][0]=='r';
471471
int undo_available;
472472
int dryRunFlag = find_option("dry-run", "n", 0)!=0;
473473
--- src/undo.c
+++ src/undo.c
@@ -462,11 +462,11 @@
462 ** that are undoable.
463 **
464 ** Options:
465 ** -n|--dry-run do not make changes but show what would be done
466 **
467 ** See also: commit, status
468 */
469 void undo_cmd(void){
470 int isRedo = g.argv[1][0]=='r';
471 int undo_available;
472 int dryRunFlag = find_option("dry-run", "n", 0)!=0;
473
--- src/undo.c
+++ src/undo.c
@@ -462,11 +462,11 @@
462 ** that are undoable.
463 **
464 ** Options:
465 ** -n|--dry-run do not make changes but show what would be done
466 **
467 ** See also: [[commit]], [[status]]
468 */
469 void undo_cmd(void){
470 int isRedo = g.argv[1][0]=='r';
471 int undo_available;
472 int dryRunFlag = find_option("dry-run", "n", 0)!=0;
473
+2 -2
--- src/update.c
+++ src/update.c
@@ -108,11 +108,11 @@
108108
** checkin which modified them).
109109
** -K|--keep-merge-files On merge conflict, retain the temporary files
110110
** used for merging, named *-baseline, *-original,
111111
** and *-merge.
112112
**
113
-** See also: revert
113
+** See also: [[revert]]
114114
*/
115115
void update_cmd(void){
116116
int vid; /* Current version */
117117
int tid=0; /* Target version - version we are changing to */
118118
Stmt q;
@@ -786,11 +786,11 @@
786786
**
787787
** Options:
788788
** -r|--revision VERSION Revert given FILE(s) back to given
789789
** VERSION
790790
**
791
-** See also: redo, undo, checkout, update
791
+** See also: [[redo]], [[undo]], [[checkout]], [[update]]
792792
*/
793793
void revert_cmd(void){
794794
Manifest *pCoManifest; /* Manifest of current checkout */
795795
Manifest *pRvManifest; /* Manifest of selected revert version */
796796
ManifestFile *pCoFile; /* File within current checkout manifest */
797797
--- src/update.c
+++ src/update.c
@@ -108,11 +108,11 @@
108 ** checkin which modified them).
109 ** -K|--keep-merge-files On merge conflict, retain the temporary files
110 ** used for merging, named *-baseline, *-original,
111 ** and *-merge.
112 **
113 ** See also: revert
114 */
115 void update_cmd(void){
116 int vid; /* Current version */
117 int tid=0; /* Target version - version we are changing to */
118 Stmt q;
@@ -786,11 +786,11 @@
786 **
787 ** Options:
788 ** -r|--revision VERSION Revert given FILE(s) back to given
789 ** VERSION
790 **
791 ** See also: redo, undo, checkout, update
792 */
793 void revert_cmd(void){
794 Manifest *pCoManifest; /* Manifest of current checkout */
795 Manifest *pRvManifest; /* Manifest of selected revert version */
796 ManifestFile *pCoFile; /* File within current checkout manifest */
797
--- src/update.c
+++ src/update.c
@@ -108,11 +108,11 @@
108 ** checkin which modified them).
109 ** -K|--keep-merge-files On merge conflict, retain the temporary files
110 ** used for merging, named *-baseline, *-original,
111 ** and *-merge.
112 **
113 ** See also: [[revert]]
114 */
115 void update_cmd(void){
116 int vid; /* Current version */
117 int tid=0; /* Target version - version we are changing to */
118 Stmt q;
@@ -786,11 +786,11 @@
786 **
787 ** Options:
788 ** -r|--revision VERSION Revert given FILE(s) back to given
789 ** VERSION
790 **
791 ** See also: [[redo]], [[undo]], [[checkout]], [[update]]
792 */
793 void revert_cmd(void){
794 Manifest *pCoManifest; /* Manifest of current checkout */
795 Manifest *pRvManifest; /* Manifest of selected revert version */
796 ManifestFile *pCoFile; /* File within current checkout manifest */
797
+716 -236
--- src/wiki.c
+++ src/wiki.c
@@ -102,11 +102,10 @@
102102
" WHERE tagid=%d AND mtime<%.16g"
103103
" ORDER BY mtime DESC LIMIT 1",
104104
tagid, mtime);
105105
}
106106
107
-
108107
/*
109108
** WEBPAGE: home
110109
** WEBPAGE: index
111110
** WEBPAGE: not_found
112111
**
@@ -398,10 +397,24 @@
398397
if( sqlite3_strglob("tag/*", zPageName)==0 ){
399398
return WIKITYPE_TAG;
400399
}
401400
return WIKITYPE_NORMAL;
402401
}
402
+
403
+/*
404
+** Returns a JSON-friendly string form of the integer value returned
405
+** by wiki_page_type(zPageName).
406
+*/
407
+const char * wiki_page_type_name(const char *zPageName){
408
+ switch(wiki_page_type(zPageName)){
409
+ case WIKITYPE_CHECKIN: return "checkin";
410
+ case WIKITYPE_BRANCH: return "branch";
411
+ case WIKITYPE_TAG: return "tag";
412
+ case WIKITYPE_NORMAL:
413
+ default: return "normal";
414
+ }
415
+}
403416
404417
/*
405418
** Add an appropriate style_header() for either the /wiki or /wikiedit page
406419
** for zPageName. zExtra is an empty string for /wiki but has the text
407420
** "Edit: " for /wikiedit.
@@ -541,16 +554,11 @@
541554
zMimetype = wiki_filter_mimetypes(zMimetype);
542555
if( !g.isHome && !noSubmenu ){
543556
if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
544557
&& wiki_special_permission(zPageName)
545558
){
546
- if( db_get_boolean("wysiwyg-wiki", 0) ){
547
- style_submenu_element("Edit", "%R/wikiedit?name=%T&wysiwyg=1",
548
- zPageName);
549
- }else{
550
- style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
551
- }
559
+ style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
552560
}else if( rid && g.perm.ApndWiki ){
553561
style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
554562
}
555563
if( g.perm.Hyperlink ){
556564
style_submenu_element("History", "%R/whistory?name=%T", zPageName);
@@ -620,220 +628,692 @@
620628
return azStyles[i+1];
621629
}
622630
}
623631
return azStyles[1];
624632
}
633
+
634
+/*
635
+ ** Tries to fetch a wiki page for the given name. If found, it
636
+ ** returns true, else false.
637
+ **
638
+ ** versionsBack specifies how many versions back in the history to
639
+ ** fetch. Use 0 for the latest version, 1 for its parent, etc.
640
+ **
641
+ ** If pRid is not NULL then if a result is found *pRid is set to its
642
+ ** RID. If ppWiki is not NULL then if found *ppWiki is set to the
643
+ ** loaded wiki object, which the caller is responsible for passing to
644
+ ** manifest_destroy().
645
+ */
646
+static int wiki_fetch_by_name( const char *zPageName,
647
+ unsigned int versionsBack,
648
+ int * pRid, Manifest **ppWiki ){
649
+ Manifest *pWiki = 0;
650
+ char *zTag = mprintf("wiki-%s", zPageName);
651
+ Stmt q = empty_Stmt;
652
+ int rid = 0;
653
+
654
+ db_prepare(&q, "SELECT rid FROM tagxref"
655
+ " WHERE tagid=(SELECT tagid FROM tag WHERE"
656
+ " tagname=%Q) "
657
+ " ORDER BY mtime DESC LIMIT -1 OFFSET %u", zTag,
658
+ versionsBack);
659
+ fossil_free(zTag);
660
+ if(SQLITE_ROW == db_step(&q)){
661
+ rid = db_column_int(&q, 0);
662
+ }
663
+ db_finalize(&q);
664
+ if( rid == 0 ){
665
+ return 0;
666
+ }
667
+ else if(pRid){
668
+ *pRid = rid;
669
+ }
670
+ if(ppWiki){
671
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
672
+ if( pWiki==0 ){
673
+ /* "Cannot happen." */
674
+ return 0;
675
+ }
676
+ *ppWiki = pWiki;
677
+ }
678
+ return 1;
679
+}
680
+
681
+/*
682
+** Determines whether the wiki page with the given name can be edited
683
+** or created by the current user. If not, an AJAX error is queued and
684
+** false is returned, else true is returned. A NULL, empty, or
685
+** malformed name is considered non-writable, regardless of the user.
686
+**
687
+** If pRid is not NULL then this function writes the page's rid to
688
+** *pRid (whether or not access is granted). On error or if the page
689
+** does not yet exist, *pRid will be set to 0.
690
+**
691
+** Note that the sandbox is a special case: it is a pseudo-page with
692
+** no rid and the /wikiajax API does not allow anyone to actually save
693
+** a sandbox page, but it is reported as writable here (with rid 0).
694
+*/
695
+static int wiki_ajax_can_write(const char *zPageName, int * pRid){
696
+ int rid = 0;
697
+ const char * zErr = 0;
698
+
699
+ if(pRid) *pRid = 0;
700
+ if(!zPageName || !*zPageName
701
+ || !wiki_name_is_wellformed((unsigned const char *)zPageName)){
702
+ zErr = "Invalid page name.";
703
+ }else if(is_sandbox(zPageName)){
704
+ return 1;
705
+ }else{
706
+ wiki_fetch_by_name(zPageName, 0, &rid, 0);
707
+ if(pRid) *pRid = rid;
708
+ if(!wiki_special_permission(zPageName)){
709
+ zErr = "Editing this page requires non-wiki write permissions.";
710
+ }else if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
711
+ return 3;
712
+ }else if(rid && !g.perm.WrWiki){
713
+ zErr = "Requires wiki-write permissions.";
714
+ }else if(!rid && !g.perm.NewWiki){
715
+ zErr = "Requires new-wiki permissions.";
716
+ }else{
717
+ zErr = "Cannot happen! Please report this as a bug.";
718
+ }
719
+ }
720
+ ajax_route_error(403, "%s", zErr);
721
+ return 0;
722
+}
723
+
724
+/*
725
+** Loads the given wiki page, sets the response type to
726
+** application/json, and emits it as a JSON object. If zPageName is a
727
+** sandbox page then a "fake" object is emitted, as the wikiajax API
728
+** does not permit saving the sandbox.
729
+**
730
+** Returns true on success, false on error, and on error it
731
+** queues up a JSON-format error response.
732
+**
733
+** Output JSON format:
734
+**
735
+** { name: "page name",
736
+** type: "normal" | "tag" | "checkin" | "branch" | "sandbox",
737
+** mimetype: "mime type",
738
+** version: UUID string or null for a sandbox page,
739
+** parent: "parent uuid" or null if no parent,
740
+** isDeleted: true if the page has no content (is "deleted")
741
+** else not set (making it "falsy" in JS),
742
+** content: "page content" (only if includeContent is true)
743
+** }
744
+**
745
+** If includeContent is false then the content member is elided.
746
+*/
747
+static int wiki_ajax_emit_page_object(const char *zPageName,
748
+ int includeContent){
749
+ Manifest * pWiki = 0;
750
+ char * zUuid;
751
+
752
+ if( is_sandbox(zPageName) ){
753
+ char * zMimetype =
754
+ db_get("sandbox-mimetype","text/x-fossil-wiki");
755
+ char * zBody = db_get("sandbox","");
756
+ CX("{\"name\": %!j, \"type\": \"sandbox\", "
757
+ "\"mimetype\": %!j, \"version\": null, \"parent\": null",
758
+ zPageName, zMimetype);
759
+ if(includeContent){
760
+ CX(", \"content\": %!j",
761
+ zBody);
762
+ }
763
+ CX("}");
764
+ fossil_free(zMimetype);
765
+ fossil_free(zBody);
766
+ return 1;
767
+ }else if( !wiki_fetch_by_name(zPageName, 0, 0, &pWiki) ){
768
+ ajax_route_error(404, "Wiki page could not be loaded: %s",
769
+ zPageName);
770
+ return 0;
771
+ }else{
772
+ zUuid = rid_to_uuid(pWiki->rid);
773
+ CX("{\"name\": %!j, \"type\": %!j, "
774
+ "\"version\": %!j, "
775
+ "\"mimetype\": %!j, ",
776
+ pWiki->zWikiTitle,
777
+ wiki_page_type_name(pWiki->zWikiTitle),
778
+ zUuid,
779
+ pWiki->zMimetype ? pWiki->zMimetype : "text/x-fossil-wiki");
780
+ CX("\"parent\": ");
781
+ if(pWiki->nParent){
782
+ CX("%!j", pWiki->azParent[0]);
783
+ }else{
784
+ CX("null");
785
+ }
786
+ if(!pWiki->zWiki || !pWiki->zWiki[0]){
787
+ CX(", \"isEmpty\": true");
788
+ }
789
+ if(includeContent){
790
+ CX(", \"content\": %!j", pWiki->zWiki);
791
+ }
792
+ CX("}");
793
+ fossil_free(zUuid);
794
+ manifest_destroy(pWiki);
795
+ return 2;
796
+ }
797
+}
798
+
799
+/*
800
+** Ajax route handler for /wikiajax/save.
801
+**
802
+** URL params:
803
+**
804
+** page = the wiki page name.
805
+** mimetype = content mime type.
806
+** content = page content. Fossil considers an empty page to
807
+** be "deleted".
808
+** isnew = 1 if the page is to be newly-created, else 0 or
809
+** not send.
810
+**
811
+** Responds with JSON. On error, an object in the form documented by
812
+** ajax_route_error(). On success, an object in the form documented
813
+** for wiki_ajax_emit_page_object().
814
+**
815
+** The wikiajax API disallows saving of a sandbox pseudo-page, and
816
+** will respond with an error if asked to save one. Should we want to
817
+** enable it, it's implemented like this for any saved page for which
818
+** is_sandbox(zPageName) is true:
819
+**
820
+** db_set("sandbox",zBody,0);
821
+** db_set("sandbox-mimetype",zMimetype,0);
822
+**
823
+*/
824
+static void wiki_ajax_route_save(void){
825
+ const char *zPageName = P("page");
826
+ const char *zMimetype = P("mimetype");
827
+ const char *zContent = P("content");
828
+ const int isNew = ajax_p_bool("isnew");
829
+ Blob content = empty_blob;
830
+ int parentRid = 0;
831
+ int rollback = 0;
832
+
833
+ if(!wiki_ajax_can_write(zPageName, &parentRid)){
834
+ return;
835
+ }else if(is_sandbox(zPageName)){
836
+ ajax_route_error(403,"Saving a sandbox page is prohibited.");
837
+ return;
838
+ }
839
+ /* These isNew checks are just me being pedantic. We could just as
840
+ easily derive isNew based on whether or not the page already
841
+ exists. */
842
+ if(isNew){
843
+ if(parentRid>0){
844
+ ajax_route_error(403,"Requested a new page, "
845
+ "but it already exists with RID %d: %s",
846
+ parentRid, zPageName);
847
+ return;
848
+ }
849
+ }else if(parentRid==0){
850
+ ajax_route_error(403,"Creating new page [%s] requires passing "
851
+ "isnew=1.", zPageName);
852
+ return;
853
+ }
854
+ blob_init(&content, zContent ? zContent : "", -1);
855
+ cgi_set_content_type("application/json");
856
+ db_begin_transaction();
857
+ wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0);
858
+ rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1;
859
+ db_end_transaction(rollback);
860
+}
861
+
862
+/*
863
+** Ajax route handler for /wikiajax/fetch.
864
+**
865
+** URL params:
866
+**
867
+** page = the wiki page name
868
+**
869
+** Responds with JSON. On error, an object in the form documented by
870
+** ajax_route_error(). On success, an object in the form documented
871
+** for wiki_ajax_emit_page_object().
872
+*/
873
+static void wiki_ajax_route_fetch(void){
874
+ const char * zPageName = P("page");
875
+
876
+ if( zPageName==0 || zPageName[0]==0 ){
877
+ ajax_route_error(400,"Missing page name.");
878
+ return;
879
+ }
880
+ cgi_set_content_type("application/json");
881
+ wiki_ajax_emit_page_object(zPageName, 1);
882
+}
883
+
884
+/*
885
+** Ajax route handler for /wikiajax/diff.
886
+**
887
+** URL params:
888
+**
889
+** page = the wiki page name
890
+** content = the new/edited wiki page content
891
+**
892
+** Requires that the user have write access solely to avoid some
893
+** potential abuse cases. It does not actually write anything.
894
+*/
895
+static void wiki_ajax_route_diff(void){
896
+ const char * zPageName = P("page");
897
+ Blob contentNew = empty_blob, contentOrig = empty_blob;
898
+ Manifest * pParent = 0;
899
+ const char * zContent = P("content");
900
+ u64 diffFlags = DIFF_HTML | DIFF_NOTTOOBIG | DIFF_STRIP_EOLCR;
901
+
902
+ if( zPageName==0 || zPageName[0]==0 ){
903
+ ajax_route_error(400,"Missing page name.");
904
+ return;
905
+ }else if(!wiki_ajax_can_write(zPageName, 0)){
906
+ return;
907
+ }
908
+ switch(atoi(PD("sbs","0"))){
909
+ case 0: diffFlags |= DIFF_LINENO; break;
910
+ default: diffFlags |= DIFF_SIDEBYSIDE;
911
+ }
912
+ switch(atoi(PD("ws","2"))){
913
+ case 1: diffFlags |= DIFF_IGNORE_EOLWS; break;
914
+ case 2: diffFlags |= DIFF_IGNORE_ALLWS; break;
915
+ default: break;
916
+ }
917
+ wiki_fetch_by_name( zPageName, 0, 0, &pParent );
918
+ if( pParent && pParent->zWiki && *pParent->zWiki ){
919
+ blob_init(&contentOrig, pParent->zWiki, -1);
920
+ }else{
921
+ blob_init(&contentOrig, "", 0);
922
+ }
923
+ blob_init(&contentNew, zContent ? zContent : "", -1);
924
+ cgi_set_content_type("text/html");
925
+ ajax_render_diff(&contentOrig, &contentNew, diffFlags);
926
+ blob_reset(&contentNew);
927
+ blob_reset(&contentOrig);
928
+ manifest_destroy(pParent);
929
+}
930
+
931
+/*
932
+** Ajax route handler for /wikiajax/preview.
933
+**
934
+** URL params:
935
+**
936
+** page = wiki page name. This is only needed for authorization
937
+** checking.
938
+** mimetype = the wiki page mimetype (determines rendering style)
939
+** content = the wiki page content
940
+*/
941
+static void wiki_ajax_route_preview(void){
942
+ const char * zPageName = P("page");
943
+ const char * zContent = P("content");
944
+
945
+ if(!wiki_ajax_can_write(zPageName, 0)){
946
+ return;
947
+ }else if( zContent==0 ){
948
+ ajax_route_error(400,"Missing content to preview.");
949
+ return;
950
+ }else{
951
+ Blob content = empty_blob;
952
+ const char * zMimetype = PD("mimetype","text/x-fossil-wiki");
953
+
954
+ blob_init(&content, zContent, -1);
955
+ cgi_set_content_type("text/html");
956
+ wiki_render_by_mimetype(&content, zMimetype);
957
+ blob_reset(&content);
958
+ }
959
+}
960
+
961
+/*
962
+** Outputs the wiki page list in JSON form. If verbose is false then
963
+** it emits an array of strings (page names). If verbose is true it outputs
964
+** an array of objects in this form:
965
+**
966
+** { name: string, version: string or null of sandbox box,
967
+** parent: uuid or null for first version or sandbox,
968
+** mimetype: string,
969
+** type: string (normal, branch, tag, checkin, or sandbox)
970
+** }
971
+**
972
+** If includeContent is true, the object contains a "content" member
973
+** with the raw page content. includeContent is ignored if verbose is
974
+** false.
975
+**
976
+*/
977
+static void wiki_render_page_list_json(int verbose, int includeContent){
978
+ Stmt q = empty_Stmt;
979
+ int n = 0;
980
+ db_begin_transaction();
981
+ db_prepare(&q, "SELECT"
982
+ " substr(tagname,6) AS name"
983
+ " FROM tag WHERE tagname GLOB 'wiki-*'"
984
+ " UNION SELECT 'Sandbox' AS name"
985
+ " ORDER BY name COLLATE NOCASE");
986
+ CX("[");
987
+ while( SQLITE_ROW==db_step(&q) ){
988
+ char const * zName = db_column_text(&q,0);
989
+ if(n++){
990
+ CX(",");
991
+ }
992
+ if(verbose==0){
993
+ CX("%!j", zName);
994
+ }else{
995
+ wiki_ajax_emit_page_object(zName, includeContent);
996
+ }
997
+ }
998
+ CX("]");
999
+ db_finalize(&q);
1000
+ db_end_transaction(0);
1001
+}
1002
+
1003
+/*
1004
+** Ajax route handler for /wikiajax/list.
1005
+**
1006
+** Optional parameters: verbose, includeContent (see below).
1007
+**
1008
+** Responds with JSON. On error, an object in the form documented by
1009
+** ajax_route_error().
1010
+**
1011
+** On success, it emits an array of strings (page names) sorted
1012
+** case-insensitively. If the "verbose" parameter is passed in then
1013
+** the result list contains objects in the format documented for
1014
+** wiki_ajax_emit_page_object(). The content of each object is elided
1015
+** unless the "includeContent" parameter is passed on with a
1016
+** "non-false" value..
1017
+**
1018
+** The result list always contains an entry named "Sandbox" which
1019
+** represents the sandbox pseudo-page.
1020
+*/
1021
+static void wiki_ajax_route_list(void){
1022
+ const int verbose = ajax_p_bool("verbose");
1023
+ const int includeContent = ajax_p_bool("includeContent");
1024
+
1025
+ cgi_set_content_type("application/json");
1026
+ wiki_render_page_list_json(verbose, includeContent);
1027
+}
1028
+
1029
+/*
1030
+** WEBPAGE: wikiajax
1031
+**
1032
+** An internal dispatcher for wiki AJAX operations. Not for direct
1033
+** client use. All routes defined by this interface are app-internal,
1034
+** subject to change
1035
+*/
1036
+void wiki_ajax_page(void){
1037
+ const char * zName = P("name");
1038
+ AjaxRoute routeName = {0,0,0,0};
1039
+ const AjaxRoute * pRoute = 0;
1040
+ const AjaxRoute routes[] = {
1041
+ /* Keep these sorted by zName (for bsearch()) */
1042
+ {"diff", wiki_ajax_route_diff, 1, 1},
1043
+ {"fetch", wiki_ajax_route_fetch, 0, 0},
1044
+ {"list", wiki_ajax_route_list, 0, 0},
1045
+ {"preview", wiki_ajax_route_preview, 0, 1}
1046
+ /* preview access mode: whether or not wiki-write mode is needed
1047
+ really depends on multiple factors. e.g. the sandbox page does
1048
+ not normally require more than anonymous access. We set its
1049
+ write-mode to false and do those checks manually in that route's
1050
+ handler.
1051
+ */,
1052
+ {"save", wiki_ajax_route_save, 1, 1}
1053
+ };
1054
+
1055
+ if(zName==0 || zName[0]==0){
1056
+ ajax_route_error(400,"Missing required [route] 'name' parameter.");
1057
+ return;
1058
+ }
1059
+ routeName.zName = zName;
1060
+ pRoute = (const AjaxRoute *)bsearch(&routeName, routes,
1061
+ count(routes), sizeof routes[0],
1062
+ cmp_ajax_route_name);
1063
+ if(pRoute==0){
1064
+ ajax_route_error(404,"Ajax route not found.");
1065
+ return;
1066
+ }
1067
+ login_check_credentials();
1068
+ if( pRoute->bWriteMode!=0 && g.perm.WrWiki==0 ){
1069
+ ajax_route_error(403,"Write permissions required.");
1070
+ return;
1071
+ }else if(0==cgi_csrf_safe(pRoute->bPost)){
1072
+ ajax_route_error(403,
1073
+ "CSRF violation (make sure sending of HTTP "
1074
+ "Referer headers is enabled for XHR "
1075
+ "connections).");
1076
+ return;
1077
+ }
1078
+ pRoute->xCallback();
1079
+}
6251080
6261081
/*
6271082
** WEBPAGE: wikiedit
628
-** URL: /wikiedit?name=PAGENAME
1083
+** URL: /wikedit?name=PAGENAME
1084
+**
1085
+** The main front-end for the Ajax-based wiki editor app. Passing
1086
+** in the name of an unknown page will trigger the creation
1087
+** of a new page (which is not actually created in the database
1088
+** until the user explicitly saves it). If passed no page name,
1089
+** the user may select a page from the list on the first UI tab.
6291090
**
630
-** Edit a wiki page.
1091
+** When creating a new page, the mimetype URL parameter may optionally
1092
+** be used to set its mimetype to one of text/x-fossil-wiki,
1093
+** text/x-markdown, or text/plain, defauling to the former.
6311094
*/
6321095
void wikiedit_page(void){
633
- char *zTag;
634
- int rid = 0;
1096
+ const char *zPageName;
1097
+ const char * zMimetype = P("mimetype");
6351098
int isSandbox;
636
- Blob wiki;
637
- Manifest *pWiki = 0;
638
- const char *zPageName;
639
- int n;
640
- const char *z;
641
- char *zBody = (char*)P("w");
642
- const char *zMimetype = wiki_filter_mimetypes(P("mimetype"));
643
- int isWysiwyg = P("wysiwyg")!=0;
644
- int goodCaptcha = 1;
645
- int eType = WIKITYPE_UNKNOWN;
646
- int havePreview = 0;
647
-
648
- if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
649
- if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
650
- if( zBody ){
651
- if( isWysiwyg ){
652
- Blob body;
653
- blob_zero(&body);
654
- htmlTidy(zBody, &body);
655
- zBody = blob_str(&body);
656
- }else{
657
- zBody = mprintf("%s", zBody);
658
- }
659
- }
1099
+ int found = 0;
1100
+
6601101
login_check_credentials();
6611102
zPageName = PD("name","");
662
- if( check_name(zPageName) ) return;
1103
+ if(zPageName && *zPageName){
1104
+ if( check_name(zPageName) ) return;
1105
+ }
6631106
isSandbox = is_sandbox(zPageName);
6641107
if( isSandbox ){
6651108
if( !g.perm.WrWiki ){
6661109
login_needed(g.anon.WrWiki);
6671110
return;
6681111
}
669
- if( zBody==0 ){
670
- zBody = db_get("sandbox","");
671
- zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
672
- }
673
- }else{
674
- zTag = mprintf("wiki-%s", zPageName);
675
- rid = db_int(0,
676
- "SELECT rid FROM tagxref"
677
- " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
678
- " ORDER BY mtime DESC", zTag
679
- );
680
- free(zTag);
1112
+ found = 1;
1113
+ }else if( zPageName!=0 ){
1114
+ int rid = 0;
6811115
if( !wiki_special_permission(zPageName) ){
6821116
login_needed(0);
6831117
return;
6841118
}
1119
+ found = wiki_fetch_by_name(zPageName, 0, &rid, 0);
6851120
if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
6861121
login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki);
6871122
return;
6881123
}
689
- if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
690
- zBody = pWiki->zWiki;
691
- zMimetype = pWiki->zMimetype;
692
- }
693
- }
694
- if( P("submit")!=0 && zBody!=0
695
- && (goodCaptcha = captcha_is_correct(0))
696
- ){
697
- char *zDate;
698
- Blob cksum;
699
- blob_zero(&wiki);
700
- db_begin_transaction();
701
- if( isSandbox ){
702
- db_set("sandbox",zBody,0);
703
- db_set("sandbox-mimetype",zMimetype,0);
704
- }else{
705
- login_verify_csrf_secret();
706
- zDate = date_in_standard_format("now");
707
- blob_appendf(&wiki, "D %s\n", zDate);
708
- free(zDate);
709
- blob_appendf(&wiki, "L %F\n", zPageName);
710
- if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
711
- blob_appendf(&wiki, "N %s\n", zMimetype);
712
- }
713
- if( rid ){
714
- char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
715
- blob_appendf(&wiki, "P %s\n", zUuid);
716
- free(zUuid);
717
- }
718
- if( !login_is_nobody() ){
719
- blob_appendf(&wiki, "U %F\n", login_name());
720
- }
721
- blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody);
722
- md5sum_blob(&wiki, &cksum);
723
- blob_appendf(&wiki, "Z %b\n", &cksum);
724
- blob_reset(&cksum);
725
- wiki_put(&wiki, 0, wiki_need_moderation(0));
726
- }
727
- db_end_transaction(0);
728
- cgi_redirectf("wiki?name=%T", zPageName);
729
- }
730
- if( P("cancel")!=0 ){
731
- cgi_redirectf("wiki?name=%T", zPageName);
732
- return;
733
- }
734
- if( zBody==0 ){
735
- zBody = mprintf("");
736
- }
737
- style_set_current_page("%T?name=%T", g.zPath, zPageName);
738
- eType = wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "Edit: ");
739
- if( rid && !isSandbox && g.perm.ApndWiki ){
740
- if( g.perm.Attach ){
741
- style_submenu_element("Attach",
742
- "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
743
- g.zTop, zPageName, g.zTop, zPageName);
744
- }
745
- }
746
- if( !goodCaptcha ){
747
- @ <p class="generalError">Error: Incorrect security code.</p>
748
- }
749
- blob_zero(&wiki);
750
- while( fossil_isspace(zBody[0]) ) zBody++;
751
- blob_append(&wiki, zBody, -1);
752
- if( P("preview")!=0 ){
753
- havePreview = 1;
754
- if( zBody[0] ){
755
- @ Preview:<hr />
756
- safe_html_context(DOCSRC_WIKI);
757
- wiki_render_by_mimetype(&wiki, zMimetype);
758
- @ <hr />
759
- blob_reset(&wiki);
760
- }
761
- }
762
- for(n=2, z=zBody; z[0]; z++){
763
- if( z[0]=='\n' ) n++;
764
- }
765
- if( n<20 ) n = 20;
766
- if( n>30 ) n = 30;
767
- if( !isWysiwyg ){
768
- /* Traditional markup-only editing */
769
- char *zPlaceholder = 0;
770
- switch( eType ){
771
- case WIKITYPE_NORMAL: {
772
- zPlaceholder = mprintf("Enter text for wiki page %s", zPageName);
773
- break;
774
- }
775
- case WIKITYPE_BRANCH: {
776
- zPlaceholder = mprintf("Enter notes about branch %s", zPageName+7);
777
- break;
778
- }
779
- case WIKITYPE_CHECKIN: {
780
- zPlaceholder = mprintf("Enter notes about check-in %.20s", zPageName+8);
781
- break;
782
- }
783
- case WIKITYPE_TAG: {
784
- zPlaceholder = mprintf("Enter notes about tag %s", zPageName+4);
785
- break;
786
- }
787
- }
788
- form_begin(0, "%R/wikiedit");
789
- @ <div>%z(href("%R/markup_help"))Markup style</a>:
790
- mimetype_option_menu(zMimetype);
791
- @ <br /><textarea name="w" class="wikiedit" cols="80" \
792
- @ rows="%d(n)" wrap="virtual" placeholder="%h(zPlaceholder)">\
793
- @ %h(zBody)</textarea>
794
- @ <br />
795
- fossil_free(zPlaceholder);
796
- if( db_get_boolean("wysiwyg-wiki", 0) ){
797
- @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
798
- @ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' />
799
- }
800
- @ <input type="submit" name="preview" value="Preview Your Changes" />
801
- }else{
802
- /* Wysiwyg editing */
803
- Blob html, temp;
804
- havePreview = 1;
805
- form_begin("", "%R/wikiedit");
806
- @ <div>
807
- @ <input type="hidden" name="wysiwyg" value="1" />
808
- blob_zero(&temp);
809
- wiki_convert(&wiki, &temp, 0);
810
- blob_zero(&html);
811
- htmlTidy(blob_str(&temp), &html);
812
- blob_reset(&temp);
813
- wysiwygEditor("w", blob_str(&html), 60, n);
814
- blob_reset(&html);
815
- @ <br />
816
- @ <input type="submit" name="edit-markup" value="Markup Editor"
817
- @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' />
818
- }
819
- login_insert_csrf_secret();
820
- if( havePreview ){
821
- if( isWysiwyg || zBody[0] ){
822
- @ <input type="submit" name="submit" value="Apply These Changes" />
823
- }else{
824
- @ <input type="submit" name="submit" value="Delete This Wiki Page" />
825
- }
826
- }
827
- @ <input type="hidden" name="name" value="%h(zPageName)" />
828
- @ <input type="submit" name="cancel" value="Cancel"
829
- @ onclick='confirm("Abandon your changes?")' />
830
- @ </div>
831
- captcha_generate(0);
832
- @ </form>
833
- manifest_destroy(pWiki);
834
- blob_reset(&wiki);
1124
+ }
1125
+ style_header("Wiki Editor");
1126
+
1127
+ /* Status bar */
1128
+ CX("<div id='fossil-status-bar' "
1129
+ "title='Status message area. Double-click to clear them.'>"
1130
+ "Status messages will go here.</div>\n"
1131
+ /* will be moved into the tab container via JS */);
1132
+
1133
+ CX("<div id='wikiedit-edit-status''>"
1134
+ "<span class='name'></span>"
1135
+ "<span class='links'></span>"
1136
+ "</div>");
1137
+
1138
+ /* Main tab container... */
1139
+ CX("<div id='wikiedit-tabs' class='tab-container'>Loading...</div>");
1140
+ /* The .hidden class on the following tab elements is to help lessen
1141
+ the FOUC effect of the tabs before JS re-assembles them. */
1142
+
1143
+ /******* Page list *******/
1144
+ {
1145
+ CX("<div id='wikiedit-tab-pages' "
1146
+ "data-tab-parent='wikiedit-tabs' "
1147
+ "data-tab-label='Wiki Page List' "
1148
+ "class='hidden'"
1149
+ ">");
1150
+ CX("<div>Loading wiki pages list...</div>");
1151
+ CX("</div>"/*#wikiedit-tab-pages*/);
1152
+ }
1153
+
1154
+ /******* Content tab *******/
1155
+ {
1156
+ CX("<div id='wikiedit-tab-content' "
1157
+ "data-tab-parent='wikiedit-tabs' "
1158
+ "data-tab-label='Editor' "
1159
+ "class='hidden'"
1160
+ ">");
1161
+ CX("<div class='flex-container flex-row child-gap-small'>");
1162
+ CX("<span class='input-with-label'>"
1163
+ "<label>Mime type</label>");
1164
+ mimetype_option_menu(0);
1165
+ CX("</span>");
1166
+ style_select_list_int("select-font-size",
1167
+ "editor_font_size", "Editor font size",
1168
+ NULL/*tooltip*/,
1169
+ 100,
1170
+ "100%", 100, "125%", 125,
1171
+ "150%", 150, "175%", 175,
1172
+ "200%", 200, NULL);
1173
+ CX("<button class='wikiedit-save'>"
1174
+ "Save</button>"
1175
+ /*will get moved around dynamically*/);
1176
+ CX("<button class='wikiedit-save-close'>"
1177
+ "Save &amp; Close</button>"/*will get moved around dynamically*/);
1178
+ CX("<span class='save-button-slot'></span>");
1179
+ CX("<button class='wikiedit-content-reload' "
1180
+ "title='Reload the file from the server, discarding "
1181
+ "any local edits. To help avoid accidental loss of "
1182
+ "edits, it requires confirmation (a second click) within "
1183
+ "a few seconds or it will not reload.'"
1184
+ ">Discard &amp; Reload</button>");
1185
+ CX("</div>");
1186
+ CX("<div class='flex-container flex-column stretch'>");
1187
+ CX("<textarea name='content' id='wikiedit-content-editor' "
1188
+ "class='wikiedit' rows='25'>");
1189
+ CX("</textarea>");
1190
+ CX("</div>"/*textarea wrapper*/);
1191
+ CX("</div>"/*#tab-file-content*/);
1192
+ }
1193
+ /****** Preview tab ******/
1194
+ {
1195
+ CX("<div id='wikiedit-tab-preview' "
1196
+ "data-tab-parent='wikiedit-tabs' "
1197
+ "data-tab-label='Preview' "
1198
+ "class='hidden'"
1199
+ ">");
1200
+ CX("<div class='wikiedit-options flex-container "
1201
+ "flex-row child-gap-small'>");
1202
+ CX("<button id='btn-preview-refresh' "
1203
+ "data-f-preview-from='wikiContent' "
1204
+ /* ^^^ fossil.page[methodName]() OR text source elem ID,
1205
+ ** but we need a method in order to support clients swapping out
1206
+ ** the text editor with their own. */
1207
+ "data-f-preview-via='_postPreview' "
1208
+ /* ^^^ fossil.page[methodName](content, callback) */
1209
+ "data-f-preview-to='#wikiedit-tab-preview-wrapper' "
1210
+ /* ^^^ dest elem ID */
1211
+ ">Refresh</button>");
1212
+ /* Toggle auto-update of preview when the Preview tab is selected. */
1213
+ style_labeled_checkbox("cb-preview-autoupdate",
1214
+ NULL,
1215
+ "Auto-refresh?",
1216
+ "1", 1,
1217
+ "If on, the preview will automatically "
1218
+ "refresh when this tab is selected.");
1219
+ CX("<span class='save-button-slot'></span>");
1220
+ CX("</div>"/*.wikiedit-options*/);
1221
+ CX("<div id='wikiedit-tab-preview-wrapper'></div>");
1222
+ CX("</div>"/*#wikiedit-tab-preview*/);
1223
+ }
1224
+
1225
+ /****** Diff tab ******/
1226
+ {
1227
+ CX("<div id='wikiedit-tab-diff' "
1228
+ "data-tab-parent='wikiedit-tabs' "
1229
+ "data-tab-label='Diff' "
1230
+ "class='hidden'"
1231
+ ">");
1232
+
1233
+ CX("<div class='wikiedit-options flex-container "
1234
+ "flex-row child-gap-small' "
1235
+ "id='wikiedit-tab-diff-buttons'>");
1236
+ CX("<button class='sbs'>Side-by-side</button>"
1237
+ "<button class='unified'>Unified</button>");
1238
+ CX("<span class='save-button-slot'></span>");
1239
+ CX("</div>");
1240
+ CX("<div id='wikiedit-tab-diff-wrapper'>"
1241
+ "Diffs will be shown here."
1242
+ "</div>");
1243
+ CX("</div>"/*#wikiedit-tab-diff*/);
1244
+ }
1245
+
1246
+ /****** The obligatory "Misc" tab ******/
1247
+ {
1248
+ CX("<div id='wikiedit-tab-misc' "
1249
+ "data-tab-parent='wikiedit-tabs' "
1250
+ "data-tab-label='Help' "
1251
+ "class='hidden'"
1252
+ ">");
1253
+ CX("<h2>Wiki formatting rules</h2>");
1254
+ CX("<ul>");
1255
+ CX("<li><a href='%R/wiki_rules'>Fossil wiki format</a></li>");
1256
+ CX("<li><a href='%R/md_rules'>Markdown format</a></li>");
1257
+ CX("<li>Plain-text pages use no special formatting.</li>");
1258
+ CX("</ul>");
1259
+ CX("<h2>The \"Sandbox\" Page</h2>");
1260
+ CX("<p>The page named \"Sandbox\" is not a real wiki page. "
1261
+ "It provides a place where users may test out wiki syntax "
1262
+ "without having to actually save anything, nor pollute "
1263
+ "the repo with endless test runs. Any attempt to save the "
1264
+ "sandbox page will fail.</p>");
1265
+ CX("<h2>Wiki Name Rules</h2>");
1266
+ well_formed_wiki_name_rules();
1267
+ CX("</div>"/*#wikiedit-tab-save*/);
1268
+ }
1269
+
1270
+ builtin_request_js("sbsdiff.js");
1271
+ style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1272
+ "storage", "page.wikiedit", 0);
1273
+ builtin_fulfill_js_requests();
1274
+ /* Dynamically populate the editor... */
1275
+ style_emit_script_tag(0,0);
1276
+ {
1277
+ /* Render the current page list to save us an XHR request
1278
+ during page initialization. This must be OUTSIDE of
1279
+ an onPageLoad() handler or else it does not get applied
1280
+ until after the wiki list widget is initialized. Similarly,
1281
+ it must come *after* window.fossil is initialized. */
1282
+ CX("\nfossil.page.initialPageList = ");
1283
+ wiki_render_page_list_json(1, 0);
1284
+ CX(";\n");
1285
+ }
1286
+ CX("fossil.onPageLoad(function(){\n");
1287
+ CX("const P = fossil.page;\n"
1288
+ "try{\n");
1289
+ if(!found && zPageName && *zPageName){
1290
+ /* For a new page, stick a dummy entry in the JS-side stash
1291
+ and "load" it from there. */
1292
+ CX("const winfo = {"
1293
+ "\"name\": %!j, \"mimetype\": %!j, "
1294
+ "\"type\": %!j, "
1295
+ "\"parent\": null, \"version\": null"
1296
+ "};\n",
1297
+ zPageName,
1298
+ zMimetype ? zMimetype : "text/x-fossil-wiki",
1299
+ wiki_page_type_name(zPageName));
1300
+ /* If the JS-side stash already has this page, load that
1301
+ copy from the stash, otherwise inject a new stash entry
1302
+ for it and load *that* one... */
1303
+ CX("if(!P.$stash.getWinfo(winfo)){"
1304
+ "P.$stash.updateWinfo(winfo,'');"
1305
+ "}\n");
1306
+ }
1307
+ if(zPageName && *zPageName){
1308
+ CX("P.loadPage(%!j);\n", zPageName);
1309
+ }
1310
+ CX("}catch(e){"
1311
+ "fossil.error(e); console.error('Exception:',e);"
1312
+ "}\n");
1313
+ CX("});\n"/*fossil.onPageLoad()*/);
1314
+ style_emit_script_tag(1,0);
8351315
style_footer();
8361316
}
8371317
8381318
/*
8391319
** WEBPAGE: wikinew
@@ -851,17 +1331,11 @@
8511331
return;
8521332
}
8531333
zName = PD("name","");
8541334
zMimetype = wiki_filter_mimetypes(P("mimetype"));
8551335
if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
856
- if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0
857
- && db_get_boolean("wysiwyg-wiki", 0)
858
- ){
859
- cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName);
860
- }else{
861
- cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype);
862
- }
1336
+ cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype);
8631337
}
8641338
style_header("Create A New Wiki Page");
8651339
wiki_standard_submenu(W_ALL_BUT(W_NEW));
8661340
@ <p>Rules for wiki page names:</p>
8671341
well_formed_wiki_name_rules();
@@ -1441,11 +1915,11 @@
14411915
** -M|--mimetype TEXT-FORMAT The mime type of the update.
14421916
** Defaults to the type used by
14431917
** the previous version of the
14441918
** page, or text/x-fossil-wiki.
14451919
** Valid values are: text/x-fossil-wiki,
1446
-** text/markdown and text/plain. fossil,
1920
+** text/x-markdown and text/plain. fossil,
14471921
** markdown or plain can be specified as
14481922
** synonyms of these values.
14491923
** -t|--technote DATETIME Specifies the timestamp of
14501924
** the technote to be created or
14511925
** updated. When updating a tech note
@@ -1479,13 +1953,18 @@
14791953
** year-month-day form, it may be truncated, the "T" may be replaced by
14801954
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
14811955
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
14821956
** means UTC.
14831957
**
1958
+** The "Sandbox" wiki pseudo-page is a special case. Its name is
1959
+** checked case-insensitively and either "create" or "commit" may be
1960
+** used to update its contents.
14841961
*/
14851962
void wiki_cmd(void){
14861963
int n;
1964
+ int isSandbox = 0; /* true if dealing with sandbox pseudo-page */
1965
+
14871966
db_find_and_open_repository(0, 0);
14881967
if( g.argc<3 ){
14891968
goto wiki_cmd_usage;
14901969
}
14911970
n = strlen(g.argv[2]);
@@ -1492,14 +1971,14 @@
14921971
if( n==0 ){
14931972
goto wiki_cmd_usage;
14941973
}
14951974
14961975
if( strncmp(g.argv[2],"export",n)==0 ){
1497
- const char *zPageName; /* Name of the wiki page to export */
1976
+ const char *zPageName = 0; /* Name of the wiki page to export */
14981977
const char *zFile; /* Name of the output file (0=stdout) */
14991978
const char *zETime; /* The name of the technote to export */
1500
- int rid; /* Artifact ID of the wiki page */
1979
+ int rid = 0; /* Artifact ID of the wiki page */
15011980
int i; /* Loop counter */
15021981
char *zBody = 0; /* Wiki page content */
15031982
Blob body = empty_blob; /* Wiki page content */
15041983
Manifest *pWiki = 0; /* Parsed wiki page content */
15051984
int fHtml = 0; /* Export in HTML form */
@@ -1517,17 +1996,18 @@
15171996
if( !zETime ){
15181997
if( (g.argc!=4) && (g.argc!=5) ){
15191998
usage("export ?-html? PAGENAME ?FILE?");
15201999
}
15212000
zPageName = g.argv[3];
1522
- rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1523
- " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1524
- " ORDER BY x.mtime DESC LIMIT 1",
1525
- zPageName
1526
- );
1527
- if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
1528
- zBody = pWiki->zWiki;
2001
+ isSandbox = is_sandbox(zPageName);
2002
+ if(isSandbox){
2003
+ zBody = db_get("sandbox", 0);
2004
+ }else{
2005
+ wiki_fetch_by_name(zPageName, 0, &rid, &pWiki);
2006
+ if(pWiki){
2007
+ zBody = pWiki->zWiki;
2008
+ }
15292009
}
15302010
if( zBody==0 ){
15312011
fossil_fatal("wiki page [%s] not found",zPageName);
15322012
}
15332013
zFile = (g.argc==4) ? "-" : g.argv[4];
@@ -1553,30 +2033,24 @@
15532033
blob_init(&body, zBody, -1);
15542034
if(fHtml==0){
15552035
blob_append(&body, "\n", 1);
15562036
}else{
15572037
Blob html = empty_blob; /* HTML-ized content */
1558
- const char * zMimetype = wiki_filter_mimetypes(pWiki->zMimetype);
2038
+ const char * zMimetype = isSandbox
2039
+ ? db_get("sandbox-mimetype", "text/x-fossil-wiki")
2040
+ : wiki_filter_mimetypes(pWiki->zMimetype);
15592041
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
15602042
wiki_convert(&body,&html,0);
15612043
}else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
1562
- markdown_to_html(&body,0,&html)
1563
- /* TODO: add -HTML|-H flag to work like -html|-h but also
1564
- ** add <html><body> tag wrappers around the output. The
1565
- ** hurdle here is that the markdown converter resets its
1566
- ** input blob before appending the output, which is
1567
- ** different from wiki_convert() and htmlize_to_blob(), and
1568
- ** precludes us simply appending the opening <html><body>
1569
- ** part to the body
1570
- */;
2044
+ markdown_to_html(&body,0,&html);
15712045
safe_html_context(DOCSRC_WIKI);
15722046
safe_html(&html);
15732047
}else if( fossil_strcmp(zMimetype, "text/plain")==0 ){
15742048
htmlize_to_blob(&html,zBody,i);
15752049
}else{
15762050
fossil_fatal("Unsupported MIME type '%s' for wiki page '%s'.",
1577
- zMimetype, pWiki->zWikiTitle );
2051
+ zMimetype, pWiki ? pWiki->zWikiTitle : zPageName );
15782052
}
15792053
blob_reset(&body);
15802054
body = html /* transfer memory */;
15812055
}
15822056
pFile = fossil_fopen_for_output(zFile);
@@ -1618,28 +2092,28 @@
16182092
if( g.argc==4 ){
16192093
blob_read_from_channel(&content, stdin, -1);
16202094
}else{
16212095
blob_read_from_file(&content, g.argv[4], ExtFILE);
16222096
}
2097
+ isSandbox = is_sandbox(zPageName);
16232098
if ( !zETime ){
1624
- rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1625
- " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1626
- " ORDER BY x.mtime DESC LIMIT 1",
1627
- zPageName
1628
- );
1629
- if( rid>0 ){
1630
- pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
2099
+ if( !isSandbox ){
2100
+ wiki_fetch_by_name(zPageName, 0, &rid, &pWiki);
16312101
}
16322102
}else{
16332103
rid = wiki_technote_to_rid(zETime);
16342104
if( rid>0 ){
16352105
pWiki = manifest_get(rid, CFTYPE_EVENT, 0);
16362106
}
16372107
}
16382108
if( !zMimeType || !*zMimeType ){
16392109
/* Try to deduce the mime type based on the prior version. */
1640
- if( pWiki!=0 && (pWiki->zMimetype && *pWiki->zMimetype) ){
2110
+ if(isSandbox){
2111
+ zMimeType =
2112
+ wiki_filter_mimetypes(db_get("sandbox-mimetype",
2113
+ "text/x-fossil-wiki"));
2114
+ }else if( pWiki!=0 && (pWiki->zMimetype && *pWiki->zMimetype) ){
16412115
zMimeType = pWiki->zMimetype;
16422116
}
16432117
}else{
16442118
zMimeType = wiki_filter_mimetypes(zMimeType);
16452119
}
@@ -1649,24 +2123,30 @@
16492123
}else{
16502124
/* Creating a tech note with same timestamp is permitted
16512125
and should create a new tech note */
16522126
rid = 0;
16532127
}
1654
- }else if( !isCreate && rid == 0 ){
2128
+ }else if( !isCreate && rid==0 && isSandbox==0 ){
16552129
if ( !zETime ){
16562130
fossil_fatal("no such wiki page: %s", zPageName);
16572131
}else{
16582132
fossil_fatal("no such tech note: %s", zETime);
16592133
}
16602134
}
16612135
16622136
if( !zETime ){
1663
- wiki_cmd_commit(zPageName, rid, &content, zMimeType, 1);
1664
- if( g.argv[2][1]=='r' ){
1665
- fossil_print("Created new wiki page %s.\n", zPageName);
2137
+ if(isSandbox){
2138
+ db_set("sandbox",blob_str(&content),0);
2139
+ db_set("sandbox-mimetype",zMimeType,0);
2140
+ fossil_print("Updated sandbox pseudo-page.\n");
16662141
}else{
1667
- fossil_print("Updated wiki page %s.\n", zPageName);
2142
+ wiki_cmd_commit(zPageName, rid, &content, zMimeType, 1);
2143
+ if( g.argv[2][1]=='r' ){
2144
+ fossil_print("Created new wiki page %s.\n", zPageName);
2145
+ }else{
2146
+ fossil_print("Updated wiki page %s.\n", zPageName);
2147
+ }
16682148
}
16692149
}else{
16702150
if( rid != -1 ){
16712151
char *zMETime; /* Normalized, mutable version of zETime */
16722152
zMETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))",
@@ -1844,8 +2324,8 @@
18442324
blob_reset(&tail);
18452325
blob_reset(&title);
18462326
blob_reset(&wiki);
18472327
}
18482328
manifest_destroy(pWiki);
1849
- style_accordion();
2329
+ builtin_request_js("accordion.js");
18502330
return 1;
18512331
}
18522332
18532333
DELETED src/wysiwyg.c
--- src/wiki.c
+++ src/wiki.c
@@ -102,11 +102,10 @@
102 " WHERE tagid=%d AND mtime<%.16g"
103 " ORDER BY mtime DESC LIMIT 1",
104 tagid, mtime);
105 }
106
107
108 /*
109 ** WEBPAGE: home
110 ** WEBPAGE: index
111 ** WEBPAGE: not_found
112 **
@@ -398,10 +397,24 @@
398 if( sqlite3_strglob("tag/*", zPageName)==0 ){
399 return WIKITYPE_TAG;
400 }
401 return WIKITYPE_NORMAL;
402 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
404 /*
405 ** Add an appropriate style_header() for either the /wiki or /wikiedit page
406 ** for zPageName. zExtra is an empty string for /wiki but has the text
407 ** "Edit: " for /wikiedit.
@@ -541,16 +554,11 @@
541 zMimetype = wiki_filter_mimetypes(zMimetype);
542 if( !g.isHome && !noSubmenu ){
543 if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
544 && wiki_special_permission(zPageName)
545 ){
546 if( db_get_boolean("wysiwyg-wiki", 0) ){
547 style_submenu_element("Edit", "%R/wikiedit?name=%T&wysiwyg=1",
548 zPageName);
549 }else{
550 style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
551 }
552 }else if( rid && g.perm.ApndWiki ){
553 style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
554 }
555 if( g.perm.Hyperlink ){
556 style_submenu_element("History", "%R/whistory?name=%T", zPageName);
@@ -620,220 +628,692 @@
620 return azStyles[i+1];
621 }
622 }
623 return azStyles[1];
624 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
625
626 /*
627 ** WEBPAGE: wikiedit
628 ** URL: /wikiedit?name=PAGENAME
 
 
 
 
 
 
629 **
630 ** Edit a wiki page.
 
 
631 */
632 void wikiedit_page(void){
633 char *zTag;
634 int rid = 0;
635 int isSandbox;
636 Blob wiki;
637 Manifest *pWiki = 0;
638 const char *zPageName;
639 int n;
640 const char *z;
641 char *zBody = (char*)P("w");
642 const char *zMimetype = wiki_filter_mimetypes(P("mimetype"));
643 int isWysiwyg = P("wysiwyg")!=0;
644 int goodCaptcha = 1;
645 int eType = WIKITYPE_UNKNOWN;
646 int havePreview = 0;
647
648 if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
649 if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
650 if( zBody ){
651 if( isWysiwyg ){
652 Blob body;
653 blob_zero(&body);
654 htmlTidy(zBody, &body);
655 zBody = blob_str(&body);
656 }else{
657 zBody = mprintf("%s", zBody);
658 }
659 }
660 login_check_credentials();
661 zPageName = PD("name","");
662 if( check_name(zPageName) ) return;
 
 
663 isSandbox = is_sandbox(zPageName);
664 if( isSandbox ){
665 if( !g.perm.WrWiki ){
666 login_needed(g.anon.WrWiki);
667 return;
668 }
669 if( zBody==0 ){
670 zBody = db_get("sandbox","");
671 zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
672 }
673 }else{
674 zTag = mprintf("wiki-%s", zPageName);
675 rid = db_int(0,
676 "SELECT rid FROM tagxref"
677 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
678 " ORDER BY mtime DESC", zTag
679 );
680 free(zTag);
681 if( !wiki_special_permission(zPageName) ){
682 login_needed(0);
683 return;
684 }
 
685 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
686 login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki);
687 return;
688 }
689 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
690 zBody = pWiki->zWiki;
691 zMimetype = pWiki->zMimetype;
692 }
693 }
694 if( P("submit")!=0 && zBody!=0
695 && (goodCaptcha = captcha_is_correct(0))
696 ){
697 char *zDate;
698 Blob cksum;
699 blob_zero(&wiki);
700 db_begin_transaction();
701 if( isSandbox ){
702 db_set("sandbox",zBody,0);
703 db_set("sandbox-mimetype",zMimetype,0);
704 }else{
705 login_verify_csrf_secret();
706 zDate = date_in_standard_format("now");
707 blob_appendf(&wiki, "D %s\n", zDate);
708 free(zDate);
709 blob_appendf(&wiki, "L %F\n", zPageName);
710 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
711 blob_appendf(&wiki, "N %s\n", zMimetype);
712 }
713 if( rid ){
714 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
715 blob_appendf(&wiki, "P %s\n", zUuid);
716 free(zUuid);
717 }
718 if( !login_is_nobody() ){
719 blob_appendf(&wiki, "U %F\n", login_name());
720 }
721 blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody);
722 md5sum_blob(&wiki, &cksum);
723 blob_appendf(&wiki, "Z %b\n", &cksum);
724 blob_reset(&cksum);
725 wiki_put(&wiki, 0, wiki_need_moderation(0));
726 }
727 db_end_transaction(0);
728 cgi_redirectf("wiki?name=%T", zPageName);
729 }
730 if( P("cancel")!=0 ){
731 cgi_redirectf("wiki?name=%T", zPageName);
732 return;
733 }
734 if( zBody==0 ){
735 zBody = mprintf("");
736 }
737 style_set_current_page("%T?name=%T", g.zPath, zPageName);
738 eType = wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "Edit: ");
739 if( rid && !isSandbox && g.perm.ApndWiki ){
740 if( g.perm.Attach ){
741 style_submenu_element("Attach",
742 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
743 g.zTop, zPageName, g.zTop, zPageName);
744 }
745 }
746 if( !goodCaptcha ){
747 @ <p class="generalError">Error: Incorrect security code.</p>
748 }
749 blob_zero(&wiki);
750 while( fossil_isspace(zBody[0]) ) zBody++;
751 blob_append(&wiki, zBody, -1);
752 if( P("preview")!=0 ){
753 havePreview = 1;
754 if( zBody[0] ){
755 @ Preview:<hr />
756 safe_html_context(DOCSRC_WIKI);
757 wiki_render_by_mimetype(&wiki, zMimetype);
758 @ <hr />
759 blob_reset(&wiki);
760 }
761 }
762 for(n=2, z=zBody; z[0]; z++){
763 if( z[0]=='\n' ) n++;
764 }
765 if( n<20 ) n = 20;
766 if( n>30 ) n = 30;
767 if( !isWysiwyg ){
768 /* Traditional markup-only editing */
769 char *zPlaceholder = 0;
770 switch( eType ){
771 case WIKITYPE_NORMAL: {
772 zPlaceholder = mprintf("Enter text for wiki page %s", zPageName);
773 break;
774 }
775 case WIKITYPE_BRANCH: {
776 zPlaceholder = mprintf("Enter notes about branch %s", zPageName+7);
777 break;
778 }
779 case WIKITYPE_CHECKIN: {
780 zPlaceholder = mprintf("Enter notes about check-in %.20s", zPageName+8);
781 break;
782 }
783 case WIKITYPE_TAG: {
784 zPlaceholder = mprintf("Enter notes about tag %s", zPageName+4);
785 break;
786 }
787 }
788 form_begin(0, "%R/wikiedit");
789 @ <div>%z(href("%R/markup_help"))Markup style</a>:
790 mimetype_option_menu(zMimetype);
791 @ <br /><textarea name="w" class="wikiedit" cols="80" \
792 @ rows="%d(n)" wrap="virtual" placeholder="%h(zPlaceholder)">\
793 @ %h(zBody)</textarea>
794 @ <br />
795 fossil_free(zPlaceholder);
796 if( db_get_boolean("wysiwyg-wiki", 0) ){
797 @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
798 @ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' />
799 }
800 @ <input type="submit" name="preview" value="Preview Your Changes" />
801 }else{
802 /* Wysiwyg editing */
803 Blob html, temp;
804 havePreview = 1;
805 form_begin("", "%R/wikiedit");
806 @ <div>
807 @ <input type="hidden" name="wysiwyg" value="1" />
808 blob_zero(&temp);
809 wiki_convert(&wiki, &temp, 0);
810 blob_zero(&html);
811 htmlTidy(blob_str(&temp), &html);
812 blob_reset(&temp);
813 wysiwygEditor("w", blob_str(&html), 60, n);
814 blob_reset(&html);
815 @ <br />
816 @ <input type="submit" name="edit-markup" value="Markup Editor"
817 @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' />
818 }
819 login_insert_csrf_secret();
820 if( havePreview ){
821 if( isWysiwyg || zBody[0] ){
822 @ <input type="submit" name="submit" value="Apply These Changes" />
823 }else{
824 @ <input type="submit" name="submit" value="Delete This Wiki Page" />
825 }
826 }
827 @ <input type="hidden" name="name" value="%h(zPageName)" />
828 @ <input type="submit" name="cancel" value="Cancel"
829 @ onclick='confirm("Abandon your changes?")' />
830 @ </div>
831 captcha_generate(0);
832 @ </form>
833 manifest_destroy(pWiki);
834 blob_reset(&wiki);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835 style_footer();
836 }
837
838 /*
839 ** WEBPAGE: wikinew
@@ -851,17 +1331,11 @@
851 return;
852 }
853 zName = PD("name","");
854 zMimetype = wiki_filter_mimetypes(P("mimetype"));
855 if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
856 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0
857 && db_get_boolean("wysiwyg-wiki", 0)
858 ){
859 cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName);
860 }else{
861 cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype);
862 }
863 }
864 style_header("Create A New Wiki Page");
865 wiki_standard_submenu(W_ALL_BUT(W_NEW));
866 @ <p>Rules for wiki page names:</p>
867 well_formed_wiki_name_rules();
@@ -1441,11 +1915,11 @@
1441 ** -M|--mimetype TEXT-FORMAT The mime type of the update.
1442 ** Defaults to the type used by
1443 ** the previous version of the
1444 ** page, or text/x-fossil-wiki.
1445 ** Valid values are: text/x-fossil-wiki,
1446 ** text/markdown and text/plain. fossil,
1447 ** markdown or plain can be specified as
1448 ** synonyms of these values.
1449 ** -t|--technote DATETIME Specifies the timestamp of
1450 ** the technote to be created or
1451 ** updated. When updating a tech note
@@ -1479,13 +1953,18 @@
1479 ** year-month-day form, it may be truncated, the "T" may be replaced by
1480 ** a space, and it may also name a timezone offset from UTC as "-HH:MM"
1481 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
1482 ** means UTC.
1483 **
 
 
 
1484 */
1485 void wiki_cmd(void){
1486 int n;
 
 
1487 db_find_and_open_repository(0, 0);
1488 if( g.argc<3 ){
1489 goto wiki_cmd_usage;
1490 }
1491 n = strlen(g.argv[2]);
@@ -1492,14 +1971,14 @@
1492 if( n==0 ){
1493 goto wiki_cmd_usage;
1494 }
1495
1496 if( strncmp(g.argv[2],"export",n)==0 ){
1497 const char *zPageName; /* Name of the wiki page to export */
1498 const char *zFile; /* Name of the output file (0=stdout) */
1499 const char *zETime; /* The name of the technote to export */
1500 int rid; /* Artifact ID of the wiki page */
1501 int i; /* Loop counter */
1502 char *zBody = 0; /* Wiki page content */
1503 Blob body = empty_blob; /* Wiki page content */
1504 Manifest *pWiki = 0; /* Parsed wiki page content */
1505 int fHtml = 0; /* Export in HTML form */
@@ -1517,17 +1996,18 @@
1517 if( !zETime ){
1518 if( (g.argc!=4) && (g.argc!=5) ){
1519 usage("export ?-html? PAGENAME ?FILE?");
1520 }
1521 zPageName = g.argv[3];
1522 rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1523 " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1524 " ORDER BY x.mtime DESC LIMIT 1",
1525 zPageName
1526 );
1527 if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
1528 zBody = pWiki->zWiki;
 
1529 }
1530 if( zBody==0 ){
1531 fossil_fatal("wiki page [%s] not found",zPageName);
1532 }
1533 zFile = (g.argc==4) ? "-" : g.argv[4];
@@ -1553,30 +2033,24 @@
1553 blob_init(&body, zBody, -1);
1554 if(fHtml==0){
1555 blob_append(&body, "\n", 1);
1556 }else{
1557 Blob html = empty_blob; /* HTML-ized content */
1558 const char * zMimetype = wiki_filter_mimetypes(pWiki->zMimetype);
 
 
1559 if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
1560 wiki_convert(&body,&html,0);
1561 }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
1562 markdown_to_html(&body,0,&html)
1563 /* TODO: add -HTML|-H flag to work like -html|-h but also
1564 ** add <html><body> tag wrappers around the output. The
1565 ** hurdle here is that the markdown converter resets its
1566 ** input blob before appending the output, which is
1567 ** different from wiki_convert() and htmlize_to_blob(), and
1568 ** precludes us simply appending the opening <html><body>
1569 ** part to the body
1570 */;
1571 safe_html_context(DOCSRC_WIKI);
1572 safe_html(&html);
1573 }else if( fossil_strcmp(zMimetype, "text/plain")==0 ){
1574 htmlize_to_blob(&html,zBody,i);
1575 }else{
1576 fossil_fatal("Unsupported MIME type '%s' for wiki page '%s'.",
1577 zMimetype, pWiki->zWikiTitle );
1578 }
1579 blob_reset(&body);
1580 body = html /* transfer memory */;
1581 }
1582 pFile = fossil_fopen_for_output(zFile);
@@ -1618,28 +2092,28 @@
1618 if( g.argc==4 ){
1619 blob_read_from_channel(&content, stdin, -1);
1620 }else{
1621 blob_read_from_file(&content, g.argv[4], ExtFILE);
1622 }
 
1623 if ( !zETime ){
1624 rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1625 " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1626 " ORDER BY x.mtime DESC LIMIT 1",
1627 zPageName
1628 );
1629 if( rid>0 ){
1630 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
1631 }
1632 }else{
1633 rid = wiki_technote_to_rid(zETime);
1634 if( rid>0 ){
1635 pWiki = manifest_get(rid, CFTYPE_EVENT, 0);
1636 }
1637 }
1638 if( !zMimeType || !*zMimeType ){
1639 /* Try to deduce the mime type based on the prior version. */
1640 if( pWiki!=0 && (pWiki->zMimetype && *pWiki->zMimetype) ){
 
 
 
 
1641 zMimeType = pWiki->zMimetype;
1642 }
1643 }else{
1644 zMimeType = wiki_filter_mimetypes(zMimeType);
1645 }
@@ -1649,24 +2123,30 @@
1649 }else{
1650 /* Creating a tech note with same timestamp is permitted
1651 and should create a new tech note */
1652 rid = 0;
1653 }
1654 }else if( !isCreate && rid == 0 ){
1655 if ( !zETime ){
1656 fossil_fatal("no such wiki page: %s", zPageName);
1657 }else{
1658 fossil_fatal("no such tech note: %s", zETime);
1659 }
1660 }
1661
1662 if( !zETime ){
1663 wiki_cmd_commit(zPageName, rid, &content, zMimeType, 1);
1664 if( g.argv[2][1]=='r' ){
1665 fossil_print("Created new wiki page %s.\n", zPageName);
 
1666 }else{
1667 fossil_print("Updated wiki page %s.\n", zPageName);
 
 
 
 
 
1668 }
1669 }else{
1670 if( rid != -1 ){
1671 char *zMETime; /* Normalized, mutable version of zETime */
1672 zMETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))",
@@ -1844,8 +2324,8 @@
1844 blob_reset(&tail);
1845 blob_reset(&title);
1846 blob_reset(&wiki);
1847 }
1848 manifest_destroy(pWiki);
1849 style_accordion();
1850 return 1;
1851 }
1852
1853 ELETED src/wysiwyg.c
--- src/wiki.c
+++ src/wiki.c
@@ -102,11 +102,10 @@
102 " WHERE tagid=%d AND mtime<%.16g"
103 " ORDER BY mtime DESC LIMIT 1",
104 tagid, mtime);
105 }
106
 
107 /*
108 ** WEBPAGE: home
109 ** WEBPAGE: index
110 ** WEBPAGE: not_found
111 **
@@ -398,10 +397,24 @@
397 if( sqlite3_strglob("tag/*", zPageName)==0 ){
398 return WIKITYPE_TAG;
399 }
400 return WIKITYPE_NORMAL;
401 }
402
403 /*
404 ** Returns a JSON-friendly string form of the integer value returned
405 ** by wiki_page_type(zPageName).
406 */
407 const char * wiki_page_type_name(const char *zPageName){
408 switch(wiki_page_type(zPageName)){
409 case WIKITYPE_CHECKIN: return "checkin";
410 case WIKITYPE_BRANCH: return "branch";
411 case WIKITYPE_TAG: return "tag";
412 case WIKITYPE_NORMAL:
413 default: return "normal";
414 }
415 }
416
417 /*
418 ** Add an appropriate style_header() for either the /wiki or /wikiedit page
419 ** for zPageName. zExtra is an empty string for /wiki but has the text
420 ** "Edit: " for /wikiedit.
@@ -541,16 +554,11 @@
554 zMimetype = wiki_filter_mimetypes(zMimetype);
555 if( !g.isHome && !noSubmenu ){
556 if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
557 && wiki_special_permission(zPageName)
558 ){
559 style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
 
 
 
 
 
560 }else if( rid && g.perm.ApndWiki ){
561 style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
562 }
563 if( g.perm.Hyperlink ){
564 style_submenu_element("History", "%R/whistory?name=%T", zPageName);
@@ -620,220 +628,692 @@
628 return azStyles[i+1];
629 }
630 }
631 return azStyles[1];
632 }
633
634 /*
635 ** Tries to fetch a wiki page for the given name. If found, it
636 ** returns true, else false.
637 **
638 ** versionsBack specifies how many versions back in the history to
639 ** fetch. Use 0 for the latest version, 1 for its parent, etc.
640 **
641 ** If pRid is not NULL then if a result is found *pRid is set to its
642 ** RID. If ppWiki is not NULL then if found *ppWiki is set to the
643 ** loaded wiki object, which the caller is responsible for passing to
644 ** manifest_destroy().
645 */
646 static int wiki_fetch_by_name( const char *zPageName,
647 unsigned int versionsBack,
648 int * pRid, Manifest **ppWiki ){
649 Manifest *pWiki = 0;
650 char *zTag = mprintf("wiki-%s", zPageName);
651 Stmt q = empty_Stmt;
652 int rid = 0;
653
654 db_prepare(&q, "SELECT rid FROM tagxref"
655 " WHERE tagid=(SELECT tagid FROM tag WHERE"
656 " tagname=%Q) "
657 " ORDER BY mtime DESC LIMIT -1 OFFSET %u", zTag,
658 versionsBack);
659 fossil_free(zTag);
660 if(SQLITE_ROW == db_step(&q)){
661 rid = db_column_int(&q, 0);
662 }
663 db_finalize(&q);
664 if( rid == 0 ){
665 return 0;
666 }
667 else if(pRid){
668 *pRid = rid;
669 }
670 if(ppWiki){
671 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
672 if( pWiki==0 ){
673 /* "Cannot happen." */
674 return 0;
675 }
676 *ppWiki = pWiki;
677 }
678 return 1;
679 }
680
681 /*
682 ** Determines whether the wiki page with the given name can be edited
683 ** or created by the current user. If not, an AJAX error is queued and
684 ** false is returned, else true is returned. A NULL, empty, or
685 ** malformed name is considered non-writable, regardless of the user.
686 **
687 ** If pRid is not NULL then this function writes the page's rid to
688 ** *pRid (whether or not access is granted). On error or if the page
689 ** does not yet exist, *pRid will be set to 0.
690 **
691 ** Note that the sandbox is a special case: it is a pseudo-page with
692 ** no rid and the /wikiajax API does not allow anyone to actually save
693 ** a sandbox page, but it is reported as writable here (with rid 0).
694 */
695 static int wiki_ajax_can_write(const char *zPageName, int * pRid){
696 int rid = 0;
697 const char * zErr = 0;
698
699 if(pRid) *pRid = 0;
700 if(!zPageName || !*zPageName
701 || !wiki_name_is_wellformed((unsigned const char *)zPageName)){
702 zErr = "Invalid page name.";
703 }else if(is_sandbox(zPageName)){
704 return 1;
705 }else{
706 wiki_fetch_by_name(zPageName, 0, &rid, 0);
707 if(pRid) *pRid = rid;
708 if(!wiki_special_permission(zPageName)){
709 zErr = "Editing this page requires non-wiki write permissions.";
710 }else if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
711 return 3;
712 }else if(rid && !g.perm.WrWiki){
713 zErr = "Requires wiki-write permissions.";
714 }else if(!rid && !g.perm.NewWiki){
715 zErr = "Requires new-wiki permissions.";
716 }else{
717 zErr = "Cannot happen! Please report this as a bug.";
718 }
719 }
720 ajax_route_error(403, "%s", zErr);
721 return 0;
722 }
723
724 /*
725 ** Loads the given wiki page, sets the response type to
726 ** application/json, and emits it as a JSON object. If zPageName is a
727 ** sandbox page then a "fake" object is emitted, as the wikiajax API
728 ** does not permit saving the sandbox.
729 **
730 ** Returns true on success, false on error, and on error it
731 ** queues up a JSON-format error response.
732 **
733 ** Output JSON format:
734 **
735 ** { name: "page name",
736 ** type: "normal" | "tag" | "checkin" | "branch" | "sandbox",
737 ** mimetype: "mime type",
738 ** version: UUID string or null for a sandbox page,
739 ** parent: "parent uuid" or null if no parent,
740 ** isDeleted: true if the page has no content (is "deleted")
741 ** else not set (making it "falsy" in JS),
742 ** content: "page content" (only if includeContent is true)
743 ** }
744 **
745 ** If includeContent is false then the content member is elided.
746 */
747 static int wiki_ajax_emit_page_object(const char *zPageName,
748 int includeContent){
749 Manifest * pWiki = 0;
750 char * zUuid;
751
752 if( is_sandbox(zPageName) ){
753 char * zMimetype =
754 db_get("sandbox-mimetype","text/x-fossil-wiki");
755 char * zBody = db_get("sandbox","");
756 CX("{\"name\": %!j, \"type\": \"sandbox\", "
757 "\"mimetype\": %!j, \"version\": null, \"parent\": null",
758 zPageName, zMimetype);
759 if(includeContent){
760 CX(", \"content\": %!j",
761 zBody);
762 }
763 CX("}");
764 fossil_free(zMimetype);
765 fossil_free(zBody);
766 return 1;
767 }else if( !wiki_fetch_by_name(zPageName, 0, 0, &pWiki) ){
768 ajax_route_error(404, "Wiki page could not be loaded: %s",
769 zPageName);
770 return 0;
771 }else{
772 zUuid = rid_to_uuid(pWiki->rid);
773 CX("{\"name\": %!j, \"type\": %!j, "
774 "\"version\": %!j, "
775 "\"mimetype\": %!j, ",
776 pWiki->zWikiTitle,
777 wiki_page_type_name(pWiki->zWikiTitle),
778 zUuid,
779 pWiki->zMimetype ? pWiki->zMimetype : "text/x-fossil-wiki");
780 CX("\"parent\": ");
781 if(pWiki->nParent){
782 CX("%!j", pWiki->azParent[0]);
783 }else{
784 CX("null");
785 }
786 if(!pWiki->zWiki || !pWiki->zWiki[0]){
787 CX(", \"isEmpty\": true");
788 }
789 if(includeContent){
790 CX(", \"content\": %!j", pWiki->zWiki);
791 }
792 CX("}");
793 fossil_free(zUuid);
794 manifest_destroy(pWiki);
795 return 2;
796 }
797 }
798
799 /*
800 ** Ajax route handler for /wikiajax/save.
801 **
802 ** URL params:
803 **
804 ** page = the wiki page name.
805 ** mimetype = content mime type.
806 ** content = page content. Fossil considers an empty page to
807 ** be "deleted".
808 ** isnew = 1 if the page is to be newly-created, else 0 or
809 ** not send.
810 **
811 ** Responds with JSON. On error, an object in the form documented by
812 ** ajax_route_error(). On success, an object in the form documented
813 ** for wiki_ajax_emit_page_object().
814 **
815 ** The wikiajax API disallows saving of a sandbox pseudo-page, and
816 ** will respond with an error if asked to save one. Should we want to
817 ** enable it, it's implemented like this for any saved page for which
818 ** is_sandbox(zPageName) is true:
819 **
820 ** db_set("sandbox",zBody,0);
821 ** db_set("sandbox-mimetype",zMimetype,0);
822 **
823 */
824 static void wiki_ajax_route_save(void){
825 const char *zPageName = P("page");
826 const char *zMimetype = P("mimetype");
827 const char *zContent = P("content");
828 const int isNew = ajax_p_bool("isnew");
829 Blob content = empty_blob;
830 int parentRid = 0;
831 int rollback = 0;
832
833 if(!wiki_ajax_can_write(zPageName, &parentRid)){
834 return;
835 }else if(is_sandbox(zPageName)){
836 ajax_route_error(403,"Saving a sandbox page is prohibited.");
837 return;
838 }
839 /* These isNew checks are just me being pedantic. We could just as
840 easily derive isNew based on whether or not the page already
841 exists. */
842 if(isNew){
843 if(parentRid>0){
844 ajax_route_error(403,"Requested a new page, "
845 "but it already exists with RID %d: %s",
846 parentRid, zPageName);
847 return;
848 }
849 }else if(parentRid==0){
850 ajax_route_error(403,"Creating new page [%s] requires passing "
851 "isnew=1.", zPageName);
852 return;
853 }
854 blob_init(&content, zContent ? zContent : "", -1);
855 cgi_set_content_type("application/json");
856 db_begin_transaction();
857 wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0);
858 rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1;
859 db_end_transaction(rollback);
860 }
861
862 /*
863 ** Ajax route handler for /wikiajax/fetch.
864 **
865 ** URL params:
866 **
867 ** page = the wiki page name
868 **
869 ** Responds with JSON. On error, an object in the form documented by
870 ** ajax_route_error(). On success, an object in the form documented
871 ** for wiki_ajax_emit_page_object().
872 */
873 static void wiki_ajax_route_fetch(void){
874 const char * zPageName = P("page");
875
876 if( zPageName==0 || zPageName[0]==0 ){
877 ajax_route_error(400,"Missing page name.");
878 return;
879 }
880 cgi_set_content_type("application/json");
881 wiki_ajax_emit_page_object(zPageName, 1);
882 }
883
884 /*
885 ** Ajax route handler for /wikiajax/diff.
886 **
887 ** URL params:
888 **
889 ** page = the wiki page name
890 ** content = the new/edited wiki page content
891 **
892 ** Requires that the user have write access solely to avoid some
893 ** potential abuse cases. It does not actually write anything.
894 */
895 static void wiki_ajax_route_diff(void){
896 const char * zPageName = P("page");
897 Blob contentNew = empty_blob, contentOrig = empty_blob;
898 Manifest * pParent = 0;
899 const char * zContent = P("content");
900 u64 diffFlags = DIFF_HTML | DIFF_NOTTOOBIG | DIFF_STRIP_EOLCR;
901
902 if( zPageName==0 || zPageName[0]==0 ){
903 ajax_route_error(400,"Missing page name.");
904 return;
905 }else if(!wiki_ajax_can_write(zPageName, 0)){
906 return;
907 }
908 switch(atoi(PD("sbs","0"))){
909 case 0: diffFlags |= DIFF_LINENO; break;
910 default: diffFlags |= DIFF_SIDEBYSIDE;
911 }
912 switch(atoi(PD("ws","2"))){
913 case 1: diffFlags |= DIFF_IGNORE_EOLWS; break;
914 case 2: diffFlags |= DIFF_IGNORE_ALLWS; break;
915 default: break;
916 }
917 wiki_fetch_by_name( zPageName, 0, 0, &pParent );
918 if( pParent && pParent->zWiki && *pParent->zWiki ){
919 blob_init(&contentOrig, pParent->zWiki, -1);
920 }else{
921 blob_init(&contentOrig, "", 0);
922 }
923 blob_init(&contentNew, zContent ? zContent : "", -1);
924 cgi_set_content_type("text/html");
925 ajax_render_diff(&contentOrig, &contentNew, diffFlags);
926 blob_reset(&contentNew);
927 blob_reset(&contentOrig);
928 manifest_destroy(pParent);
929 }
930
931 /*
932 ** Ajax route handler for /wikiajax/preview.
933 **
934 ** URL params:
935 **
936 ** page = wiki page name. This is only needed for authorization
937 ** checking.
938 ** mimetype = the wiki page mimetype (determines rendering style)
939 ** content = the wiki page content
940 */
941 static void wiki_ajax_route_preview(void){
942 const char * zPageName = P("page");
943 const char * zContent = P("content");
944
945 if(!wiki_ajax_can_write(zPageName, 0)){
946 return;
947 }else if( zContent==0 ){
948 ajax_route_error(400,"Missing content to preview.");
949 return;
950 }else{
951 Blob content = empty_blob;
952 const char * zMimetype = PD("mimetype","text/x-fossil-wiki");
953
954 blob_init(&content, zContent, -1);
955 cgi_set_content_type("text/html");
956 wiki_render_by_mimetype(&content, zMimetype);
957 blob_reset(&content);
958 }
959 }
960
961 /*
962 ** Outputs the wiki page list in JSON form. If verbose is false then
963 ** it emits an array of strings (page names). If verbose is true it outputs
964 ** an array of objects in this form:
965 **
966 ** { name: string, version: string or null of sandbox box,
967 ** parent: uuid or null for first version or sandbox,
968 ** mimetype: string,
969 ** type: string (normal, branch, tag, checkin, or sandbox)
970 ** }
971 **
972 ** If includeContent is true, the object contains a "content" member
973 ** with the raw page content. includeContent is ignored if verbose is
974 ** false.
975 **
976 */
977 static void wiki_render_page_list_json(int verbose, int includeContent){
978 Stmt q = empty_Stmt;
979 int n = 0;
980 db_begin_transaction();
981 db_prepare(&q, "SELECT"
982 " substr(tagname,6) AS name"
983 " FROM tag WHERE tagname GLOB 'wiki-*'"
984 " UNION SELECT 'Sandbox' AS name"
985 " ORDER BY name COLLATE NOCASE");
986 CX("[");
987 while( SQLITE_ROW==db_step(&q) ){
988 char const * zName = db_column_text(&q,0);
989 if(n++){
990 CX(",");
991 }
992 if(verbose==0){
993 CX("%!j", zName);
994 }else{
995 wiki_ajax_emit_page_object(zName, includeContent);
996 }
997 }
998 CX("]");
999 db_finalize(&q);
1000 db_end_transaction(0);
1001 }
1002
1003 /*
1004 ** Ajax route handler for /wikiajax/list.
1005 **
1006 ** Optional parameters: verbose, includeContent (see below).
1007 **
1008 ** Responds with JSON. On error, an object in the form documented by
1009 ** ajax_route_error().
1010 **
1011 ** On success, it emits an array of strings (page names) sorted
1012 ** case-insensitively. If the "verbose" parameter is passed in then
1013 ** the result list contains objects in the format documented for
1014 ** wiki_ajax_emit_page_object(). The content of each object is elided
1015 ** unless the "includeContent" parameter is passed on with a
1016 ** "non-false" value..
1017 **
1018 ** The result list always contains an entry named "Sandbox" which
1019 ** represents the sandbox pseudo-page.
1020 */
1021 static void wiki_ajax_route_list(void){
1022 const int verbose = ajax_p_bool("verbose");
1023 const int includeContent = ajax_p_bool("includeContent");
1024
1025 cgi_set_content_type("application/json");
1026 wiki_render_page_list_json(verbose, includeContent);
1027 }
1028
1029 /*
1030 ** WEBPAGE: wikiajax
1031 **
1032 ** An internal dispatcher for wiki AJAX operations. Not for direct
1033 ** client use. All routes defined by this interface are app-internal,
1034 ** subject to change
1035 */
1036 void wiki_ajax_page(void){
1037 const char * zName = P("name");
1038 AjaxRoute routeName = {0,0,0,0};
1039 const AjaxRoute * pRoute = 0;
1040 const AjaxRoute routes[] = {
1041 /* Keep these sorted by zName (for bsearch()) */
1042 {"diff", wiki_ajax_route_diff, 1, 1},
1043 {"fetch", wiki_ajax_route_fetch, 0, 0},
1044 {"list", wiki_ajax_route_list, 0, 0},
1045 {"preview", wiki_ajax_route_preview, 0, 1}
1046 /* preview access mode: whether or not wiki-write mode is needed
1047 really depends on multiple factors. e.g. the sandbox page does
1048 not normally require more than anonymous access. We set its
1049 write-mode to false and do those checks manually in that route's
1050 handler.
1051 */,
1052 {"save", wiki_ajax_route_save, 1, 1}
1053 };
1054
1055 if(zName==0 || zName[0]==0){
1056 ajax_route_error(400,"Missing required [route] 'name' parameter.");
1057 return;
1058 }
1059 routeName.zName = zName;
1060 pRoute = (const AjaxRoute *)bsearch(&routeName, routes,
1061 count(routes), sizeof routes[0],
1062 cmp_ajax_route_name);
1063 if(pRoute==0){
1064 ajax_route_error(404,"Ajax route not found.");
1065 return;
1066 }
1067 login_check_credentials();
1068 if( pRoute->bWriteMode!=0 && g.perm.WrWiki==0 ){
1069 ajax_route_error(403,"Write permissions required.");
1070 return;
1071 }else if(0==cgi_csrf_safe(pRoute->bPost)){
1072 ajax_route_error(403,
1073 "CSRF violation (make sure sending of HTTP "
1074 "Referer headers is enabled for XHR "
1075 "connections).");
1076 return;
1077 }
1078 pRoute->xCallback();
1079 }
1080
1081 /*
1082 ** WEBPAGE: wikiedit
1083 ** URL: /wikedit?name=PAGENAME
1084 **
1085 ** The main front-end for the Ajax-based wiki editor app. Passing
1086 ** in the name of an unknown page will trigger the creation
1087 ** of a new page (which is not actually created in the database
1088 ** until the user explicitly saves it). If passed no page name,
1089 ** the user may select a page from the list on the first UI tab.
1090 **
1091 ** When creating a new page, the mimetype URL parameter may optionally
1092 ** be used to set its mimetype to one of text/x-fossil-wiki,
1093 ** text/x-markdown, or text/plain, defauling to the former.
1094 */
1095 void wikiedit_page(void){
1096 const char *zPageName;
1097 const char * zMimetype = P("mimetype");
1098 int isSandbox;
1099 int found = 0;
1100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1101 login_check_credentials();
1102 zPageName = PD("name","");
1103 if(zPageName && *zPageName){
1104 if( check_name(zPageName) ) return;
1105 }
1106 isSandbox = is_sandbox(zPageName);
1107 if( isSandbox ){
1108 if( !g.perm.WrWiki ){
1109 login_needed(g.anon.WrWiki);
1110 return;
1111 }
1112 found = 1;
1113 }else if( zPageName!=0 ){
1114 int rid = 0;
 
 
 
 
 
 
 
 
 
1115 if( !wiki_special_permission(zPageName) ){
1116 login_needed(0);
1117 return;
1118 }
1119 found = wiki_fetch_by_name(zPageName, 0, &rid, 0);
1120 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
1121 login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki);
1122 return;
1123 }
1124 }
1125 style_header("Wiki Editor");
1126
1127 /* Status bar */
1128 CX("<div id='fossil-status-bar' "
1129 "title='Status message area. Double-click to clear them.'>"
1130 "Status messages will go here.</div>\n"
1131 /* will be moved into the tab container via JS */);
1132
1133 CX("<div id='wikiedit-edit-status''>"
1134 "<span class='name'></span>"
1135 "<span class='links'></span>"
1136 "</div>");
1137
1138 /* Main tab container... */
1139 CX("<div id='wikiedit-tabs' class='tab-container'>Loading...</div>");
1140 /* The .hidden class on the following tab elements is to help lessen
1141 the FOUC effect of the tabs before JS re-assembles them. */
1142
1143 /******* Page list *******/
1144 {
1145 CX("<div id='wikiedit-tab-pages' "
1146 "data-tab-parent='wikiedit-tabs' "
1147 "data-tab-label='Wiki Page List' "
1148 "class='hidden'"
1149 ">");
1150 CX("<div>Loading wiki pages list...</div>");
1151 CX("</div>"/*#wikiedit-tab-pages*/);
1152 }
1153
1154 /******* Content tab *******/
1155 {
1156 CX("<div id='wikiedit-tab-content' "
1157 "data-tab-parent='wikiedit-tabs' "
1158 "data-tab-label='Editor' "
1159 "class='hidden'"
1160 ">");
1161 CX("<div class='flex-container flex-row child-gap-small'>");
1162 CX("<span class='input-with-label'>"
1163 "<label>Mime type</label>");
1164 mimetype_option_menu(0);
1165 CX("</span>");
1166 style_select_list_int("select-font-size",
1167 "editor_font_size", "Editor font size",
1168 NULL/*tooltip*/,
1169 100,
1170 "100%", 100, "125%", 125,
1171 "150%", 150, "175%", 175,
1172 "200%", 200, NULL);
1173 CX("<button class='wikiedit-save'>"
1174 "Save</button>"
1175 /*will get moved around dynamically*/);
1176 CX("<button class='wikiedit-save-close'>"
1177 "Save &amp; Close</button>"/*will get moved around dynamically*/);
1178 CX("<span class='save-button-slot'></span>");
1179 CX("<button class='wikiedit-content-reload' "
1180 "title='Reload the file from the server, discarding "
1181 "any local edits. To help avoid accidental loss of "
1182 "edits, it requires confirmation (a second click) within "
1183 "a few seconds or it will not reload.'"
1184 ">Discard &amp; Reload</button>");
1185 CX("</div>");
1186 CX("<div class='flex-container flex-column stretch'>");
1187 CX("<textarea name='content' id='wikiedit-content-editor' "
1188 "class='wikiedit' rows='25'>");
1189 CX("</textarea>");
1190 CX("</div>"/*textarea wrapper*/);
1191 CX("</div>"/*#tab-file-content*/);
1192 }
1193 /****** Preview tab ******/
1194 {
1195 CX("<div id='wikiedit-tab-preview' "
1196 "data-tab-parent='wikiedit-tabs' "
1197 "data-tab-label='Preview' "
1198 "class='hidden'"
1199 ">");
1200 CX("<div class='wikiedit-options flex-container "
1201 "flex-row child-gap-small'>");
1202 CX("<button id='btn-preview-refresh' "
1203 "data-f-preview-from='wikiContent' "
1204 /* ^^^ fossil.page[methodName]() OR text source elem ID,
1205 ** but we need a method in order to support clients swapping out
1206 ** the text editor with their own. */
1207 "data-f-preview-via='_postPreview' "
1208 /* ^^^ fossil.page[methodName](content, callback) */
1209 "data-f-preview-to='#wikiedit-tab-preview-wrapper' "
1210 /* ^^^ dest elem ID */
1211 ">Refresh</button>");
1212 /* Toggle auto-update of preview when the Preview tab is selected. */
1213 style_labeled_checkbox("cb-preview-autoupdate",
1214 NULL,
1215 "Auto-refresh?",
1216 "1", 1,
1217 "If on, the preview will automatically "
1218 "refresh when this tab is selected.");
1219 CX("<span class='save-button-slot'></span>");
1220 CX("</div>"/*.wikiedit-options*/);
1221 CX("<div id='wikiedit-tab-preview-wrapper'></div>");
1222 CX("</div>"/*#wikiedit-tab-preview*/);
1223 }
1224
1225 /****** Diff tab ******/
1226 {
1227 CX("<div id='wikiedit-tab-diff' "
1228 "data-tab-parent='wikiedit-tabs' "
1229 "data-tab-label='Diff' "
1230 "class='hidden'"
1231 ">");
1232
1233 CX("<div class='wikiedit-options flex-container "
1234 "flex-row child-gap-small' "
1235 "id='wikiedit-tab-diff-buttons'>");
1236 CX("<button class='sbs'>Side-by-side</button>"
1237 "<button class='unified'>Unified</button>");
1238 CX("<span class='save-button-slot'></span>");
1239 CX("</div>");
1240 CX("<div id='wikiedit-tab-diff-wrapper'>"
1241 "Diffs will be shown here."
1242 "</div>");
1243 CX("</div>"/*#wikiedit-tab-diff*/);
1244 }
1245
1246 /****** The obligatory "Misc" tab ******/
1247 {
1248 CX("<div id='wikiedit-tab-misc' "
1249 "data-tab-parent='wikiedit-tabs' "
1250 "data-tab-label='Help' "
1251 "class='hidden'"
1252 ">");
1253 CX("<h2>Wiki formatting rules</h2>");
1254 CX("<ul>");
1255 CX("<li><a href='%R/wiki_rules'>Fossil wiki format</a></li>");
1256 CX("<li><a href='%R/md_rules'>Markdown format</a></li>");
1257 CX("<li>Plain-text pages use no special formatting.</li>");
1258 CX("</ul>");
1259 CX("<h2>The \"Sandbox\" Page</h2>");
1260 CX("<p>The page named \"Sandbox\" is not a real wiki page. "
1261 "It provides a place where users may test out wiki syntax "
1262 "without having to actually save anything, nor pollute "
1263 "the repo with endless test runs. Any attempt to save the "
1264 "sandbox page will fail.</p>");
1265 CX("<h2>Wiki Name Rules</h2>");
1266 well_formed_wiki_name_rules();
1267 CX("</div>"/*#wikiedit-tab-save*/);
1268 }
1269
1270 builtin_request_js("sbsdiff.js");
1271 style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer",
1272 "storage", "page.wikiedit", 0);
1273 builtin_fulfill_js_requests();
1274 /* Dynamically populate the editor... */
1275 style_emit_script_tag(0,0);
1276 {
1277 /* Render the current page list to save us an XHR request
1278 during page initialization. This must be OUTSIDE of
1279 an onPageLoad() handler or else it does not get applied
1280 until after the wiki list widget is initialized. Similarly,
1281 it must come *after* window.fossil is initialized. */
1282 CX("\nfossil.page.initialPageList = ");
1283 wiki_render_page_list_json(1, 0);
1284 CX(";\n");
1285 }
1286 CX("fossil.onPageLoad(function(){\n");
1287 CX("const P = fossil.page;\n"
1288 "try{\n");
1289 if(!found && zPageName && *zPageName){
1290 /* For a new page, stick a dummy entry in the JS-side stash
1291 and "load" it from there. */
1292 CX("const winfo = {"
1293 "\"name\": %!j, \"mimetype\": %!j, "
1294 "\"type\": %!j, "
1295 "\"parent\": null, \"version\": null"
1296 "};\n",
1297 zPageName,
1298 zMimetype ? zMimetype : "text/x-fossil-wiki",
1299 wiki_page_type_name(zPageName));
1300 /* If the JS-side stash already has this page, load that
1301 copy from the stash, otherwise inject a new stash entry
1302 for it and load *that* one... */
1303 CX("if(!P.$stash.getWinfo(winfo)){"
1304 "P.$stash.updateWinfo(winfo,'');"
1305 "}\n");
1306 }
1307 if(zPageName && *zPageName){
1308 CX("P.loadPage(%!j);\n", zPageName);
1309 }
1310 CX("}catch(e){"
1311 "fossil.error(e); console.error('Exception:',e);"
1312 "}\n");
1313 CX("});\n"/*fossil.onPageLoad()*/);
1314 style_emit_script_tag(1,0);
1315 style_footer();
1316 }
1317
1318 /*
1319 ** WEBPAGE: wikinew
@@ -851,17 +1331,11 @@
1331 return;
1332 }
1333 zName = PD("name","");
1334 zMimetype = wiki_filter_mimetypes(P("mimetype"));
1335 if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
1336 cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype);
 
 
 
 
 
 
1337 }
1338 style_header("Create A New Wiki Page");
1339 wiki_standard_submenu(W_ALL_BUT(W_NEW));
1340 @ <p>Rules for wiki page names:</p>
1341 well_formed_wiki_name_rules();
@@ -1441,11 +1915,11 @@
1915 ** -M|--mimetype TEXT-FORMAT The mime type of the update.
1916 ** Defaults to the type used by
1917 ** the previous version of the
1918 ** page, or text/x-fossil-wiki.
1919 ** Valid values are: text/x-fossil-wiki,
1920 ** text/x-markdown and text/plain. fossil,
1921 ** markdown or plain can be specified as
1922 ** synonyms of these values.
1923 ** -t|--technote DATETIME Specifies the timestamp of
1924 ** the technote to be created or
1925 ** updated. When updating a tech note
@@ -1479,13 +1953,18 @@
1953 ** year-month-day form, it may be truncated, the "T" may be replaced by
1954 ** a space, and it may also name a timezone offset from UTC as "-HH:MM"
1955 ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
1956 ** means UTC.
1957 **
1958 ** The "Sandbox" wiki pseudo-page is a special case. Its name is
1959 ** checked case-insensitively and either "create" or "commit" may be
1960 ** used to update its contents.
1961 */
1962 void wiki_cmd(void){
1963 int n;
1964 int isSandbox = 0; /* true if dealing with sandbox pseudo-page */
1965
1966 db_find_and_open_repository(0, 0);
1967 if( g.argc<3 ){
1968 goto wiki_cmd_usage;
1969 }
1970 n = strlen(g.argv[2]);
@@ -1492,14 +1971,14 @@
1971 if( n==0 ){
1972 goto wiki_cmd_usage;
1973 }
1974
1975 if( strncmp(g.argv[2],"export",n)==0 ){
1976 const char *zPageName = 0; /* Name of the wiki page to export */
1977 const char *zFile; /* Name of the output file (0=stdout) */
1978 const char *zETime; /* The name of the technote to export */
1979 int rid = 0; /* Artifact ID of the wiki page */
1980 int i; /* Loop counter */
1981 char *zBody = 0; /* Wiki page content */
1982 Blob body = empty_blob; /* Wiki page content */
1983 Manifest *pWiki = 0; /* Parsed wiki page content */
1984 int fHtml = 0; /* Export in HTML form */
@@ -1517,17 +1996,18 @@
1996 if( !zETime ){
1997 if( (g.argc!=4) && (g.argc!=5) ){
1998 usage("export ?-html? PAGENAME ?FILE?");
1999 }
2000 zPageName = g.argv[3];
2001 isSandbox = is_sandbox(zPageName);
2002 if(isSandbox){
2003 zBody = db_get("sandbox", 0);
2004 }else{
2005 wiki_fetch_by_name(zPageName, 0, &rid, &pWiki);
2006 if(pWiki){
2007 zBody = pWiki->zWiki;
2008 }
2009 }
2010 if( zBody==0 ){
2011 fossil_fatal("wiki page [%s] not found",zPageName);
2012 }
2013 zFile = (g.argc==4) ? "-" : g.argv[4];
@@ -1553,30 +2033,24 @@
2033 blob_init(&body, zBody, -1);
2034 if(fHtml==0){
2035 blob_append(&body, "\n", 1);
2036 }else{
2037 Blob html = empty_blob; /* HTML-ized content */
2038 const char * zMimetype = isSandbox
2039 ? db_get("sandbox-mimetype", "text/x-fossil-wiki")
2040 : wiki_filter_mimetypes(pWiki->zMimetype);
2041 if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
2042 wiki_convert(&body,&html,0);
2043 }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
2044 markdown_to_html(&body,0,&html);
 
 
 
 
 
 
 
 
2045 safe_html_context(DOCSRC_WIKI);
2046 safe_html(&html);
2047 }else if( fossil_strcmp(zMimetype, "text/plain")==0 ){
2048 htmlize_to_blob(&html,zBody,i);
2049 }else{
2050 fossil_fatal("Unsupported MIME type '%s' for wiki page '%s'.",
2051 zMimetype, pWiki ? pWiki->zWikiTitle : zPageName );
2052 }
2053 blob_reset(&body);
2054 body = html /* transfer memory */;
2055 }
2056 pFile = fossil_fopen_for_output(zFile);
@@ -1618,28 +2092,28 @@
2092 if( g.argc==4 ){
2093 blob_read_from_channel(&content, stdin, -1);
2094 }else{
2095 blob_read_from_file(&content, g.argv[4], ExtFILE);
2096 }
2097 isSandbox = is_sandbox(zPageName);
2098 if ( !zETime ){
2099 if( !isSandbox ){
2100 wiki_fetch_by_name(zPageName, 0, &rid, &pWiki);
 
 
 
 
 
2101 }
2102 }else{
2103 rid = wiki_technote_to_rid(zETime);
2104 if( rid>0 ){
2105 pWiki = manifest_get(rid, CFTYPE_EVENT, 0);
2106 }
2107 }
2108 if( !zMimeType || !*zMimeType ){
2109 /* Try to deduce the mime type based on the prior version. */
2110 if(isSandbox){
2111 zMimeType =
2112 wiki_filter_mimetypes(db_get("sandbox-mimetype",
2113 "text/x-fossil-wiki"));
2114 }else if( pWiki!=0 && (pWiki->zMimetype && *pWiki->zMimetype) ){
2115 zMimeType = pWiki->zMimetype;
2116 }
2117 }else{
2118 zMimeType = wiki_filter_mimetypes(zMimeType);
2119 }
@@ -1649,24 +2123,30 @@
2123 }else{
2124 /* Creating a tech note with same timestamp is permitted
2125 and should create a new tech note */
2126 rid = 0;
2127 }
2128 }else if( !isCreate && rid==0 && isSandbox==0 ){
2129 if ( !zETime ){
2130 fossil_fatal("no such wiki page: %s", zPageName);
2131 }else{
2132 fossil_fatal("no such tech note: %s", zETime);
2133 }
2134 }
2135
2136 if( !zETime ){
2137 if(isSandbox){
2138 db_set("sandbox",blob_str(&content),0);
2139 db_set("sandbox-mimetype",zMimeType,0);
2140 fossil_print("Updated sandbox pseudo-page.\n");
2141 }else{
2142 wiki_cmd_commit(zPageName, rid, &content, zMimeType, 1);
2143 if( g.argv[2][1]=='r' ){
2144 fossil_print("Created new wiki page %s.\n", zPageName);
2145 }else{
2146 fossil_print("Updated wiki page %s.\n", zPageName);
2147 }
2148 }
2149 }else{
2150 if( rid != -1 ){
2151 char *zMETime; /* Normalized, mutable version of zETime */
2152 zMETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))",
@@ -1844,8 +2324,8 @@
2324 blob_reset(&tail);
2325 blob_reset(&title);
2326 blob_reset(&wiki);
2327 }
2328 manifest_destroy(pWiki);
2329 builtin_request_js("accordion.js");
2330 return 1;
2331 }
2332
2333 ELETED src/wysiwyg.c
D src/wysiwyg.c
-328
--- a/src/wysiwyg.c
+++ b/src/wysiwyg.c
@@ -1,328 +0,0 @@
1
-/*
2
-** Copyright (c) 2012 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
-** This file contains code that generates WYSIWYG text editors on
19
-** web pages.
20
-*/
21
-#include "config.h"
22
-#include <assert.h>
23
-#include <ctype.h>
24
-#include "wysiwyg.h"
25
-
26
-
27
-/*
28
-** Output code for a WYSIWYG editor. The caller must have already generated
29
-** the <form> that will contain the editor, and the call must generate the
30
-** corresponding </form> after this routine returns. The caller must include
31
-** an onsubmit= attribute on the <form> element that invokes the
32
-** wysiwygSubmit() function.
33
-**
34
-** There can only be a single WYSIWYG editor per frame.
35
-*/
36
-void wysiwygEditor(
37
- const char *zId, /* ID for this editor */
38
- const char *zContent, /* Initial content (HTML) */
39
- int w, int h /* Initial width and height */
40
-){
41
-
42
- @ <style type="text/css">
43
- @ .intLink { cursor: pointer; }
44
- @ img.intLink { border: 0; }
45
- @ #wysiwygBox {
46
- @ border: 1px #000000 solid;
47
- @ padding: 12px;
48
- @ }
49
- @ #editMode label { cursor: pointer; }
50
- @ </style>
51
-
52
- @ <input id="wysiwygValue" type="hidden" name="%s(zId)">
53
- @ <div id="editModeDiv">Edit mode:
54
- @ <select id="editMode" size=1>
55
- @ <option value="0">WYSIWYG</option>
56
- @ <option value="1">Raw HTML</option>
57
- @ </select></div>
58
- @ <div id="toolBar1">
59
- @ <select class="format" data-format="formatblock">
60
- @ <option selected>- formatting -</option>
61
- @ <option value="h1">Title 1 &lt;h1&gt;</option>
62
- @ <option value="h2">Title 2 &lt;h2&gt;</option>
63
- @ <option value="h3">Title 3 &lt;h3&gt;</option>
64
- @ <option value="h4">Title 4 &lt;h4&gt;</option>
65
- @ <option value="h5">Title 5 &lt;h5&gt;</option>
66
- @ <option value="h6">Subtitle &lt;h6&gt;</option>
67
- @ <option value="p">Paragraph &lt;p&gt;</option>
68
- @ <option value="pre">Preformatted &lt;pre&gt;</option>
69
- @ </select>
70
- @ <select class="format" data-format="fontname">
71
- @ <option class="heading" selected>- font -</option>
72
- @ <option>Arial</option>
73
- @ <option>Arial Black</option>
74
- @ <option>Courier New</option>
75
- @ <option>Times New Roman</option>
76
- @ </select>
77
- @ <select class="format" data-format="fontsize">
78
- @ <option class="heading" selected>- size -</option>
79
- @ <option value="1">Very small</option>
80
- @ <option value="2">A bit small</option>
81
- @ <option value="3">Normal</option>
82
- @ <option value="4">Medium-large</option>
83
- @ <option value="5">Big</option>
84
- @ <option value="6">Very big</option>
85
- @ <option value="7">Maximum</option>
86
- @ </select>
87
- @ <select class="format" data-format="forecolor">
88
- @ <option class="heading" selected>- color -</option>
89
- @ <option value="red">Red</option>
90
- @ <option value="blue">Blue</option>
91
- @ <option value="green">Green</option>
92
- @ <option value="black">Black</option>
93
- @ </select>
94
- @ </div>
95
- @ <div id="toolBar2">
96
- @ <img class="intLink" title="Undo" data-format="undo"
97
- @ src="data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7
98
- @ /I19DV3NHa7P///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq704680
99
- @ 7TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfE
100
- @ whdRIH4fh/DZMICe3/C4nBQBADs=">
101
-
102
- @ <img class="intLink" title="Redo" data-format="redo"
103
- @ src="data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1/
104
- @ ///yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9Na
105
- @ EDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw==">
106
-
107
- @ <img class="intLink" title="Remove formatting" data-format="removeFormat"
108
- @ src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AA
109
- @ AABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwA
110
- @ AAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB5
111
- @ 01ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqG
112
- @ Xz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMz
113
- @ deiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3//sf37/1/c02cCG1lB8f//f95
114
- @ DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af///2ckaHBp7+7wmavP5n76+P2C
115
- @ lrLIYl8H9W36auJCbCxM4szMTJac7Kza////R3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tA
116
- @ wMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n
117
- @ 7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1
118
- @ lsXc4Db7z8C3r8p7Qjf///2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj
119
- @ 5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwf
120
- @ fj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv//vPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrj
121
- @ b/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0////fv77//8nLy+7MCc
122
- @ XmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc66
123
- @ 6s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7//8/4//9/pgOnH
124
- @ 6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg==">
125
-
126
- @ <img class="intLink" title="Bold" data-format="bold"
127
- @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
128
- @ YAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs=" />
129
-
130
- @ <img class="intLink" title="Italic" data-format="italic"
131
- @ src="data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf///yH5BAEAAAMALA
132
- @ AAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw==" />
133
-
134
- @ <img class="intLink" title="Underline" data-format="underline"
135
- @ src="data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vj////////yH5BAEAAAIALA
136
- @ AAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA
137
- @ 7" />
138
-
139
- @ <img class="intLink" title="Left align" data-format="justifyleft"
140
- @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
141
- @ YAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw==" />
142
-
143
- @ <img class="intLink" title="Center align" data-format="justifycenter"
144
- @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
145
- @ YAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7" />
146
-
147
- @ <img class="intLink" title="Right align" data-format="justifyright"
148
- @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
149
- @ YAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw==" />
150
- @ <img class="intLink" title="Numbered list"
151
- @ data-format="insertorderedlist"
152
- @ src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P////
153
- @ ///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEO
154
- @ zyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs=" />
155
-
156
- @ <img class="intLink" title="Dotted list"
157
- @ data-format="insertunorderedlist"
158
- @ src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv////
159
- @ ///yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud6
160
- @ 4UwiuKnigGQliQuWOyKQykgAAOw==" />
161
-
162
- @ <img class="intLink" title="Quote" data-format="formatblock"
163
- @ src="data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2
164
- @ R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P/////////
165
- @ //////////////////////////yH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2Cekk
166
- @ ErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrT
167
- @ q/b7/i8fp8PAQA7" />
168
-
169
- @ <img class="intLink" title="Delete indentation" data-format="outdent"
170
- @ src="data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P
171
- @ ///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMcz
172
- @ sYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs=" />
173
-
174
- @ <img class="intLink" title="Add indentation" data-format="indent"
175
- @ src="data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3N
176
- @ Ha7P///////////////////////////////yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650
177
- @ B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw==">
178
-
179
- @ <img class="intLink" title="Hyperlink" data-format="createlink"
180
- @ src="data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb
181
- @ /I19Ha7Pv8/f///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq704682
182
- @ 7/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghG
183
- @ i9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7" />
184
-
185
-#if 0 /* Cut/Copy/Paste requires special browser permissions for security
186
- ** reasons. So omit these buttons */
187
- @ <img class="intLink" title="Cut" data-format="cut"
188
- @ src="data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1
189
- @ dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P/////////////////////////////
190
- @ //////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnE
191
- @ bGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9
192
- @ ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw==" />
193
-
194
- @ <img class="intLink" title="Copy" data-format="copy"
195
- @ src="data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31
196
- @ iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OP
197
- @ s++bx/Pv8/f///////////////yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/
198
- @ kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ
199
- @ ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA
200
- @ Grpy+wsbKzIiEAOw==" />
201
-
202
- @ <img class="intLink" title="Paste" data-format="paste"
203
- @ src="data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp
204
- @ qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/////////////////////
205
- @ //////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB
206
- @ SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ
207
- @ o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA
208
- @ MOaK+bLAOrtLUyt7i5uiUhADs=" />
209
-#endif
210
-
211
- @ </div>
212
- @ <div id="wysiwygBox"
213
- @ style="resize:both;overflow:auto;width:95%%;min-height:%d(h)em;"
214
- @ contenteditable="true">%s(zContent)</div>
215
- @ <script nonce="%h(style_nonce())">
216
- @ var oDoc;
217
- @
218
- @ /* Initialize the document editor */
219
- @ function initDoc() {
220
- @ initEventHandlers();
221
- @ oDoc = document.getElementById("wysiwygBox");
222
- @ if (!isWysiwyg()) { setDocMode(true); }
223
- @ }
224
- @
225
- @ function initEventHandlers() {
226
- @ document.querySelector('form').onsubmit = wysiwygSubmit;
227
- @ document.querySelector('#editMode').onchange = function() {
228
- @ setDocMode(this.selectedIndex)
229
- @ };
230
- @ var controls = document.querySelectorAll('select.format');
231
- @ for(var i = 0; i < controls.length; i++) {
232
- @ controls[i].onchange = handleDropDown;
233
- @ }
234
- @ controls = document.querySelectorAll('.intLink');
235
- @ for(i = 0; i < controls.length; i++) {
236
- @ controls[i].onclick = handleFormatButton;
237
- @ }
238
- @
239
- @ function handleDropDown() {
240
- @ formatDoc(this.dataset.format,this[this.selectedIndex].value);
241
- @ this.selectedIndex = 0;
242
- @ }
243
- @
244
- @ function handleFormatButton() {
245
- @ var extra;
246
- @ switch (this.dataset.format) {
247
- @ case 'createlink':
248
- @ var sLnk = prompt('Target URL:','');
249
- @ if(sLnk && sLnk != '')
250
- @ {
251
- @ extra = sLnk;
252
- @ }
253
- @ break;
254
- @ case 'formatblock':
255
- @ extra = 'blockquote';
256
- @ break;
257
- @ }
258
- @ formatDoc(this.dataset.format, extra);
259
- @ }
260
- @ }
261
- @
262
- @ /* Return true if the document editor is in WYSIWYG mode. Return
263
- @ ** false if it is in Markup mode */
264
- @ function isWysiwyg() {
265
- @ return document.getElementById("editMode").selectedIndex==0;
266
- @ }
267
- @
268
- @ /* Invoke this routine prior to submitting the HTML content back
269
- @ ** to the server */
270
- @ function wysiwygSubmit() {
271
- @ if(oDoc.style.whiteSpace=="pre-wrap"){setDocMode(0);}
272
- @ document.getElementById("wysiwygValue").value=oDoc.innerHTML;
273
- @ }
274
- @
275
- @ /* Run the editing command if in WYSIWYG mode */
276
- @ function formatDoc(sCmd, sValue) {
277
- @ if (isWysiwyg()){
278
- @ try {
279
- @ // First, try the W3C draft standard way, which has
280
- @ // been working on all non-IE browsers for a while.
281
- @ // It is also supported by IE11 and higher.
282
- @ document.execCommand("styleWithCSS", false, false);
283
- @ } catch (e) {
284
- @ try {
285
- @ // For IE9 or IE10, this should work.
286
- @ document.execCommand("useCSS", 0, true);
287
- @ } catch (e) {
288
- @ // OK, that apparently did not work, do nothing.
289
- @ }
290
- @ }
291
- @ document.execCommand(sCmd, false, sValue);
292
- @ oDoc.focus();
293
- @ }
294
- @ }
295
- @
296
- @ /* Change the editing mode. Convert to markup if the argument
297
- @ ** is true and wysiwyg if the argument is false. */
298
- @ function setDocMode(bToMarkup) {
299
- @ var oContent;
300
- @ if (bToMarkup) {
301
- @ /* WYSIWYG -> Markup */
302
- @ var linebreak = new RegExp("</p><p>","ig");
303
- @ oContent = document.createTextNode(
304
- @ oDoc.innerHTML.replace(linebreak,"</p>\n\n<p>"));
305
- @ oDoc.innerHTML = "";
306
- @ oDoc.style.whiteSpace = "pre-wrap";
307
- @ oDoc.appendChild(oContent);
308
- @ document.getElementById("toolBar1").style.visibility="hidden";
309
- @ document.getElementById("toolBar2").style.visibility="hidden";
310
- @ } else {
311
- @ /* Markup -> WYSIWYG */
312
- @ if (document.all) {
313
- @ oDoc.innerHTML = oDoc.innerText;
314
- @ } else {
315
- @ oContent = document.createRange();
316
- @ oContent.selectNodeContents(oDoc.firstChild);
317
- @ oDoc.innerHTML = oContent.toString();
318
- @ }
319
- @ oDoc.style.whiteSpace = "normal";
320
- @ document.getElementById("toolBar1").style.visibility="visible";
321
- @ document.getElementById("toolBar2").style.visibility="visible";
322
- @ }
323
- @ oDoc.focus();
324
- @ }
325
- @ initDoc();
326
- @ </script>
327
-
328
-}
--- a/src/wysiwyg.c
+++ b/src/wysiwyg.c
@@ -1,328 +0,0 @@
1 /*
2 ** Copyright (c) 2012 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 ** This file contains code that generates WYSIWYG text editors on
19 ** web pages.
20 */
21 #include "config.h"
22 #include <assert.h>
23 #include <ctype.h>
24 #include "wysiwyg.h"
25
26
27 /*
28 ** Output code for a WYSIWYG editor. The caller must have already generated
29 ** the <form> that will contain the editor, and the call must generate the
30 ** corresponding </form> after this routine returns. The caller must include
31 ** an onsubmit= attribute on the <form> element that invokes the
32 ** wysiwygSubmit() function.
33 **
34 ** There can only be a single WYSIWYG editor per frame.
35 */
36 void wysiwygEditor(
37 const char *zId, /* ID for this editor */
38 const char *zContent, /* Initial content (HTML) */
39 int w, int h /* Initial width and height */
40 ){
41
42 @ <style type="text/css">
43 @ .intLink { cursor: pointer; }
44 @ img.intLink { border: 0; }
45 @ #wysiwygBox {
46 @ border: 1px #000000 solid;
47 @ padding: 12px;
48 @ }
49 @ #editMode label { cursor: pointer; }
50 @ </style>
51
52 @ <input id="wysiwygValue" type="hidden" name="%s(zId)">
53 @ <div id="editModeDiv">Edit mode:
54 @ <select id="editMode" size=1>
55 @ <option value="0">WYSIWYG</option>
56 @ <option value="1">Raw HTML</option>
57 @ </select></div>
58 @ <div id="toolBar1">
59 @ <select class="format" data-format="formatblock">
60 @ <option selected>- formatting -</option>
61 @ <option value="h1">Title 1 &lt;h1&gt;</option>
62 @ <option value="h2">Title 2 &lt;h2&gt;</option>
63 @ <option value="h3">Title 3 &lt;h3&gt;</option>
64 @ <option value="h4">Title 4 &lt;h4&gt;</option>
65 @ <option value="h5">Title 5 &lt;h5&gt;</option>
66 @ <option value="h6">Subtitle &lt;h6&gt;</option>
67 @ <option value="p">Paragraph &lt;p&gt;</option>
68 @ <option value="pre">Preformatted &lt;pre&gt;</option>
69 @ </select>
70 @ <select class="format" data-format="fontname">
71 @ <option class="heading" selected>- font -</option>
72 @ <option>Arial</option>
73 @ <option>Arial Black</option>
74 @ <option>Courier New</option>
75 @ <option>Times New Roman</option>
76 @ </select>
77 @ <select class="format" data-format="fontsize">
78 @ <option class="heading" selected>- size -</option>
79 @ <option value="1">Very small</option>
80 @ <option value="2">A bit small</option>
81 @ <option value="3">Normal</option>
82 @ <option value="4">Medium-large</option>
83 @ <option value="5">Big</option>
84 @ <option value="6">Very big</option>
85 @ <option value="7">Maximum</option>
86 @ </select>
87 @ <select class="format" data-format="forecolor">
88 @ <option class="heading" selected>- color -</option>
89 @ <option value="red">Red</option>
90 @ <option value="blue">Blue</option>
91 @ <option value="green">Green</option>
92 @ <option value="black">Black</option>
93 @ </select>
94 @ </div>
95 @ <div id="toolBar2">
96 @ <img class="intLink" title="Undo" data-format="undo"
97 @ src="data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7
98 @ /I19DV3NHa7P///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq704680
99 @ 7TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfE
100 @ whdRIH4fh/DZMICe3/C4nBQBADs=">
101
102 @ <img class="intLink" title="Redo" data-format="redo"
103 @ src="data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1/
104 @ ///yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9Na
105 @ EDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw==">
106
107 @ <img class="intLink" title="Remove formatting" data-format="removeFormat"
108 @ src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AA
109 @ AABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwA
110 @ AAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB5
111 @ 01ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqG
112 @ Xz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMz
113 @ deiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3//sf37/1/c02cCG1lB8f//f95
114 @ DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af///2ckaHBp7+7wmavP5n76+P2C
115 @ lrLIYl8H9W36auJCbCxM4szMTJac7Kza////R3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tA
116 @ wMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n
117 @ 7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1
118 @ lsXc4Db7z8C3r8p7Qjf///2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj
119 @ 5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwf
120 @ fj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv//vPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrj
121 @ b/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0////fv77//8nLy+7MCc
122 @ XmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc66
123 @ 6s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7//8/4//9/pgOnH
124 @ 6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg==">
125
126 @ <img class="intLink" title="Bold" data-format="bold"
127 @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
128 @ YAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs=" />
129
130 @ <img class="intLink" title="Italic" data-format="italic"
131 @ src="data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf///yH5BAEAAAMALA
132 @ AAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw==" />
133
134 @ <img class="intLink" title="Underline" data-format="underline"
135 @ src="data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vj////////yH5BAEAAAIALA
136 @ AAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA
137 @ 7" />
138
139 @ <img class="intLink" title="Left align" data-format="justifyleft"
140 @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
141 @ YAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw==" />
142
143 @ <img class="intLink" title="Center align" data-format="justifycenter"
144 @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
145 @ YAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7" />
146
147 @ <img class="intLink" title="Right align" data-format="justifyright"
148 @ src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB
149 @ YAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw==" />
150 @ <img class="intLink" title="Numbered list"
151 @ data-format="insertorderedlist"
152 @ src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P////
153 @ ///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEO
154 @ zyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs=" />
155
156 @ <img class="intLink" title="Dotted list"
157 @ data-format="insertunorderedlist"
158 @ src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv////
159 @ ///yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud6
160 @ 4UwiuKnigGQliQuWOyKQykgAAOw==" />
161
162 @ <img class="intLink" title="Quote" data-format="formatblock"
163 @ src="data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2
164 @ R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P/////////
165 @ //////////////////////////yH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2Cekk
166 @ ErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrT
167 @ q/b7/i8fp8PAQA7" />
168
169 @ <img class="intLink" title="Delete indentation" data-format="outdent"
170 @ src="data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P
171 @ ///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMcz
172 @ sYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs=" />
173
174 @ <img class="intLink" title="Add indentation" data-format="indent"
175 @ src="data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3N
176 @ Ha7P///////////////////////////////yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650
177 @ B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw==">
178
179 @ <img class="intLink" title="Hyperlink" data-format="createlink"
180 @ src="data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb
181 @ /I19Ha7Pv8/f///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq704682
182 @ 7/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghG
183 @ i9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7" />
184
185 #if 0 /* Cut/Copy/Paste requires special browser permissions for security
186 ** reasons. So omit these buttons */
187 @ <img class="intLink" title="Cut" data-format="cut"
188 @ src="data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1
189 @ dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P/////////////////////////////
190 @ //////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnE
191 @ bGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9
192 @ ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw==" />
193
194 @ <img class="intLink" title="Copy" data-format="copy"
195 @ src="data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31
196 @ iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OP
197 @ s++bx/Pv8/f///////////////yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/
198 @ kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ
199 @ ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA
200 @ Grpy+wsbKzIiEAOw==" />
201
202 @ <img class="intLink" title="Paste" data-format="paste"
203 @ src="data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp
204 @ qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/////////////////////
205 @ //////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB
206 @ SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ
207 @ o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA
208 @ MOaK+bLAOrtLUyt7i5uiUhADs=" />
209 #endif
210
211 @ </div>
212 @ <div id="wysiwygBox"
213 @ style="resize:both;overflow:auto;width:95%%;min-height:%d(h)em;"
214 @ contenteditable="true">%s(zContent)</div>
215 @ <script nonce="%h(style_nonce())">
216 @ var oDoc;
217 @
218 @ /* Initialize the document editor */
219 @ function initDoc() {
220 @ initEventHandlers();
221 @ oDoc = document.getElementById("wysiwygBox");
222 @ if (!isWysiwyg()) { setDocMode(true); }
223 @ }
224 @
225 @ function initEventHandlers() {
226 @ document.querySelector('form').onsubmit = wysiwygSubmit;
227 @ document.querySelector('#editMode').onchange = function() {
228 @ setDocMode(this.selectedIndex)
229 @ };
230 @ var controls = document.querySelectorAll('select.format');
231 @ for(var i = 0; i < controls.length; i++) {
232 @ controls[i].onchange = handleDropDown;
233 @ }
234 @ controls = document.querySelectorAll('.intLink');
235 @ for(i = 0; i < controls.length; i++) {
236 @ controls[i].onclick = handleFormatButton;
237 @ }
238 @
239 @ function handleDropDown() {
240 @ formatDoc(this.dataset.format,this[this.selectedIndex].value);
241 @ this.selectedIndex = 0;
242 @ }
243 @
244 @ function handleFormatButton() {
245 @ var extra;
246 @ switch (this.dataset.format) {
247 @ case 'createlink':
248 @ var sLnk = prompt('Target URL:','');
249 @ if(sLnk && sLnk != '')
250 @ {
251 @ extra = sLnk;
252 @ }
253 @ break;
254 @ case 'formatblock':
255 @ extra = 'blockquote';
256 @ break;
257 @ }
258 @ formatDoc(this.dataset.format, extra);
259 @ }
260 @ }
261 @
262 @ /* Return true if the document editor is in WYSIWYG mode. Return
263 @ ** false if it is in Markup mode */
264 @ function isWysiwyg() {
265 @ return document.getElementById("editMode").selectedIndex==0;
266 @ }
267 @
268 @ /* Invoke this routine prior to submitting the HTML content back
269 @ ** to the server */
270 @ function wysiwygSubmit() {
271 @ if(oDoc.style.whiteSpace=="pre-wrap"){setDocMode(0);}
272 @ document.getElementById("wysiwygValue").value=oDoc.innerHTML;
273 @ }
274 @
275 @ /* Run the editing command if in WYSIWYG mode */
276 @ function formatDoc(sCmd, sValue) {
277 @ if (isWysiwyg()){
278 @ try {
279 @ // First, try the W3C draft standard way, which has
280 @ // been working on all non-IE browsers for a while.
281 @ // It is also supported by IE11 and higher.
282 @ document.execCommand("styleWithCSS", false, false);
283 @ } catch (e) {
284 @ try {
285 @ // For IE9 or IE10, this should work.
286 @ document.execCommand("useCSS", 0, true);
287 @ } catch (e) {
288 @ // OK, that apparently did not work, do nothing.
289 @ }
290 @ }
291 @ document.execCommand(sCmd, false, sValue);
292 @ oDoc.focus();
293 @ }
294 @ }
295 @
296 @ /* Change the editing mode. Convert to markup if the argument
297 @ ** is true and wysiwyg if the argument is false. */
298 @ function setDocMode(bToMarkup) {
299 @ var oContent;
300 @ if (bToMarkup) {
301 @ /* WYSIWYG -> Markup */
302 @ var linebreak = new RegExp("</p><p>","ig");
303 @ oContent = document.createTextNode(
304 @ oDoc.innerHTML.replace(linebreak,"</p>\n\n<p>"));
305 @ oDoc.innerHTML = "";
306 @ oDoc.style.whiteSpace = "pre-wrap";
307 @ oDoc.appendChild(oContent);
308 @ document.getElementById("toolBar1").style.visibility="hidden";
309 @ document.getElementById("toolBar2").style.visibility="hidden";
310 @ } else {
311 @ /* Markup -> WYSIWYG */
312 @ if (document.all) {
313 @ oDoc.innerHTML = oDoc.innerText;
314 @ } else {
315 @ oContent = document.createRange();
316 @ oContent.selectNodeContents(oDoc.firstChild);
317 @ oDoc.innerHTML = oContent.toString();
318 @ }
319 @ oDoc.style.whiteSpace = "normal";
320 @ document.getElementById("toolBar1").style.visibility="visible";
321 @ document.getElementById("toolBar2").style.visibility="visible";
322 @ }
323 @ oDoc.focus();
324 @ }
325 @ initDoc();
326 @ </script>
327
328 }
--- a/src/wysiwyg.c
+++ b/src/wysiwyg.c
@@ -1,328 +0,0 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
+2 -2
--- src/xfer.c
+++ src/xfer.c
@@ -1213,11 +1213,11 @@
12131213
xfer.maxTime = db_get_int("max-download-time", 30);
12141214
if( xfer.maxTime<1 ) xfer.maxTime = 1;
12151215
xfer.maxTime += time(NULL);
12161216
g.xferPanic = 1;
12171217
1218
- db_begin_transaction();
1218
+ db_begin_write();
12191219
db_multi_exec(
12201220
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
12211221
"CREATE TEMP TABLE unk(uuid TEXT PRIMARY KEY) WITHOUT ROWID;"
12221222
);
12231223
manifest_crosslink_begin();
@@ -1753,11 +1753,11 @@
17531753
*/
17541754
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
17551755
@ # timestamp %s(zNow)
17561756
free(zNow);
17571757
1758
- db_end_transaction(0);
1758
+ db_commit_transaction();
17591759
configure_rebuild();
17601760
}
17611761
17621762
/*
17631763
** COMMAND: test-xfer
17641764
--- src/xfer.c
+++ src/xfer.c
@@ -1213,11 +1213,11 @@
1213 xfer.maxTime = db_get_int("max-download-time", 30);
1214 if( xfer.maxTime<1 ) xfer.maxTime = 1;
1215 xfer.maxTime += time(NULL);
1216 g.xferPanic = 1;
1217
1218 db_begin_transaction();
1219 db_multi_exec(
1220 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
1221 "CREATE TEMP TABLE unk(uuid TEXT PRIMARY KEY) WITHOUT ROWID;"
1222 );
1223 manifest_crosslink_begin();
@@ -1753,11 +1753,11 @@
1753 */
1754 zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
1755 @ # timestamp %s(zNow)
1756 free(zNow);
1757
1758 db_end_transaction(0);
1759 configure_rebuild();
1760 }
1761
1762 /*
1763 ** COMMAND: test-xfer
1764
--- src/xfer.c
+++ src/xfer.c
@@ -1213,11 +1213,11 @@
1213 xfer.maxTime = db_get_int("max-download-time", 30);
1214 if( xfer.maxTime<1 ) xfer.maxTime = 1;
1215 xfer.maxTime += time(NULL);
1216 g.xferPanic = 1;
1217
1218 db_begin_write();
1219 db_multi_exec(
1220 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
1221 "CREATE TEMP TABLE unk(uuid TEXT PRIMARY KEY) WITHOUT ROWID;"
1222 );
1223 manifest_crosslink_begin();
@@ -1753,11 +1753,11 @@
1753 */
1754 zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
1755 @ # timestamp %s(zNow)
1756 free(zNow);
1757
1758 db_commit_transaction();
1759 configure_rebuild();
1760 }
1761
1762 /*
1763 ** COMMAND: test-xfer
1764
--- test/merge1.test
+++ test/merge1.test
@@ -75,11 +75,11 @@
7575
555 - we think it well and other stuff too - 5555
7676
}
7777
write_file_indented t23 {
7878
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
7979
111 - This is line ONE of the demo program - 1111
80
- ======= COMMON ANCESTOR content follows ============================
80
+ ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
8181
111 - This is line one of the demo program - 1111
8282
======= MERGED IN content follows ==================================
8383
111 - This is line one OF the demo program - 1111
8484
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
8585
222 - The second line program line in code - 2222
@@ -88,11 +88,11 @@
8888
555 - we think it well and other stuff too - 5555
8989
}
9090
write_file_indented t32 {
9191
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
9292
111 - This is line one OF the demo program - 1111
93
- ======= COMMON ANCESTOR content follows ============================
93
+ ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
9494
111 - This is line one of the demo program - 1111
9595
======= MERGED IN content follows ==================================
9696
111 - This is line ONE of the demo program - 1111
9797
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
9898
222 - The second line program line in code - 2222
@@ -159,11 +159,11 @@
159159
444 - If all goes well, we will be pleased - 4444
160160
555 - we think it well and other stuff too - 5555
161161
}
162162
write_file_indented t32 {
163163
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
164
- ======= COMMON ANCESTOR content follows ============================
164
+ ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
165165
111 - This is line one of the demo program - 1111
166166
======= MERGED IN content follows ==================================
167167
000 - Zero lines added to the beginning of - 0000
168168
111 - This is line one of the demo program - 1111
169169
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -174,11 +174,11 @@
174174
}
175175
write_file_indented t23 {
176176
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
177177
000 - Zero lines added to the beginning of - 0000
178178
111 - This is line one of the demo program - 1111
179
- ======= COMMON ANCESTOR content follows ============================
179
+ ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
180180
111 - This is line one of the demo program - 1111
181181
======= MERGED IN content follows ==================================
182182
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
183183
222 - The second line program line in code - 2222
184184
333 - This is a test of the merging algohm - 3333
@@ -306,11 +306,11 @@
306306
qrst
307307
uvwx
308308
yzAB 2
309309
CDEF 2
310310
GHIJ 2
311
- ======= COMMON ANCESTOR content follows ============================
311
+ ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
312312
efgh
313313
ijkl
314314
mnop
315315
qrst
316316
uvwx
@@ -374,11 +374,11 @@
374374
qrst
375375
uvwx
376376
yzAB 2
377377
CDEF 2
378378
GHIJ 2
379
- ======= COMMON ANCESTOR content follows ============================
379
+ ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
380380
efgh
381381
ijkl
382382
mnop
383383
qrst
384384
uvwx
385385
--- test/merge1.test
+++ test/merge1.test
@@ -75,11 +75,11 @@
75 555 - we think it well and other stuff too - 5555
76 }
77 write_file_indented t23 {
78 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
79 111 - This is line ONE of the demo program - 1111
80 ======= COMMON ANCESTOR content follows ============================
81 111 - This is line one of the demo program - 1111
82 ======= MERGED IN content follows ==================================
83 111 - This is line one OF the demo program - 1111
84 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
85 222 - The second line program line in code - 2222
@@ -88,11 +88,11 @@
88 555 - we think it well and other stuff too - 5555
89 }
90 write_file_indented t32 {
91 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
92 111 - This is line one OF the demo program - 1111
93 ======= COMMON ANCESTOR content follows ============================
94 111 - This is line one of the demo program - 1111
95 ======= MERGED IN content follows ==================================
96 111 - This is line ONE of the demo program - 1111
97 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
98 222 - The second line program line in code - 2222
@@ -159,11 +159,11 @@
159 444 - If all goes well, we will be pleased - 4444
160 555 - we think it well and other stuff too - 5555
161 }
162 write_file_indented t32 {
163 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
164 ======= COMMON ANCESTOR content follows ============================
165 111 - This is line one of the demo program - 1111
166 ======= MERGED IN content follows ==================================
167 000 - Zero lines added to the beginning of - 0000
168 111 - This is line one of the demo program - 1111
169 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -174,11 +174,11 @@
174 }
175 write_file_indented t23 {
176 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
177 000 - Zero lines added to the beginning of - 0000
178 111 - This is line one of the demo program - 1111
179 ======= COMMON ANCESTOR content follows ============================
180 111 - This is line one of the demo program - 1111
181 ======= MERGED IN content follows ==================================
182 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
183 222 - The second line program line in code - 2222
184 333 - This is a test of the merging algohm - 3333
@@ -306,11 +306,11 @@
306 qrst
307 uvwx
308 yzAB 2
309 CDEF 2
310 GHIJ 2
311 ======= COMMON ANCESTOR content follows ============================
312 efgh
313 ijkl
314 mnop
315 qrst
316 uvwx
@@ -374,11 +374,11 @@
374 qrst
375 uvwx
376 yzAB 2
377 CDEF 2
378 GHIJ 2
379 ======= COMMON ANCESTOR content follows ============================
380 efgh
381 ijkl
382 mnop
383 qrst
384 uvwx
385
--- test/merge1.test
+++ test/merge1.test
@@ -75,11 +75,11 @@
75 555 - we think it well and other stuff too - 5555
76 }
77 write_file_indented t23 {
78 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
79 111 - This is line ONE of the demo program - 1111
80 ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
81 111 - This is line one of the demo program - 1111
82 ======= MERGED IN content follows ==================================
83 111 - This is line one OF the demo program - 1111
84 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
85 222 - The second line program line in code - 2222
@@ -88,11 +88,11 @@
88 555 - we think it well and other stuff too - 5555
89 }
90 write_file_indented t32 {
91 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
92 111 - This is line one OF the demo program - 1111
93 ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
94 111 - This is line one of the demo program - 1111
95 ======= MERGED IN content follows ==================================
96 111 - This is line ONE of the demo program - 1111
97 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
98 222 - The second line program line in code - 2222
@@ -159,11 +159,11 @@
159 444 - If all goes well, we will be pleased - 4444
160 555 - we think it well and other stuff too - 5555
161 }
162 write_file_indented t32 {
163 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
164 ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
165 111 - This is line one of the demo program - 1111
166 ======= MERGED IN content follows ==================================
167 000 - Zero lines added to the beginning of - 0000
168 111 - This is line one of the demo program - 1111
169 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -174,11 +174,11 @@
174 }
175 write_file_indented t23 {
176 <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
177 000 - Zero lines added to the beginning of - 0000
178 111 - This is line one of the demo program - 1111
179 ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
180 111 - This is line one of the demo program - 1111
181 ======= MERGED IN content follows ==================================
182 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
183 222 - The second line program line in code - 2222
184 333 - This is a test of the merging algohm - 3333
@@ -306,11 +306,11 @@
306 qrst
307 uvwx
308 yzAB 2
309 CDEF 2
310 GHIJ 2
311 ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
312 efgh
313 ijkl
314 mnop
315 qrst
316 uvwx
@@ -374,11 +374,11 @@
374 qrst
375 uvwx
376 yzAB 2
377 CDEF 2
378 GHIJ 2
379 ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
380 efgh
381 ijkl
382 mnop
383 qrst
384 uvwx
385
--- test/merge3.test
+++ test/merge3.test
@@ -26,11 +26,11 @@
2626
write_file t3 [join [string trim $v2] \n]\n
2727
fossil 3-way-merge t1 t2 t3 t4
2828
set x [read_file t4]
2929
regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
3030
{MINE:} x
31
- regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x
31
+ regsub -all {\|\|\|\|\|\|\| COMMON ANCESTOR content follows \|+} $x {COM:} x
3232
regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
3333
regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x
3434
set x [split [string trim $x] \n]
3535
set result [string trim $result]
3636
if {$x!=$result} {
3737
--- test/merge3.test
+++ test/merge3.test
@@ -26,11 +26,11 @@
26 write_file t3 [join [string trim $v2] \n]\n
27 fossil 3-way-merge t1 t2 t3 t4
28 set x [read_file t4]
29 regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
30 {MINE:} x
31 regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x
32 regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
33 regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x
34 set x [split [string trim $x] \n]
35 set result [string trim $result]
36 if {$x!=$result} {
37
--- test/merge3.test
+++ test/merge3.test
@@ -26,11 +26,11 @@
26 write_file t3 [join [string trim $v2] \n]\n
27 fossil 3-way-merge t1 t2 t3 t4
28 set x [read_file t4]
29 regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
30 {MINE:} x
31 regsub -all {\|\|\|\|\|\|\| COMMON ANCESTOR content follows \|+} $x {COM:} x
32 regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
33 regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x
34 set x [split [string trim $x] \n]
35 set result [string trim $result]
36 if {$x!=$result} {
37
--- test/merge4.test
+++ test/merge4.test
@@ -26,31 +26,31 @@
2626
write_file t3 [join [string trim $v2] \n]\n
2727
fossil 3-way-merge t1 t2 t3 t4
2828
fossil 3-way-merge t1 t3 t2 t5
2929
set x [read_file t4]
3030
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
31
- regsub -all {=======.*=======} $x {=} x
31
+ regsub -all {\|\|\|\|\|\|\|.*=======} $x {=} x
3232
regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
3333
set x [split [string trim $x] \n]
3434
set y [read_file t5]
3535
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $y {>} y
36
- regsub -all {=======.*=======} $y {=} y
36
+ regsub -all {\|\|\|\|\|\|\|.*=======} $y {=} y
3737
regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y
3838
set y [split [string trim $y] \n]
3939
set result1 [string trim $result1]
4040
if {$x!=$result1} {
4141
protOut " Expected \[$result1\]"
4242
protOut " Got \[$x\]"
43
- test merge3-$testid 0
43
+ test merge4-$testid 0
4444
} else {
4545
set result2 [string trim $result2]
4646
if {$y!=$result2} {
4747
protOut " Expected \[$result2\]"
4848
protOut " Got \[$y\]"
49
- test merge3-$testid 0
49
+ test merge4-$testid 0
5050
} else {
51
- test merge3-$testid 1
51
+ test merge4-$testid 1
5252
}
5353
}
5454
}
5555
5656
merge-test 1000 {
5757
--- test/merge4.test
+++ test/merge4.test
@@ -26,31 +26,31 @@
26 write_file t3 [join [string trim $v2] \n]\n
27 fossil 3-way-merge t1 t2 t3 t4
28 fossil 3-way-merge t1 t3 t2 t5
29 set x [read_file t4]
30 regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
31 regsub -all {=======.*=======} $x {=} x
32 regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
33 set x [split [string trim $x] \n]
34 set y [read_file t5]
35 regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $y {>} y
36 regsub -all {=======.*=======} $y {=} y
37 regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y
38 set y [split [string trim $y] \n]
39 set result1 [string trim $result1]
40 if {$x!=$result1} {
41 protOut " Expected \[$result1\]"
42 protOut " Got \[$x\]"
43 test merge3-$testid 0
44 } else {
45 set result2 [string trim $result2]
46 if {$y!=$result2} {
47 protOut " Expected \[$result2\]"
48 protOut " Got \[$y\]"
49 test merge3-$testid 0
50 } else {
51 test merge3-$testid 1
52 }
53 }
54 }
55
56 merge-test 1000 {
57
--- test/merge4.test
+++ test/merge4.test
@@ -26,31 +26,31 @@
26 write_file t3 [join [string trim $v2] \n]\n
27 fossil 3-way-merge t1 t2 t3 t4
28 fossil 3-way-merge t1 t3 t2 t5
29 set x [read_file t4]
30 regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
31 regsub -all {\|\|\|\|\|\|\|.*=======} $x {=} x
32 regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
33 set x [split [string trim $x] \n]
34 set y [read_file t5]
35 regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $y {>} y
36 regsub -all {\|\|\|\|\|\|\|.*=======} $y {=} y
37 regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y
38 set y [split [string trim $y] \n]
39 set result1 [string trim $result1]
40 if {$x!=$result1} {
41 protOut " Expected \[$result1\]"
42 protOut " Got \[$x\]"
43 test merge4-$testid 0
44 } else {
45 set result2 [string trim $result2]
46 if {$y!=$result2} {
47 protOut " Expected \[$result2\]"
48 protOut " Got \[$y\]"
49 test merge4-$testid 0
50 } else {
51 test merge4-$testid 1
52 }
53 }
54 }
55
56 merge-test 1000 {
57
--- test/tester.tcl
+++ test/tester.tcl
@@ -334,10 +334,11 @@
334334
proxy \
335335
redirect-to-https \
336336
relative-paths \
337337
repo-cksum \
338338
repolist-skin \
339
+ safe-html \
339340
self-register \
340341
ssh-command \
341342
ssl-ca-location \
342343
ssl-identity \
343344
tclsh \
344345
--- test/tester.tcl
+++ test/tester.tcl
@@ -334,10 +334,11 @@
334 proxy \
335 redirect-to-https \
336 relative-paths \
337 repo-cksum \
338 repolist-skin \
 
339 self-register \
340 ssh-command \
341 ssl-ca-location \
342 ssl-identity \
343 tclsh \
344
--- test/tester.tcl
+++ test/tester.tcl
@@ -334,10 +334,11 @@
334 proxy \
335 redirect-to-https \
336 relative-paths \
337 repo-cksum \
338 repolist-skin \
339 safe-html \
340 self-register \
341 ssh-command \
342 ssl-ca-location \
343 ssl-identity \
344 tclsh \
345
--- test/wiki.test
+++ test/wiki.test
@@ -17,10 +17,16 @@
1717
#
1818
# Test wiki and attachment command Support
1919
#
2020
2121
test_setup
22
+
23
+# Disable backoffice for this test, otherwise its process lingers for some
24
+# time after the test has completed.
25
+# Perhaps, this should be done in test_setup and enabled explicitly only
26
+# when needed.
27
+fossil set backoffice-disable 1
2228
2329
# Return true if two files are similar (i.e. not only compress trailing spaces
2430
# from a line, but remove any final LF from the file as well)
2531
proc similar_file {a b} {
2632
set x ""
2733
--- test/wiki.test
+++ test/wiki.test
@@ -17,10 +17,16 @@
17 #
18 # Test wiki and attachment command Support
19 #
20
21 test_setup
 
 
 
 
 
 
22
23 # Return true if two files are similar (i.e. not only compress trailing spaces
24 # from a line, but remove any final LF from the file as well)
25 proc similar_file {a b} {
26 set x ""
27
--- test/wiki.test
+++ test/wiki.test
@@ -17,10 +17,16 @@
17 #
18 # Test wiki and attachment command Support
19 #
20
21 test_setup
22
23 # Disable backoffice for this test, otherwise its process lingers for some
24 # time after the test has completed.
25 # Perhaps, this should be done in test_setup and enabled explicitly only
26 # when needed.
27 fossil set backoffice-disable 1
28
29 # Return true if two files are similar (i.e. not only compress trailing spaces
30 # from a line, but remove any final LF from the file as well)
31 proc similar_file {a b} {
32 set x ""
33
+4 -10
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
2828
2929
SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
3030
3131
SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
3232
33
-SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
33
+SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c
3434
35
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
35
+OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
3636
3737
3838
RC=$(DMDIR)\bin\rcc
3939
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
4040
@@ -49,11 +49,11 @@
4949
5050
$(OBJDIR)\fossil.res: $B\win\fossil.rc
5151
$(RC) $(RCFLAGS) -o$@ $**
5252
5353
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54
- +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
54
+ +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@
5555
+echo fossil >> $@
5656
+echo fossil >> $@
5757
+echo $(LIBS) >> $@
5858
+echo. >> $@
5959
+echo fossil >> $@
@@ -962,16 +962,10 @@
962962
$(TCC) -o$@ -c winhttp_.c
963963
964964
winhttp_.c : $(SRCDIR)\winhttp.c
965965
+translate$E $** > $@
966966
967
-$(OBJDIR)\wysiwyg$O : wysiwyg_.c wysiwyg.h
968
- $(TCC) -o$@ -c wysiwyg_.c
969
-
970
-wysiwyg_.c : $(SRCDIR)\wysiwyg.c
971
- +translate$E $** > $@
972
-
973967
$(OBJDIR)\xfer$O : xfer_.c xfer.h
974968
$(TCC) -o$@ -c xfer_.c
975969
976970
xfer_.c : $(SRCDIR)\xfer.c
977971
+translate$E $** > $@
@@ -987,7 +981,7 @@
987981
988982
zip_.c : $(SRCDIR)\zip.c
989983
+translate$E $** > $@
990984
991985
headers: makeheaders$E page_index.h builtin_data.h VERSION.h
992
- +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
986
+ +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
993987
@copy /Y nul: headers
994988
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
30
31 SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -962,16 +962,10 @@
962 $(TCC) -o$@ -c winhttp_.c
963
964 winhttp_.c : $(SRCDIR)\winhttp.c
965 +translate$E $** > $@
966
967 $(OBJDIR)\wysiwyg$O : wysiwyg_.c wysiwyg.h
968 $(TCC) -o$@ -c wysiwyg_.c
969
970 wysiwyg_.c : $(SRCDIR)\wysiwyg.c
971 +translate$E $** > $@
972
973 $(OBJDIR)\xfer$O : xfer_.c xfer.h
974 $(TCC) -o$@ -c xfer_.c
975
976 xfer_.c : $(SRCDIR)\xfer.c
977 +translate$E $** > $@
@@ -987,7 +981,7 @@
987
988 zip_.c : $(SRCDIR)\zip.c
989 +translate$E $** > $@
990
991 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
992 +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
993 @copy /Y nul: headers
994
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
30
31 SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -962,16 +962,10 @@
962 $(TCC) -o$@ -c winhttp_.c
963
964 winhttp_.c : $(SRCDIR)\winhttp.c
965 +translate$E $** > $@
966
 
 
 
 
 
 
967 $(OBJDIR)\xfer$O : xfer_.c xfer.h
968 $(TCC) -o$@ -c xfer_.c
969
970 xfer_.c : $(SRCDIR)\xfer.c
971 +translate$E $** > $@
@@ -987,7 +981,7 @@
981
982 zip_.c : $(SRCDIR)\zip.c
983 +translate$E $** > $@
984
985 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
986 +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
987 @copy /Y nul: headers
988
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -566,11 +566,10 @@
566566
$(SRCDIR)/webmail.c \
567567
$(SRCDIR)/wiki.c \
568568
$(SRCDIR)/wikiformat.c \
569569
$(SRCDIR)/winfile.c \
570570
$(SRCDIR)/winhttp.c \
571
- $(SRCDIR)/wysiwyg.c \
572571
$(SRCDIR)/xfer.c \
573572
$(SRCDIR)/xfersetup.c \
574573
$(SRCDIR)/zip.c
575574
576575
EXTRA_FILES = \
@@ -636,14 +635,18 @@
636635
$(SRCDIR)/default.css \
637636
$(SRCDIR)/diff.tcl \
638637
$(SRCDIR)/forum.js \
639638
$(SRCDIR)/fossil.bootstrap.js \
640639
$(SRCDIR)/fossil.confirmer.js \
640
+ $(SRCDIR)/fossil.copybutton.js \
641641
$(SRCDIR)/fossil.dom.js \
642642
$(SRCDIR)/fossil.fetch.js \
643
+ $(SRCDIR)/fossil.numbered-lines.js \
643644
$(SRCDIR)/fossil.page.fileedit.js \
644645
$(SRCDIR)/fossil.page.forumpost.js \
646
+ $(SRCDIR)/fossil.page.wikiedit.js \
647
+ $(SRCDIR)/fossil.popupwidget.js \
645648
$(SRCDIR)/fossil.storage.js \
646649
$(SRCDIR)/fossil.tabs.js \
647650
$(SRCDIR)/graph.js \
648651
$(SRCDIR)/href.js \
649652
$(SRCDIR)/login.js \
@@ -669,10 +672,11 @@
669672
$(SRCDIR)/sounds/d.wav \
670673
$(SRCDIR)/sounds/e.wav \
671674
$(SRCDIR)/sounds/f.wav \
672675
$(SRCDIR)/style.admin_log.css \
673676
$(SRCDIR)/style.fileedit.css \
677
+ $(SRCDIR)/style.wikiedit.css \
674678
$(SRCDIR)/tree.js \
675679
$(SRCDIR)/useredit.js \
676680
$(SRCDIR)/wiki.wiki
677681
678682
TRANS_SRC = \
@@ -814,11 +818,10 @@
814818
$(OBJDIR)/webmail_.c \
815819
$(OBJDIR)/wiki_.c \
816820
$(OBJDIR)/wikiformat_.c \
817821
$(OBJDIR)/winfile_.c \
818822
$(OBJDIR)/winhttp_.c \
819
- $(OBJDIR)/wysiwyg_.c \
820823
$(OBJDIR)/xfer_.c \
821824
$(OBJDIR)/xfersetup_.c \
822825
$(OBJDIR)/zip_.c
823826
824827
OBJ = \
@@ -960,11 +963,10 @@
960963
$(OBJDIR)/webmail.o \
961964
$(OBJDIR)/wiki.o \
962965
$(OBJDIR)/wikiformat.o \
963966
$(OBJDIR)/winfile.o \
964967
$(OBJDIR)/winhttp.o \
965
- $(OBJDIR)/wysiwyg.o \
966968
$(OBJDIR)/xfer.o \
967969
$(OBJDIR)/xfersetup.o \
968970
$(OBJDIR)/zip.o
969971
970972
APPNAME = fossil.exe
@@ -1061,13 +1063,16 @@
10611063
# build is done from, i.e. the checkout belongs to. Do not sync/push
10621064
# the repository after running the tests.
10631065
test: $(OBJDIR) $(APPNAME)
10641066
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
10651067
1066
-$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION)
1068
+$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(OBJDIR)/phony.h
10671069
$(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@
10681070
1071
+$(OBJDIR)/phony.h:
1072
+ # Force rebuild of VERSION.h every time "make" is run
1073
+
10691074
# The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
10701075
# to 1. If it is set to 1, then there is no need to build or link
10711076
# the sqlite3.o object. Instead, the system SQLite will be linked
10721077
# using -lsqlite3.
10731078
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
@@ -1318,11 +1323,10 @@
13181323
$(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \
13191324
$(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
13201325
$(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
13211326
$(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \
13221327
$(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
1323
- $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \
13241328
$(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \
13251329
$(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \
13261330
$(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \
13271331
$(SRCDIR)/sqlite3.h \
13281332
$(SRCDIR)/th.h \
@@ -2451,18 +2455,10 @@
24512455
$(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h
24522456
$(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c
24532457
24542458
$(OBJDIR)/winhttp.h: $(OBJDIR)/headers
24552459
2456
-$(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(TRANSLATE)
2457
- $(TRANSLATE) $(SRCDIR)/wysiwyg.c >$@
2458
-
2459
-$(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h
2460
- $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c
2461
-
2462
-$(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers
2463
-
24642460
$(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE)
24652461
$(TRANSLATE) $(SRCDIR)/xfer.c >$@
24662462
24672463
$(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h
24682464
$(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c
24692465
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -566,11 +566,10 @@
566 $(SRCDIR)/webmail.c \
567 $(SRCDIR)/wiki.c \
568 $(SRCDIR)/wikiformat.c \
569 $(SRCDIR)/winfile.c \
570 $(SRCDIR)/winhttp.c \
571 $(SRCDIR)/wysiwyg.c \
572 $(SRCDIR)/xfer.c \
573 $(SRCDIR)/xfersetup.c \
574 $(SRCDIR)/zip.c
575
576 EXTRA_FILES = \
@@ -636,14 +635,18 @@
636 $(SRCDIR)/default.css \
637 $(SRCDIR)/diff.tcl \
638 $(SRCDIR)/forum.js \
639 $(SRCDIR)/fossil.bootstrap.js \
640 $(SRCDIR)/fossil.confirmer.js \
 
641 $(SRCDIR)/fossil.dom.js \
642 $(SRCDIR)/fossil.fetch.js \
 
643 $(SRCDIR)/fossil.page.fileedit.js \
644 $(SRCDIR)/fossil.page.forumpost.js \
 
 
645 $(SRCDIR)/fossil.storage.js \
646 $(SRCDIR)/fossil.tabs.js \
647 $(SRCDIR)/graph.js \
648 $(SRCDIR)/href.js \
649 $(SRCDIR)/login.js \
@@ -669,10 +672,11 @@
669 $(SRCDIR)/sounds/d.wav \
670 $(SRCDIR)/sounds/e.wav \
671 $(SRCDIR)/sounds/f.wav \
672 $(SRCDIR)/style.admin_log.css \
673 $(SRCDIR)/style.fileedit.css \
 
674 $(SRCDIR)/tree.js \
675 $(SRCDIR)/useredit.js \
676 $(SRCDIR)/wiki.wiki
677
678 TRANS_SRC = \
@@ -814,11 +818,10 @@
814 $(OBJDIR)/webmail_.c \
815 $(OBJDIR)/wiki_.c \
816 $(OBJDIR)/wikiformat_.c \
817 $(OBJDIR)/winfile_.c \
818 $(OBJDIR)/winhttp_.c \
819 $(OBJDIR)/wysiwyg_.c \
820 $(OBJDIR)/xfer_.c \
821 $(OBJDIR)/xfersetup_.c \
822 $(OBJDIR)/zip_.c
823
824 OBJ = \
@@ -960,11 +963,10 @@
960 $(OBJDIR)/webmail.o \
961 $(OBJDIR)/wiki.o \
962 $(OBJDIR)/wikiformat.o \
963 $(OBJDIR)/winfile.o \
964 $(OBJDIR)/winhttp.o \
965 $(OBJDIR)/wysiwyg.o \
966 $(OBJDIR)/xfer.o \
967 $(OBJDIR)/xfersetup.o \
968 $(OBJDIR)/zip.o
969
970 APPNAME = fossil.exe
@@ -1061,13 +1063,16 @@
1061 # build is done from, i.e. the checkout belongs to. Do not sync/push
1062 # the repository after running the tests.
1063 test: $(OBJDIR) $(APPNAME)
1064 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
1065
1066 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION)
1067 $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@
1068
 
 
 
1069 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
1070 # to 1. If it is set to 1, then there is no need to build or link
1071 # the sqlite3.o object. Instead, the system SQLite will be linked
1072 # using -lsqlite3.
1073 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
@@ -1318,11 +1323,10 @@
1318 $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \
1319 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
1320 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
1321 $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \
1322 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
1323 $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \
1324 $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \
1325 $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \
1326 $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \
1327 $(SRCDIR)/sqlite3.h \
1328 $(SRCDIR)/th.h \
@@ -2451,18 +2455,10 @@
2451 $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h
2452 $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c
2453
2454 $(OBJDIR)/winhttp.h: $(OBJDIR)/headers
2455
2456 $(OBJDIR)/wysiwyg_.c: $(SRCDIR)/wysiwyg.c $(TRANSLATE)
2457 $(TRANSLATE) $(SRCDIR)/wysiwyg.c >$@
2458
2459 $(OBJDIR)/wysiwyg.o: $(OBJDIR)/wysiwyg_.c $(OBJDIR)/wysiwyg.h $(SRCDIR)/config.h
2460 $(XTCC) -o $(OBJDIR)/wysiwyg.o -c $(OBJDIR)/wysiwyg_.c
2461
2462 $(OBJDIR)/wysiwyg.h: $(OBJDIR)/headers
2463
2464 $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE)
2465 $(TRANSLATE) $(SRCDIR)/xfer.c >$@
2466
2467 $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h
2468 $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c
2469
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -566,11 +566,10 @@
566 $(SRCDIR)/webmail.c \
567 $(SRCDIR)/wiki.c \
568 $(SRCDIR)/wikiformat.c \
569 $(SRCDIR)/winfile.c \
570 $(SRCDIR)/winhttp.c \
 
571 $(SRCDIR)/xfer.c \
572 $(SRCDIR)/xfersetup.c \
573 $(SRCDIR)/zip.c
574
575 EXTRA_FILES = \
@@ -636,14 +635,18 @@
635 $(SRCDIR)/default.css \
636 $(SRCDIR)/diff.tcl \
637 $(SRCDIR)/forum.js \
638 $(SRCDIR)/fossil.bootstrap.js \
639 $(SRCDIR)/fossil.confirmer.js \
640 $(SRCDIR)/fossil.copybutton.js \
641 $(SRCDIR)/fossil.dom.js \
642 $(SRCDIR)/fossil.fetch.js \
643 $(SRCDIR)/fossil.numbered-lines.js \
644 $(SRCDIR)/fossil.page.fileedit.js \
645 $(SRCDIR)/fossil.page.forumpost.js \
646 $(SRCDIR)/fossil.page.wikiedit.js \
647 $(SRCDIR)/fossil.popupwidget.js \
648 $(SRCDIR)/fossil.storage.js \
649 $(SRCDIR)/fossil.tabs.js \
650 $(SRCDIR)/graph.js \
651 $(SRCDIR)/href.js \
652 $(SRCDIR)/login.js \
@@ -669,10 +672,11 @@
672 $(SRCDIR)/sounds/d.wav \
673 $(SRCDIR)/sounds/e.wav \
674 $(SRCDIR)/sounds/f.wav \
675 $(SRCDIR)/style.admin_log.css \
676 $(SRCDIR)/style.fileedit.css \
677 $(SRCDIR)/style.wikiedit.css \
678 $(SRCDIR)/tree.js \
679 $(SRCDIR)/useredit.js \
680 $(SRCDIR)/wiki.wiki
681
682 TRANS_SRC = \
@@ -814,11 +818,10 @@
818 $(OBJDIR)/webmail_.c \
819 $(OBJDIR)/wiki_.c \
820 $(OBJDIR)/wikiformat_.c \
821 $(OBJDIR)/winfile_.c \
822 $(OBJDIR)/winhttp_.c \
 
823 $(OBJDIR)/xfer_.c \
824 $(OBJDIR)/xfersetup_.c \
825 $(OBJDIR)/zip_.c
826
827 OBJ = \
@@ -960,11 +963,10 @@
963 $(OBJDIR)/webmail.o \
964 $(OBJDIR)/wiki.o \
965 $(OBJDIR)/wikiformat.o \
966 $(OBJDIR)/winfile.o \
967 $(OBJDIR)/winhttp.o \
 
968 $(OBJDIR)/xfer.o \
969 $(OBJDIR)/xfersetup.o \
970 $(OBJDIR)/zip.o
971
972 APPNAME = fossil.exe
@@ -1061,13 +1063,16 @@
1063 # build is done from, i.e. the checkout belongs to. Do not sync/push
1064 # the repository after running the tests.
1065 test: $(OBJDIR) $(APPNAME)
1066 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
1067
1068 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(MKVERSION) $(OBJDIR)/phony.h
1069 $(MKVERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$@
1070
1071 $(OBJDIR)/phony.h:
1072 # Force rebuild of VERSION.h every time "make" is run
1073
1074 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
1075 # to 1. If it is set to 1, then there is no need to build or link
1076 # the sqlite3.o object. Instead, the system SQLite will be linked
1077 # using -lsqlite3.
1078 SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
@@ -1318,11 +1323,10 @@
1323 $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \
1324 $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \
1325 $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \
1326 $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \
1327 $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \
 
1328 $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \
1329 $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \
1330 $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \
1331 $(SRCDIR)/sqlite3.h \
1332 $(SRCDIR)/th.h \
@@ -2451,18 +2455,10 @@
2455 $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h
2456 $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c
2457
2458 $(OBJDIR)/winhttp.h: $(OBJDIR)/headers
2459
 
 
 
 
 
 
 
 
2460 $(OBJDIR)/xfer_.c: $(SRCDIR)/xfer.c $(TRANSLATE)
2461 $(TRANSLATE) $(SRCDIR)/xfer.c >$@
2462
2463 $(OBJDIR)/xfer.o: $(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h $(SRCDIR)/config.h
2464 $(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c
2465
+15 -12
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -488,11 +488,10 @@
488488
"$(OX)\webmail_.c" \
489489
"$(OX)\wiki_.c" \
490490
"$(OX)\wikiformat_.c" \
491491
"$(OX)\winfile_.c" \
492492
"$(OX)\winhttp_.c" \
493
- "$(OX)\wysiwyg_.c" \
494493
"$(OX)\xfer_.c" \
495494
"$(OX)\xfersetup_.c" \
496495
"$(OX)\zip_.c"
497496
498497
EXTRA_FILES = "$(SRCDIR)\..\skins\aht\details.txt" \
@@ -557,14 +556,18 @@
557556
"$(SRCDIR)\default.css" \
558557
"$(SRCDIR)\diff.tcl" \
559558
"$(SRCDIR)\forum.js" \
560559
"$(SRCDIR)\fossil.bootstrap.js" \
561560
"$(SRCDIR)\fossil.confirmer.js" \
561
+ "$(SRCDIR)\fossil.copybutton.js" \
562562
"$(SRCDIR)\fossil.dom.js" \
563563
"$(SRCDIR)\fossil.fetch.js" \
564
+ "$(SRCDIR)\fossil.numbered-lines.js" \
564565
"$(SRCDIR)\fossil.page.fileedit.js" \
565566
"$(SRCDIR)\fossil.page.forumpost.js" \
567
+ "$(SRCDIR)\fossil.page.wikiedit.js" \
568
+ "$(SRCDIR)\fossil.popupwidget.js" \
566569
"$(SRCDIR)\fossil.storage.js" \
567570
"$(SRCDIR)\fossil.tabs.js" \
568571
"$(SRCDIR)\graph.js" \
569572
"$(SRCDIR)\href.js" \
570573
"$(SRCDIR)\login.js" \
@@ -590,10 +593,11 @@
590593
"$(SRCDIR)\sounds\d.wav" \
591594
"$(SRCDIR)\sounds\e.wav" \
592595
"$(SRCDIR)\sounds\f.wav" \
593596
"$(SRCDIR)\style.admin_log.css" \
594597
"$(SRCDIR)\style.fileedit.css" \
598
+ "$(SRCDIR)\style.wikiedit.css" \
595599
"$(SRCDIR)\tree.js" \
596600
"$(SRCDIR)\useredit.js" \
597601
"$(SRCDIR)\wiki.wiki"
598602
599603
OBJ = "$(OX)\add$O" \
@@ -740,11 +744,10 @@
740744
"$(OX)\webmail$O" \
741745
"$(OX)\wiki$O" \
742746
"$(OX)\wikiformat$O" \
743747
"$(OX)\winfile$O" \
744748
"$(OX)\winhttp$O" \
745
- "$(OX)\wysiwyg$O" \
746749
"$(OX)\xfer$O" \
747750
"$(OX)\xfersetup$O" \
748751
"$(OX)\zip$O" \
749752
!if $(FOSSIL_ENABLE_MINIZ)!=0
750753
"$(OX)\miniz$O" \
@@ -967,11 +970,10 @@
967970
echo "$(OX)\webmail.obj" >> $@
968971
echo "$(OX)\wiki.obj" >> $@
969972
echo "$(OX)\wikiformat.obj" >> $@
970973
echo "$(OX)\winfile.obj" >> $@
971974
echo "$(OX)\winhttp.obj" >> $@
972
- echo "$(OX)\wysiwyg.obj" >> $@
973975
echo "$(OX)\xfer.obj" >> $@
974976
echo "$(OX)\xfersetup.obj" >> $@
975977
echo "$(OX)\zip.obj" >> $@
976978
!if $(FOSSIL_ENABLE_MINIZ)!=0
977979
echo "$(OX)\miniz.obj" >> $@
@@ -1022,12 +1024,15 @@
10221024
$(TCC) /Fo$@ /Fd$(@D)\ -c $**
10231025
10241026
"$(OX)\miniz$O" : "$(SRCDIR)\miniz.c"
10251027
$(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $**
10261028
1027
-"$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION"
1028
- $** > $@
1029
+"$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" "$(B)\phony.h"
1030
+ "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" > $@
1031
+
1032
+"$(B)\phony.h" :
1033
+ rem Force rebuild of VERSION.h whenever nmake is run
10291034
10301035
"$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c"
10311036
$(TCC) /Fo$@ /Fd$(@D)\ -c $**
10321037
10331038
"$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC)
@@ -1148,14 +1153,18 @@
11481153
echo "$(SRCDIR)\default.css" >> $@
11491154
echo "$(SRCDIR)\diff.tcl" >> $@
11501155
echo "$(SRCDIR)\forum.js" >> $@
11511156
echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
11521157
echo "$(SRCDIR)\fossil.confirmer.js" >> $@
1158
+ echo "$(SRCDIR)\fossil.copybutton.js" >> $@
11531159
echo "$(SRCDIR)\fossil.dom.js" >> $@
11541160
echo "$(SRCDIR)\fossil.fetch.js" >> $@
1161
+ echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
11551162
echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
11561163
echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
1164
+ echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
1165
+ echo "$(SRCDIR)\fossil.popupwidget.js" >> $@
11571166
echo "$(SRCDIR)\fossil.storage.js" >> $@
11581167
echo "$(SRCDIR)\fossil.tabs.js" >> $@
11591168
echo "$(SRCDIR)\graph.js" >> $@
11601169
echo "$(SRCDIR)\href.js" >> $@
11611170
echo "$(SRCDIR)\login.js" >> $@
@@ -1181,10 +1190,11 @@
11811190
echo "$(SRCDIR)\sounds/d.wav" >> $@
11821191
echo "$(SRCDIR)\sounds/e.wav" >> $@
11831192
echo "$(SRCDIR)\sounds/f.wav" >> $@
11841193
echo "$(SRCDIR)\style.admin_log.css" >> $@
11851194
echo "$(SRCDIR)\style.fileedit.css" >> $@
1195
+ echo "$(SRCDIR)\style.wikiedit.css" >> $@
11861196
echo "$(SRCDIR)\tree.js" >> $@
11871197
echo "$(SRCDIR)\useredit.js" >> $@
11881198
echo "$(SRCDIR)\wiki.wiki" >> $@
11891199
11901200
"$(OX)\add$O" : "$(OX)\add_.c" "$(OX)\add.h"
@@ -2025,16 +2035,10 @@
20252035
$(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\winhttp_.c"
20262036
20272037
"$(OX)\winhttp_.c" : "$(SRCDIR)\winhttp.c"
20282038
"$(OBJDIR)\translate$E" $** > $@
20292039
2030
-"$(OX)\wysiwyg$O" : "$(OX)\wysiwyg_.c" "$(OX)\wysiwyg.h"
2031
- $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\wysiwyg_.c"
2032
-
2033
-"$(OX)\wysiwyg_.c" : "$(SRCDIR)\wysiwyg.c"
2034
- "$(OBJDIR)\translate$E" $** > $@
2035
-
20362040
"$(OX)\xfer$O" : "$(OX)\xfer_.c" "$(OX)\xfer.h"
20372041
$(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\xfer_.c"
20382042
20392043
"$(OX)\xfer_.c" : "$(SRCDIR)\xfer.c"
20402044
"$(OBJDIR)\translate$E" $** > $@
@@ -2193,14 +2197,13 @@
21932197
"$(OX)\webmail_.c":"$(OX)\webmail.h" \
21942198
"$(OX)\wiki_.c":"$(OX)\wiki.h" \
21952199
"$(OX)\wikiformat_.c":"$(OX)\wikiformat.h" \
21962200
"$(OX)\winfile_.c":"$(OX)\winfile.h" \
21972201
"$(OX)\winhttp_.c":"$(OX)\winhttp.h" \
2198
- "$(OX)\wysiwyg_.c":"$(OX)\wysiwyg.h" \
21992202
"$(OX)\xfer_.c":"$(OX)\xfer.h" \
22002203
"$(OX)\xfersetup_.c":"$(OX)\xfersetup.h" \
22012204
"$(OX)\zip_.c":"$(OX)\zip.h" \
22022205
"$(SRCDIR)\sqlite3.h" \
22032206
"$(SRCDIR)\th.h" \
22042207
"$(OX)\VERSION.h" \
22052208
"$(SRCDIR)\cson_amalgamation.h"
22062209
@copy /Y nul: $@
22072210
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -488,11 +488,10 @@
488 "$(OX)\webmail_.c" \
489 "$(OX)\wiki_.c" \
490 "$(OX)\wikiformat_.c" \
491 "$(OX)\winfile_.c" \
492 "$(OX)\winhttp_.c" \
493 "$(OX)\wysiwyg_.c" \
494 "$(OX)\xfer_.c" \
495 "$(OX)\xfersetup_.c" \
496 "$(OX)\zip_.c"
497
498 EXTRA_FILES = "$(SRCDIR)\..\skins\aht\details.txt" \
@@ -557,14 +556,18 @@
557 "$(SRCDIR)\default.css" \
558 "$(SRCDIR)\diff.tcl" \
559 "$(SRCDIR)\forum.js" \
560 "$(SRCDIR)\fossil.bootstrap.js" \
561 "$(SRCDIR)\fossil.confirmer.js" \
 
562 "$(SRCDIR)\fossil.dom.js" \
563 "$(SRCDIR)\fossil.fetch.js" \
 
564 "$(SRCDIR)\fossil.page.fileedit.js" \
565 "$(SRCDIR)\fossil.page.forumpost.js" \
 
 
566 "$(SRCDIR)\fossil.storage.js" \
567 "$(SRCDIR)\fossil.tabs.js" \
568 "$(SRCDIR)\graph.js" \
569 "$(SRCDIR)\href.js" \
570 "$(SRCDIR)\login.js" \
@@ -590,10 +593,11 @@
590 "$(SRCDIR)\sounds\d.wav" \
591 "$(SRCDIR)\sounds\e.wav" \
592 "$(SRCDIR)\sounds\f.wav" \
593 "$(SRCDIR)\style.admin_log.css" \
594 "$(SRCDIR)\style.fileedit.css" \
 
595 "$(SRCDIR)\tree.js" \
596 "$(SRCDIR)\useredit.js" \
597 "$(SRCDIR)\wiki.wiki"
598
599 OBJ = "$(OX)\add$O" \
@@ -740,11 +744,10 @@
740 "$(OX)\webmail$O" \
741 "$(OX)\wiki$O" \
742 "$(OX)\wikiformat$O" \
743 "$(OX)\winfile$O" \
744 "$(OX)\winhttp$O" \
745 "$(OX)\wysiwyg$O" \
746 "$(OX)\xfer$O" \
747 "$(OX)\xfersetup$O" \
748 "$(OX)\zip$O" \
749 !if $(FOSSIL_ENABLE_MINIZ)!=0
750 "$(OX)\miniz$O" \
@@ -967,11 +970,10 @@
967 echo "$(OX)\webmail.obj" >> $@
968 echo "$(OX)\wiki.obj" >> $@
969 echo "$(OX)\wikiformat.obj" >> $@
970 echo "$(OX)\winfile.obj" >> $@
971 echo "$(OX)\winhttp.obj" >> $@
972 echo "$(OX)\wysiwyg.obj" >> $@
973 echo "$(OX)\xfer.obj" >> $@
974 echo "$(OX)\xfersetup.obj" >> $@
975 echo "$(OX)\zip.obj" >> $@
976 !if $(FOSSIL_ENABLE_MINIZ)!=0
977 echo "$(OX)\miniz.obj" >> $@
@@ -1022,12 +1024,15 @@
1022 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1023
1024 "$(OX)\miniz$O" : "$(SRCDIR)\miniz.c"
1025 $(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $**
1026
1027 "$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION"
1028 $** > $@
 
 
 
1029
1030 "$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c"
1031 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1032
1033 "$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC)
@@ -1148,14 +1153,18 @@
1148 echo "$(SRCDIR)\default.css" >> $@
1149 echo "$(SRCDIR)\diff.tcl" >> $@
1150 echo "$(SRCDIR)\forum.js" >> $@
1151 echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
1152 echo "$(SRCDIR)\fossil.confirmer.js" >> $@
 
1153 echo "$(SRCDIR)\fossil.dom.js" >> $@
1154 echo "$(SRCDIR)\fossil.fetch.js" >> $@
 
1155 echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
1156 echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
 
 
1157 echo "$(SRCDIR)\fossil.storage.js" >> $@
1158 echo "$(SRCDIR)\fossil.tabs.js" >> $@
1159 echo "$(SRCDIR)\graph.js" >> $@
1160 echo "$(SRCDIR)\href.js" >> $@
1161 echo "$(SRCDIR)\login.js" >> $@
@@ -1181,10 +1190,11 @@
1181 echo "$(SRCDIR)\sounds/d.wav" >> $@
1182 echo "$(SRCDIR)\sounds/e.wav" >> $@
1183 echo "$(SRCDIR)\sounds/f.wav" >> $@
1184 echo "$(SRCDIR)\style.admin_log.css" >> $@
1185 echo "$(SRCDIR)\style.fileedit.css" >> $@
 
1186 echo "$(SRCDIR)\tree.js" >> $@
1187 echo "$(SRCDIR)\useredit.js" >> $@
1188 echo "$(SRCDIR)\wiki.wiki" >> $@
1189
1190 "$(OX)\add$O" : "$(OX)\add_.c" "$(OX)\add.h"
@@ -2025,16 +2035,10 @@
2025 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\winhttp_.c"
2026
2027 "$(OX)\winhttp_.c" : "$(SRCDIR)\winhttp.c"
2028 "$(OBJDIR)\translate$E" $** > $@
2029
2030 "$(OX)\wysiwyg$O" : "$(OX)\wysiwyg_.c" "$(OX)\wysiwyg.h"
2031 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\wysiwyg_.c"
2032
2033 "$(OX)\wysiwyg_.c" : "$(SRCDIR)\wysiwyg.c"
2034 "$(OBJDIR)\translate$E" $** > $@
2035
2036 "$(OX)\xfer$O" : "$(OX)\xfer_.c" "$(OX)\xfer.h"
2037 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\xfer_.c"
2038
2039 "$(OX)\xfer_.c" : "$(SRCDIR)\xfer.c"
2040 "$(OBJDIR)\translate$E" $** > $@
@@ -2193,14 +2197,13 @@
2193 "$(OX)\webmail_.c":"$(OX)\webmail.h" \
2194 "$(OX)\wiki_.c":"$(OX)\wiki.h" \
2195 "$(OX)\wikiformat_.c":"$(OX)\wikiformat.h" \
2196 "$(OX)\winfile_.c":"$(OX)\winfile.h" \
2197 "$(OX)\winhttp_.c":"$(OX)\winhttp.h" \
2198 "$(OX)\wysiwyg_.c":"$(OX)\wysiwyg.h" \
2199 "$(OX)\xfer_.c":"$(OX)\xfer.h" \
2200 "$(OX)\xfersetup_.c":"$(OX)\xfersetup.h" \
2201 "$(OX)\zip_.c":"$(OX)\zip.h" \
2202 "$(SRCDIR)\sqlite3.h" \
2203 "$(SRCDIR)\th.h" \
2204 "$(OX)\VERSION.h" \
2205 "$(SRCDIR)\cson_amalgamation.h"
2206 @copy /Y nul: $@
2207
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -488,11 +488,10 @@
488 "$(OX)\webmail_.c" \
489 "$(OX)\wiki_.c" \
490 "$(OX)\wikiformat_.c" \
491 "$(OX)\winfile_.c" \
492 "$(OX)\winhttp_.c" \
 
493 "$(OX)\xfer_.c" \
494 "$(OX)\xfersetup_.c" \
495 "$(OX)\zip_.c"
496
497 EXTRA_FILES = "$(SRCDIR)\..\skins\aht\details.txt" \
@@ -557,14 +556,18 @@
556 "$(SRCDIR)\default.css" \
557 "$(SRCDIR)\diff.tcl" \
558 "$(SRCDIR)\forum.js" \
559 "$(SRCDIR)\fossil.bootstrap.js" \
560 "$(SRCDIR)\fossil.confirmer.js" \
561 "$(SRCDIR)\fossil.copybutton.js" \
562 "$(SRCDIR)\fossil.dom.js" \
563 "$(SRCDIR)\fossil.fetch.js" \
564 "$(SRCDIR)\fossil.numbered-lines.js" \
565 "$(SRCDIR)\fossil.page.fileedit.js" \
566 "$(SRCDIR)\fossil.page.forumpost.js" \
567 "$(SRCDIR)\fossil.page.wikiedit.js" \
568 "$(SRCDIR)\fossil.popupwidget.js" \
569 "$(SRCDIR)\fossil.storage.js" \
570 "$(SRCDIR)\fossil.tabs.js" \
571 "$(SRCDIR)\graph.js" \
572 "$(SRCDIR)\href.js" \
573 "$(SRCDIR)\login.js" \
@@ -590,10 +593,11 @@
593 "$(SRCDIR)\sounds\d.wav" \
594 "$(SRCDIR)\sounds\e.wav" \
595 "$(SRCDIR)\sounds\f.wav" \
596 "$(SRCDIR)\style.admin_log.css" \
597 "$(SRCDIR)\style.fileedit.css" \
598 "$(SRCDIR)\style.wikiedit.css" \
599 "$(SRCDIR)\tree.js" \
600 "$(SRCDIR)\useredit.js" \
601 "$(SRCDIR)\wiki.wiki"
602
603 OBJ = "$(OX)\add$O" \
@@ -740,11 +744,10 @@
744 "$(OX)\webmail$O" \
745 "$(OX)\wiki$O" \
746 "$(OX)\wikiformat$O" \
747 "$(OX)\winfile$O" \
748 "$(OX)\winhttp$O" \
 
749 "$(OX)\xfer$O" \
750 "$(OX)\xfersetup$O" \
751 "$(OX)\zip$O" \
752 !if $(FOSSIL_ENABLE_MINIZ)!=0
753 "$(OX)\miniz$O" \
@@ -967,11 +970,10 @@
970 echo "$(OX)\webmail.obj" >> $@
971 echo "$(OX)\wiki.obj" >> $@
972 echo "$(OX)\wikiformat.obj" >> $@
973 echo "$(OX)\winfile.obj" >> $@
974 echo "$(OX)\winhttp.obj" >> $@
 
975 echo "$(OX)\xfer.obj" >> $@
976 echo "$(OX)\xfersetup.obj" >> $@
977 echo "$(OX)\zip.obj" >> $@
978 !if $(FOSSIL_ENABLE_MINIZ)!=0
979 echo "$(OX)\miniz.obj" >> $@
@@ -1022,12 +1024,15 @@
1024 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1025
1026 "$(OX)\miniz$O" : "$(SRCDIR)\miniz.c"
1027 $(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $**
1028
1029 "$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" "$(B)\phony.h"
1030 "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" > $@
1031
1032 "$(B)\phony.h" :
1033 rem Force rebuild of VERSION.h whenever nmake is run
1034
1035 "$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c"
1036 $(TCC) /Fo$@ /Fd$(@D)\ -c $**
1037
1038 "$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC)
@@ -1148,14 +1153,18 @@
1153 echo "$(SRCDIR)\default.css" >> $@
1154 echo "$(SRCDIR)\diff.tcl" >> $@
1155 echo "$(SRCDIR)\forum.js" >> $@
1156 echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
1157 echo "$(SRCDIR)\fossil.confirmer.js" >> $@
1158 echo "$(SRCDIR)\fossil.copybutton.js" >> $@
1159 echo "$(SRCDIR)\fossil.dom.js" >> $@
1160 echo "$(SRCDIR)\fossil.fetch.js" >> $@
1161 echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
1162 echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
1163 echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
1164 echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
1165 echo "$(SRCDIR)\fossil.popupwidget.js" >> $@
1166 echo "$(SRCDIR)\fossil.storage.js" >> $@
1167 echo "$(SRCDIR)\fossil.tabs.js" >> $@
1168 echo "$(SRCDIR)\graph.js" >> $@
1169 echo "$(SRCDIR)\href.js" >> $@
1170 echo "$(SRCDIR)\login.js" >> $@
@@ -1181,10 +1190,11 @@
1190 echo "$(SRCDIR)\sounds/d.wav" >> $@
1191 echo "$(SRCDIR)\sounds/e.wav" >> $@
1192 echo "$(SRCDIR)\sounds/f.wav" >> $@
1193 echo "$(SRCDIR)\style.admin_log.css" >> $@
1194 echo "$(SRCDIR)\style.fileedit.css" >> $@
1195 echo "$(SRCDIR)\style.wikiedit.css" >> $@
1196 echo "$(SRCDIR)\tree.js" >> $@
1197 echo "$(SRCDIR)\useredit.js" >> $@
1198 echo "$(SRCDIR)\wiki.wiki" >> $@
1199
1200 "$(OX)\add$O" : "$(OX)\add_.c" "$(OX)\add.h"
@@ -2025,16 +2035,10 @@
2035 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\winhttp_.c"
2036
2037 "$(OX)\winhttp_.c" : "$(SRCDIR)\winhttp.c"
2038 "$(OBJDIR)\translate$E" $** > $@
2039
 
 
 
 
 
 
2040 "$(OX)\xfer$O" : "$(OX)\xfer_.c" "$(OX)\xfer.h"
2041 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\xfer_.c"
2042
2043 "$(OX)\xfer_.c" : "$(SRCDIR)\xfer.c"
2044 "$(OBJDIR)\translate$E" $** > $@
@@ -2193,14 +2197,13 @@
2197 "$(OX)\webmail_.c":"$(OX)\webmail.h" \
2198 "$(OX)\wiki_.c":"$(OX)\wiki.h" \
2199 "$(OX)\wikiformat_.c":"$(OX)\wikiformat.h" \
2200 "$(OX)\winfile_.c":"$(OX)\winfile.h" \
2201 "$(OX)\winhttp_.c":"$(OX)\winhttp.h" \
 
2202 "$(OX)\xfer_.c":"$(OX)\xfer.h" \
2203 "$(OX)\xfersetup_.c":"$(OX)\xfersetup.h" \
2204 "$(OX)\zip_.c":"$(OX)\zip.h" \
2205 "$(SRCDIR)\sqlite3.h" \
2206 "$(SRCDIR)\th.h" \
2207 "$(OX)\VERSION.h" \
2208 "$(SRCDIR)\cson_amalgamation.h"
2209 @copy /Y nul: $@
2210
+19 -3
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,22 +1,27 @@
11
<title>Change Log</title>
22
33
<a name='v2_12'></a>
4
-<h2>Changes for Version 2.12 (pending)</h2>
4
+<h2>Changes for Version 2.12</h2>
55
66
* Security fix in the "[/help?cmd=git|fossil git export]" command.
77
The same fix is also backported to version 2.10.1 and 2.11.1.
88
New "safety-net" features were added to prevent similar problems
99
in the future.
1010
* Enhancements to the graph display for cases when there are
1111
many cherry-pick merges into a single check-in.
1212
[/timeline?f=2d75e87b760c0a9|Example]
13
+ * Enhance the [/help?cmd=open|fossil open] command with the new
14
+ --workdir option and the ability to accept a URL as the repository
15
+ name, causing the remote repository to be cloned automatically.
16
+ Do not allow "fossil open" to open in a non-empty working directory
17
+ unless the --keep option or the new --force option is used.
1318
* Enhance the markdown formatter to more closely follow the
1419
[https://spec.commonmark.org/0.29/#emphasis-and-strong-emphasis|CommonMark specification]
1520
with regard to text highlighting.
16
- Underscores in the middle of identifiers (ex: fossil_printf()
17
- no longer need to be escaped).
21
+ Underscores in the middle of identifiers (ex: fossil_printf())
22
+ no longer need to be escaped.
1823
* The markdown-to-html translator can prevent unsafe HTML
1924
(for example: &lt;script&gt;) on user-contributed pages like forum and
2025
tickets and wiki. The admin can adjust this behavior using
2126
the [/help?cmd=safe-html|safe-html setting] on the Admin/Wiki page.
2227
The default is to disallow unsafe HTML everywhere.
@@ -57,11 +62,22 @@
5762
* Update the built-in SQLite so that the
5863
"[/help?cmd=sql|fossil sql]" command supports new output
5964
modes ".mode box" and ".mode json".
6065
* Add the "<tt>obscure()</tt>" SQL function to the
6166
"[/help?cmd=sql|fossil sql]" command.
67
+ * Added virtual tables "<tt>helptext</tt>" and "<tt>builtin</tt>" to
68
+ the "[/help?cmd=sql|fossil sql]" command, providing access to the
69
+ dispatch table including all help text, and the builtin data files,
70
+ respectively.
6271
* [./delta_format.wiki|Delta compression] is now applied to forum edits.
72
+ * The [/help?cmd=/wikiedit|wiki editor] has been modernized and is
73
+ now Ajax-based. The WYSIWYG editing option for Fossil-format wiki
74
+ pages was removed. (Please let us know, via the site's Support menu,
75
+ if that removal unduly impacts you.) This also changes the semantics
76
+ of the wiki "Sandbox": that pseudo-page may be freely edited but
77
+ no longer saved via the UI (the [/help?cmd=wiki|wiki CLI command]
78
+ can, though).
6379
* Countless documentation enhancements.
6480
6581
<a name='v2_11'></a>
6682
<h2>Changes for Version 2.11 (2020-05-25)</h2>
6783
6884
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,22 +1,27 @@
1 <title>Change Log</title>
2
3 <a name='v2_12'></a>
4 <h2>Changes for Version 2.12 (pending)</h2>
5
6 * Security fix in the "[/help?cmd=git|fossil git export]" command.
7 The same fix is also backported to version 2.10.1 and 2.11.1.
8 New "safety-net" features were added to prevent similar problems
9 in the future.
10 * Enhancements to the graph display for cases when there are
11 many cherry-pick merges into a single check-in.
12 [/timeline?f=2d75e87b760c0a9|Example]
 
 
 
 
 
13 * Enhance the markdown formatter to more closely follow the
14 [https://spec.commonmark.org/0.29/#emphasis-and-strong-emphasis|CommonMark specification]
15 with regard to text highlighting.
16 Underscores in the middle of identifiers (ex: fossil_printf()
17 no longer need to be escaped).
18 * The markdown-to-html translator can prevent unsafe HTML
19 (for example: &lt;script&gt;) on user-contributed pages like forum and
20 tickets and wiki. The admin can adjust this behavior using
21 the [/help?cmd=safe-html|safe-html setting] on the Admin/Wiki page.
22 The default is to disallow unsafe HTML everywhere.
@@ -57,11 +62,22 @@
57 * Update the built-in SQLite so that the
58 "[/help?cmd=sql|fossil sql]" command supports new output
59 modes ".mode box" and ".mode json".
60 * Add the "<tt>obscure()</tt>" SQL function to the
61 "[/help?cmd=sql|fossil sql]" command.
 
 
 
 
62 * [./delta_format.wiki|Delta compression] is now applied to forum edits.
 
 
 
 
 
 
 
63 * Countless documentation enhancements.
64
65 <a name='v2_11'></a>
66 <h2>Changes for Version 2.11 (2020-05-25)</h2>
67
68
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,22 +1,27 @@
1 <title>Change Log</title>
2
3 <a name='v2_12'></a>
4 <h2>Changes for Version 2.12</h2>
5
6 * Security fix in the "[/help?cmd=git|fossil git export]" command.
7 The same fix is also backported to version 2.10.1 and 2.11.1.
8 New "safety-net" features were added to prevent similar problems
9 in the future.
10 * Enhancements to the graph display for cases when there are
11 many cherry-pick merges into a single check-in.
12 [/timeline?f=2d75e87b760c0a9|Example]
13 * Enhance the [/help?cmd=open|fossil open] command with the new
14 --workdir option and the ability to accept a URL as the repository
15 name, causing the remote repository to be cloned automatically.
16 Do not allow "fossil open" to open in a non-empty working directory
17 unless the --keep option or the new --force option is used.
18 * Enhance the markdown formatter to more closely follow the
19 [https://spec.commonmark.org/0.29/#emphasis-and-strong-emphasis|CommonMark specification]
20 with regard to text highlighting.
21 Underscores in the middle of identifiers (ex: fossil_printf())
22 no longer need to be escaped.
23 * The markdown-to-html translator can prevent unsafe HTML
24 (for example: &lt;script&gt;) on user-contributed pages like forum and
25 tickets and wiki. The admin can adjust this behavior using
26 the [/help?cmd=safe-html|safe-html setting] on the Admin/Wiki page.
27 The default is to disallow unsafe HTML everywhere.
@@ -57,11 +62,22 @@
62 * Update the built-in SQLite so that the
63 "[/help?cmd=sql|fossil sql]" command supports new output
64 modes ".mode box" and ".mode json".
65 * Add the "<tt>obscure()</tt>" SQL function to the
66 "[/help?cmd=sql|fossil sql]" command.
67 * Added virtual tables "<tt>helptext</tt>" and "<tt>builtin</tt>" to
68 the "[/help?cmd=sql|fossil sql]" command, providing access to the
69 dispatch table including all help text, and the builtin data files,
70 respectively.
71 * [./delta_format.wiki|Delta compression] is now applied to forum edits.
72 * The [/help?cmd=/wikiedit|wiki editor] has been modernized and is
73 now Ajax-based. The WYSIWYG editing option for Fossil-format wiki
74 pages was removed. (Please let us know, via the site's Support menu,
75 if that removal unduly impacts you.) This also changes the semantics
76 of the wiki "Sandbox": that pseudo-page may be freely edited but
77 no longer saved via the UI (the [/help?cmd=wiki|wiki CLI command]
78 can, though).
79 * Countless documentation enhancements.
80
81 <a name='v2_11'></a>
82 <h2>Changes for Version 2.11 (2020-05-25)</h2>
83
84
--- www/fileedit-page.md
+++ www/fileedit-page.md
@@ -245,11 +245,11 @@
245245
246246
First, install proxy functions so that `fossil.page.fileContent()`
247247
can get and set your content:
248248
249249
```
250
-fossil.page.setFileContentMethods(
250
+fossil.page.setContentMethods(
251251
function(){ return text-form content of your widget },
252252
function(content){ set text-form content of your widget }
253253
};
254254
```
255255
256256
--- www/fileedit-page.md
+++ www/fileedit-page.md
@@ -245,11 +245,11 @@
245
246 First, install proxy functions so that `fossil.page.fileContent()`
247 can get and set your content:
248
249 ```
250 fossil.page.setFileContentMethods(
251 function(){ return text-form content of your widget },
252 function(content){ set text-form content of your widget }
253 };
254 ```
255
256
--- www/fileedit-page.md
+++ www/fileedit-page.md
@@ -245,11 +245,11 @@
245
246 First, install proxy functions so that `fossil.page.fileContent()`
247 can get and set your content:
248
249 ```
250 fossil.page.setContentMethods(
251 function(){ return text-form content of your widget },
252 function(content){ set text-form content of your widget }
253 };
254 ```
255
256
+1 -1
--- www/gitusers.md
+++ www/gitusers.md
@@ -137,11 +137,11 @@
137137
[3]: ./rebaseharm.md
138138
139139
## Branch and Tag Names
140140
141141
Fossil has no special restrictions on the names of tags and branches,
142
-though you might want to to keep [Git's tag and branch name restrictions][4]
142
+though you might want to keep [Git's tag and branch name restrictions][4]
143143
in mind if you plan on mirroring your Fossil repository to GitHub.
144144
145145
[4]: https://git-scm.com/docs/git-check-ref-format
146146
147147
Fossil does not require tag and branch names to be unique. It is
148148
--- www/gitusers.md
+++ www/gitusers.md
@@ -137,11 +137,11 @@
137 [3]: ./rebaseharm.md
138
139 ## Branch and Tag Names
140
141 Fossil has no special restrictions on the names of tags and branches,
142 though you might want to to keep [Git's tag and branch name restrictions][4]
143 in mind if you plan on mirroring your Fossil repository to GitHub.
144
145 [4]: https://git-scm.com/docs/git-check-ref-format
146
147 Fossil does not require tag and branch names to be unique. It is
148
--- www/gitusers.md
+++ www/gitusers.md
@@ -137,11 +137,11 @@
137 [3]: ./rebaseharm.md
138
139 ## Branch and Tag Names
140
141 Fossil has no special restrictions on the names of tags and branches,
142 though you might want to keep [Git's tag and branch name restrictions][4]
143 in mind if you plan on mirroring your Fossil repository to GitHub.
144
145 [4]: https://git-scm.com/docs/git-check-ref-format
146
147 Fossil does not require tag and branch names to be unique. It is
148
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -66,20 +66,24 @@
6666
## <a name="chroot"></a>Setup chroot
6767
6868
Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible
6969
from within the chroot, so need to be constructed; `/var`, however, is
7070
mounted with the `nodev` option. Rather than removing this default
71
-setting, create a small memory filesystem with [`mount_mfs(8)`][mfs]
72
-upon which `/var/www/dev` will be mounted so that the `random` and
73
-`null` device files can be created.
71
+setting, create a small memory filesystem and then mount it on to
72
+`/var/www/dev` with [`mount_mfs(8)`][mfs] so that the `random` and
73
+`null` device files can be created. In order to avoid neccessitating a
74
+startup script to recreate the device files at boot, create a template
75
+of the needed ``/dev`` tree to automatically populate the memory
76
+filesystem.
7477
7578
```console
7679
$ doas mkdir /var/www/dev
77
- $ doas mount_mfs -s 1M /dev/sd0b /var/www/dev
78
- $ doas cd /var/www/dev
80
+ $ doas install -d -g daemon /template/dev
81
+ $ cd /template/dev
7982
$ doas /dev/MAKEDEV urandom
8083
$ doas mknod -m 666 null c 2 2
84
+ $ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev
8185
$ ls -l
8286
total 0
8387
crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null
8488
lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom
8589
crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom
@@ -90,11 +94,11 @@
9094
To make the mountable memory filesystem permanent, open `/etc/fstab` as
9195
a privileged user and add the following line to automate creation of the
9296
filesystem at startup:
9397
9498
```console
95
- swap /var/www/dev mfs rw,-s=1048576 0 0
99
+ swap /var/www/dev mfs rw,-s=1048576,-P=/template/dev 0 0
96100
```
97101
98102
The same user that executes the fossil binary must have writable access
99103
to the repository directory that resides within the chroot; on OpenBSD
100104
this is `www`. In addition, grant repository directory ownership to the
101105
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -66,20 +66,24 @@
66 ## <a name="chroot"></a>Setup chroot
67
68 Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible
69 from within the chroot, so need to be constructed; `/var`, however, is
70 mounted with the `nodev` option. Rather than removing this default
71 setting, create a small memory filesystem with [`mount_mfs(8)`][mfs]
72 upon which `/var/www/dev` will be mounted so that the `random` and
73 `null` device files can be created.
 
 
 
74
75 ```console
76 $ doas mkdir /var/www/dev
77 $ doas mount_mfs -s 1M /dev/sd0b /var/www/dev
78 $ doas cd /var/www/dev
79 $ doas /dev/MAKEDEV urandom
80 $ doas mknod -m 666 null c 2 2
 
81 $ ls -l
82 total 0
83 crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null
84 lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom
85 crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom
@@ -90,11 +94,11 @@
90 To make the mountable memory filesystem permanent, open `/etc/fstab` as
91 a privileged user and add the following line to automate creation of the
92 filesystem at startup:
93
94 ```console
95 swap /var/www/dev mfs rw,-s=1048576 0 0
96 ```
97
98 The same user that executes the fossil binary must have writable access
99 to the repository directory that resides within the chroot; on OpenBSD
100 this is `www`. In addition, grant repository directory ownership to the
101
--- www/server/openbsd/fastcgi.md
+++ www/server/openbsd/fastcgi.md
@@ -66,20 +66,24 @@
66 ## <a name="chroot"></a>Setup chroot
67
68 Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible
69 from within the chroot, so need to be constructed; `/var`, however, is
70 mounted with the `nodev` option. Rather than removing this default
71 setting, create a small memory filesystem and then mount it on to
72 `/var/www/dev` with [`mount_mfs(8)`][mfs] so that the `random` and
73 `null` device files can be created. In order to avoid neccessitating a
74 startup script to recreate the device files at boot, create a template
75 of the needed ``/dev`` tree to automatically populate the memory
76 filesystem.
77
78 ```console
79 $ doas mkdir /var/www/dev
80 $ doas install -d -g daemon /template/dev
81 $ cd /template/dev
82 $ doas /dev/MAKEDEV urandom
83 $ doas mknod -m 666 null c 2 2
84 $ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev
85 $ ls -l
86 total 0
87 crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null
88 lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom
89 crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom
@@ -90,11 +94,11 @@
94 To make the mountable memory filesystem permanent, open `/etc/fstab` as
95 a privileged user and add the following line to automate creation of the
96 filesystem at startup:
97
98 ```console
99 swap /var/www/dev mfs rw,-s=1048576,-P=/template/dev 0 0
100 ```
101
102 The same user that executes the fossil binary must have writable access
103 to the repository directory that resides within the chroot; on OpenBSD
104 this is `www`. In addition, grant repository directory ownership to the
105

Keyboard Shortcuts

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