Fossil SCM

Merge latest trunk. This branch is more a "proof-of-concept" then a final implementation.

baruch 2015-02-01 07:18 file-filter merge
Commit 8841f6d48fa215ec18e0fe5ed00a31dfb6221285
113 files changed +26 +5 -14 +1 -1 +1 -1 +29 +82 +1 +43 +68 +3 +3 +1 +24 +89 +68 +23 +89 +1 +3 +3 +27 +1 +1 +18 +6 +1 +13 +105 +1 +38 +2 -2 +154 -38 +10 -3 +10 -3 +10 -2 +4 -1 +13 -5 +14 -11 +4 -4 +192 +102 -33 +1 -1 +9 +130 -126 +4 -4 +19 +69 -55 +25 -5 +4 -4 -19 +26 -5 +13 -8 +56 -46 +1 -1 +2 -4 +5 -5 +5 -5 +2 -1 +79 -15 +39 -2 +59 -59 +22 -9 +64 -53 +224 +5 -5 +6 -6 +32 -13 +3 -3 +1 -1 +1 -1 +9 -9 +89 -30 +35 -12 +621 -83 +62 -27 +7 -7 +300 -139 +1 +196 -1310 +34 -2 +759 -522 +31 -13 +6 +535 +92 -240 +5 -5 +3 -2 +1 -1 +2 -2 +13 -689 +1 -1 +17 -17 +12 -1 +5 -4 +10 +2 -2 +32 -8 +72 +2 -2 +1 -1 +12 -11 +1 -1 +11 -5 +42 -4 +42 -4 +38 -3 +2 -2 +1 -1 +75 -13 +2 -2 +5 -5 +2 -1 +3 -1
~ .dockerignore ~ Dockerfile ~ VERSION ~ auto.def ~ skins/README.md ~ skins/black_and_white/css.txt ~ skins/black_and_white/footer.txt ~ skins/black_and_white/header.txt ~ skins/default/css.txt ~ skins/default/footer.txt ~ skins/default/header.txt ~ skins/eagle/css.txt ~ skins/eagle/footer.txt ~ skins/eagle/header.txt ~ skins/enhanced1/css.txt ~ skins/enhanced1/footer.txt ~ skins/enhanced1/header.txt ~ skins/etienne1/README.md ~ skins/etienne1/css.txt ~ skins/etienne1/footer.txt ~ skins/etienne1/header.txt ~ skins/khaki/css.txt ~ skins/khaki/footer.txt ~ skins/khaki/header.txt ~ skins/plain_gray/css.txt ~ skins/plain_gray/footer.txt ~ skins/plain_gray/header.txt ~ skins/rounded1/css.txt ~ skins/rounded1/footer.txt ~ skins/rounded1/header.txt ~ src/attach.c ~ src/branch.c ~ src/browse.c ~ src/browse.c ~ src/builtin.c ~ src/cgi.c ~ src/checkin.c ~ src/clone.c ~ src/codecheck1.c ~ src/configure.c ~ src/db.c ~ src/deltacmd.c ~ src/diff.tcl ~ src/doc.c ~ src/export.c ~ src/file.c ~ src/finfo.c ~ src/foci.c ~ src/fusefs.c ~ src/glob.c ~ src/graph.c ~ src/http.c ~ src/http_socket.c ~ src/http_transport.c ~ src/info.c ~ src/json_branch.c ~ src/leaf.c ~ src/login.c ~ src/main.c ~ src/main.mk ~ src/makeheaders.c ~ src/makemake.tcl ~ src/manifest.c ~ src/markdown.md ~ src/md5.c ~ src/merge.c ~ src/mkbuiltin.c ~ src/mkindex.c ~ src/mkversion.c ~ src/publish.c ~ src/regexp.c ~ src/report.c ~ src/schema.c ~ src/search.c ~ src/setup.c ~ src/sha1.c ~ src/shell.c ~ src/sitemap.c ~ src/skins.c ~ src/sqlcmd.c ~ src/sqlite3.c ~ src/sqlite3.h ~ src/stat.c ~ src/statrep.c ~ src/style.c ~ src/sync.c ~ src/tag.c ~ src/th.h ~ src/th_main.c ~ src/timeline.c ~ src/translate.c ~ src/update.c ~ src/url.c ~ src/user.c ~ src/util.c ~ src/verify.c ~ src/wiki.c ~ src/wikiformat.c ~ src/xfer.c ~ test/diff-test-1.wiki ~ test/graph-test-1.wiki ~ win/Makefile.PellesCGMake ~ win/Makefile.dmc ~ win/Makefile.mingw ~ win/Makefile.mingw.mistachkin ~ win/Makefile.msc ~ win/include/unistd.h ~ www/build.wiki ~ www/changes.wiki ~ www/delta_format.wiki ~ www/fileformat.wiki ~ www/hints.wiki ~ www/qandc.wiki
--- a/.dockerignore
+++ b/.dockerignore
@@ -0,0 +1,26 @@
1
+_FOSSIL_
2
+.fslckout
3
+ajax
4
+art
5
+autosetup
6
+bld
7
+compat
8
+debian
9
+fossil
10
+fossil.exe
11
+setup
12
+src
13
+test
14
+tools
15
+win
16
+wbld
17
+win
18
+www
19
+*.a
20
+*.lib
21
+*.log
22
+*.manifest
23
+*.o
24
+*.obj
25
+*.pdb
26
+*.res
--- a/.dockerignore
+++ b/.dockerignore
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/.dockerignore
+++ b/.dockerignore
@@ -0,0 +1,26 @@
1 _FOSSIL_
2 .fslckout
3 ajax
4 art
5 autosetup
6 bld
7 compat
8 debian
9 fossil
10 fossil.exe
11 setup
12 src
13 test
14 tools
15 win
16 wbld
17 win
18 www
19 *.a
20 *.lib
21 *.log
22 *.manifest
23 *.o
24 *.obj
25 *.pdb
26 *.res
+5 -14
--- Dockerfile
+++ Dockerfile
@@ -2,35 +2,26 @@
22
# Dockerfile for Fossil
33
###
44
FROM fedora:21
55
66
### Now install some additional parts we will need for the build
7
-# RUN yum update -y && yum clean all
8
-RUN yum install -y gcc make zlib-devel openssl-devel tcl-devel && yum clean all
9
-RUN groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil
7
+RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tcl tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil
108
119
### If you want to build "release", change the next line accordingly.
1210
ENV FOSSIL_INSTALL_VERSION trunk
1311
1412
RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx
15
-RUN cd fossil-src && ./configure --lineedit=0 --json --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make;
16
-RUN cp fossil-src/fossil /usr/bin
17
-RUN rm -rf fossil-src
18
-RUN chmod a+rx /usr/bin/fossil
19
-RUN mkdir -p /opt/fossil
20
-RUN chown fossil:fossil /opt/fossil
13
+RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make;
14
+RUN cp fossil-src/fossil /usr/bin && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil
2115
2216
### Build is done, remove modules no longer needed
23
-RUN yum remove -y gcc make zlib-devel openssl-devel tcl-devel && yum clean all
17
+RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all
2418
2519
USER fossil
2620
2721
ENV HOME /opt/fossil
2822
29
-RUN fossil new --docker -A admin /opt/fossil/repository.fossil
30
-RUN fossil user password -R /opt/fossil/repository.fossil admin admin
31
-RUN fossil cache init -R /opt/fossil/repository.fossil
23
+RUN fossil new --docker -A admin /opt/fossil/repository.fossil && fossil user password -R /opt/fossil/repository.fossil admin admin && fossil cache init -R /opt/fossil/repository.fossil
3224
3325
EXPOSE 8080
3426
3527
CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"]
36
-
3728
--- Dockerfile
+++ Dockerfile
@@ -2,35 +2,26 @@
2 # Dockerfile for Fossil
3 ###
4 FROM fedora:21
5
6 ### Now install some additional parts we will need for the build
7 # RUN yum update -y && yum clean all
8 RUN yum install -y gcc make zlib-devel openssl-devel tcl-devel && yum clean all
9 RUN groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil
10
11 ### If you want to build "release", change the next line accordingly.
12 ENV FOSSIL_INSTALL_VERSION trunk
13
14 RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx
15 RUN cd fossil-src && ./configure --lineedit=0 --json --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make;
16 RUN cp fossil-src/fossil /usr/bin
17 RUN rm -rf fossil-src
18 RUN chmod a+rx /usr/bin/fossil
19 RUN mkdir -p /opt/fossil
20 RUN chown fossil:fossil /opt/fossil
21
22 ### Build is done, remove modules no longer needed
23 RUN yum remove -y gcc make zlib-devel openssl-devel tcl-devel && yum clean all
24
25 USER fossil
26
27 ENV HOME /opt/fossil
28
29 RUN fossil new --docker -A admin /opt/fossil/repository.fossil
30 RUN fossil user password -R /opt/fossil/repository.fossil admin admin
31 RUN fossil cache init -R /opt/fossil/repository.fossil
32
33 EXPOSE 8080
34
35 CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"]
36
37
--- Dockerfile
+++ Dockerfile
@@ -2,35 +2,26 @@
2 # Dockerfile for Fossil
3 ###
4 FROM fedora:21
5
6 ### Now install some additional parts we will need for the build
7 RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tcl tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil
 
 
8
9 ### If you want to build "release", change the next line accordingly.
10 ENV FOSSIL_INSTALL_VERSION trunk
11
12 RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx
13 RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make;
14 RUN cp fossil-src/fossil /usr/bin && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil
 
 
 
 
15
16 ### Build is done, remove modules no longer needed
17 RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all
18
19 USER fossil
20
21 ENV HOME /opt/fossil
22
23 RUN fossil new --docker -A admin /opt/fossil/repository.fossil && fossil user password -R /opt/fossil/repository.fossil admin admin && fossil cache init -R /opt/fossil/repository.fossil
 
 
24
25 EXPOSE 8080
26
27 CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"]
 
28
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-1.30
1
+1.31
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.30
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.31
2
+1 -1
--- auto.def
+++ auto.def
@@ -68,11 +68,11 @@
6868
6969
find_internal_sqlite
7070
}
7171
7272
if {[string match *-solaris* [get-define host]]} {
73
- define-append EXTRA_CFLAGS -D_XOPEN_SOURCE=500
73
+ define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__}
7474
}
7575
7676
if {[opt-bool fossil-debug]} {
7777
define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
7878
msg-result "Debugging support enabled"
7979
8080
ADDED skins/README.md
8181
ADDED skins/black_and_white/css.txt
8282
ADDED skins/black_and_white/footer.txt
8383
ADDED skins/black_and_white/header.txt
8484
ADDED skins/default/css.txt
8585
ADDED skins/default/footer.txt
8686
ADDED skins/default/header.txt
8787
ADDED skins/eagle/css.txt
8888
ADDED skins/eagle/footer.txt
8989
ADDED skins/eagle/header.txt
9090
ADDED skins/enhanced1/css.txt
9191
ADDED skins/enhanced1/footer.txt
9292
ADDED skins/enhanced1/header.txt
9393
ADDED skins/etienne1/README.md
9494
ADDED skins/etienne1/css.txt
9595
ADDED skins/etienne1/footer.txt
9696
ADDED skins/etienne1/header.txt
9797
ADDED skins/khaki/css.txt
9898
ADDED skins/khaki/footer.txt
9999
ADDED skins/khaki/header.txt
100100
ADDED skins/plain_gray/css.txt
101101
ADDED skins/plain_gray/footer.txt
102102
ADDED skins/plain_gray/header.txt
103103
ADDED skins/rounded1/css.txt
104104
ADDED skins/rounded1/footer.txt
105105
ADDED skins/rounded1/header.txt
--- auto.def
+++ auto.def
@@ -68,11 +68,11 @@
68
69 find_internal_sqlite
70 }
71
72 if {[string match *-solaris* [get-define host]]} {
73 define-append EXTRA_CFLAGS -D_XOPEN_SOURCE=500
74 }
75
76 if {[opt-bool fossil-debug]} {
77 define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
78 msg-result "Debugging support enabled"
79
80 DDED skins/README.md
81 DDED skins/black_and_white/css.txt
82 DDED skins/black_and_white/footer.txt
83 DDED skins/black_and_white/header.txt
84 DDED skins/default/css.txt
85 DDED skins/default/footer.txt
86 DDED skins/default/header.txt
87 DDED skins/eagle/css.txt
88 DDED skins/eagle/footer.txt
89 DDED skins/eagle/header.txt
90 DDED skins/enhanced1/css.txt
91 DDED skins/enhanced1/footer.txt
92 DDED skins/enhanced1/header.txt
93 DDED skins/etienne1/README.md
94 DDED skins/etienne1/css.txt
95 DDED skins/etienne1/footer.txt
96 DDED skins/etienne1/header.txt
97 DDED skins/khaki/css.txt
98 DDED skins/khaki/footer.txt
99 DDED skins/khaki/header.txt
100 DDED skins/plain_gray/css.txt
101 DDED skins/plain_gray/footer.txt
102 DDED skins/plain_gray/header.txt
103 DDED skins/rounded1/css.txt
104 DDED skins/rounded1/footer.txt
105 DDED skins/rounded1/header.txt
--- auto.def
+++ auto.def
@@ -68,11 +68,11 @@
68
69 find_internal_sqlite
70 }
71
72 if {[string match *-solaris* [get-define host]]} {
73 define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__}
74 }
75
76 if {[opt-bool fossil-debug]} {
77 define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
78 msg-result "Debugging support enabled"
79
80 DDED skins/README.md
81 DDED skins/black_and_white/css.txt
82 DDED skins/black_and_white/footer.txt
83 DDED skins/black_and_white/header.txt
84 DDED skins/default/css.txt
85 DDED skins/default/footer.txt
86 DDED skins/default/header.txt
87 DDED skins/eagle/css.txt
88 DDED skins/eagle/footer.txt
89 DDED skins/eagle/header.txt
90 DDED skins/enhanced1/css.txt
91 DDED skins/enhanced1/footer.txt
92 DDED skins/enhanced1/header.txt
93 DDED skins/etienne1/README.md
94 DDED skins/etienne1/css.txt
95 DDED skins/etienne1/footer.txt
96 DDED skins/etienne1/header.txt
97 DDED skins/khaki/css.txt
98 DDED skins/khaki/footer.txt
99 DDED skins/khaki/header.txt
100 DDED skins/plain_gray/css.txt
101 DDED skins/plain_gray/footer.txt
102 DDED skins/plain_gray/header.txt
103 DDED skins/rounded1/css.txt
104 DDED skins/rounded1/footer.txt
105 DDED skins/rounded1/header.txt
--- a/skins/README.md
+++ b/skins/README.md
@@ -0,0 +1,29 @@
1
+Built-in Skins
2
+==============
3
+
4
+Each subdirectory under this folder describes a three files in each subheader,
5
+and the foothe Content Footer
6
+
7
+To improve an exieing built-in skin, simply edit the appropriate
8
+files and recompile.
9
+
10
+To add a new skin:
11
+
12
+ 1. Create a new subdirectory under skins/. (The new directory is
13
+ called "skins/newskin" below but you should use a new original
14
+ name, of course.)
15
+
16
+ 2. Add files skins/newskin/css.txt, skins and skinheader.txt,
17
+ . Go to the src/ footer.txt.the src/ directory and rerun "tclsh makemake.tcl". This
18
+ step rebuilds the various makefiles so that they have dependencies
19
+ on the skin files you just installed.
20
+
21
+ 4. Edit the BuiltinSkin[] array near the top of the src/skins.c source
22
+ file so that it describes and references the "newskin" skin.
23
+
24
+ 5. Type "make" to rebuild.
25
+
26
+Development Hints
27
+-----------------
28
+
29
+One way to develop a new skin is to copy th
--- a/skins/README.md
+++ b/skins/README.md
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/README.md
+++ b/skins/README.md
@@ -0,0 +1,29 @@
1 Built-in Skins
2 ==============
3
4 Each subdirectory under this folder describes a three files in each subheader,
5 and the foothe Content Footer
6
7 To improve an exieing built-in skin, simply edit the appropriate
8 files and recompile.
9
10 To add a new skin:
11
12 1. Create a new subdirectory under skins/. (The new directory is
13 called "skins/newskin" below but you should use a new original
14 name, of course.)
15
16 2. Add files skins/newskin/css.txt, skins and skinheader.txt,
17 . Go to the src/ footer.txt.the src/ directory and rerun "tclsh makemake.tcl". This
18 step rebuilds the various makefiles so that they have dependencies
19 on the skin files you just installed.
20
21 4. Edit the BuiltinSkin[] array near the top of the src/skins.c source
22 file so that it describes and references the "newskin" skin.
23
24 5. Type "make" to rebuild.
25
26 Development Hints
27 -----------------
28
29 One way to develop a new skin is to copy th
--- a/skins/black_and_white/css.txt
+++ b/skins/black_and_white/css.txt
@@ -0,0 +1,82 @@
1
+/* General settings for the entire page */
2
+body {
3
+ margin:0px 0px 0px 0px;
4
+ padding:0px;
5
+ font-family:verdana, arial, helvetica, "sans serif";
6
+ color:#333;
7
+ background-color:white;
8
+mx-text-size-adjust: none;
9
+}
10
+
11
+/* consistent colours */
12
+h2 {
13
+ color: #333;
14
+}
15
+h3 {
16
+ color: #333;
17
+}
18
+
19
+/* The project logo in the upper left-hand corner of each page */
20
+div.logo {
21
+ display: table-cell;
22
+ text-align: left;
23
+ vertical-align: bottom;
24
+ font-weight: bold;
25
+ color: #333;
26
+ white-space: nowrap;
27
+}
28
+
29
+/* The page title centered at the top of each page */
30
+div.title {
31
+ -size: 2em;
32
+ font-weight: bold;
33
+ text-align: center;
34
+ color: #333;
35
+ vertical-align: bot The login status message in the top right-hand corner */
36
+div.status {
37
+ display: table-cell;
38
+ padding-right: 10px;
39
+ text-align: right;
40
+ vertical-align: bottom;
41
+ padding-bottom: 5px;
42
+ color: #333;
43
+ font-size: 0.8em;
44
+ font-weight: bold;
45
+ white-space: nowrap;
46
+}
47
+
48
+/* The header across the top of the page */
49
+div.header {
50
+ margin:10px 0px 10px 0px;
51
+ padding:1px 0px 0px 20px;
52
+ border-style:solid;
53
+ border-color:black;
54
+ border-width:1px 0px;
55
+ background-color:#eee;
56
+}
57
+
58
+/* The main menu bar that appears at the top left of the page beneath
59
+** the header. Width must be co-ordinated wdiv.mainmenu {
60
+ float: left;
61
+ margin-left: 10px;
62
+ margin-right: vertical-align: bottpadding:5px;
63
+ background-color:#eee;
64
+ border:1px solid #999;
65
+ width:8em;
66
+}
67
+
68
+/* Main menu is now a list */
69
+diin menu is now a list */div.mainmenu a, di:none;
70
+}
71
+nav.mainmenu a, nav.mainmenu a:visited{
72
+ padding: 1px 10px 1px 10px;
73
+ color: #333;
74
+div.mainmenu a:hover {
75
+ color: #eee;
76
+ background-color: #333;
77
+}
78
+
79
+/* Container for the sub-menu and content so they don't spread
80
+** out underneath the main menu */
81
+#container {
82
+ padding-leftdidiv.submenu a, didi/* General settings for the en
--- a/skins/black_and_white/css.txt
+++ b/skins/black_and_white/css.txt
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/black_and_white/css.txt
+++ b/skins/black_and_white/css.txt
@@ -0,0 +1,82 @@
1 /* General settings for the entire page */
2 body {
3 margin:0px 0px 0px 0px;
4 padding:0px;
5 font-family:verdana, arial, helvetica, "sans serif";
6 color:#333;
7 background-color:white;
8 mx-text-size-adjust: none;
9 }
10
11 /* consistent colours */
12 h2 {
13 color: #333;
14 }
15 h3 {
16 color: #333;
17 }
18
19 /* The project logo in the upper left-hand corner of each page */
20 div.logo {
21 display: table-cell;
22 text-align: left;
23 vertical-align: bottom;
24 font-weight: bold;
25 color: #333;
26 white-space: nowrap;
27 }
28
29 /* The page title centered at the top of each page */
30 div.title {
31 -size: 2em;
32 font-weight: bold;
33 text-align: center;
34 color: #333;
35 vertical-align: bot The login status message in the top right-hand corner */
36 div.status {
37 display: table-cell;
38 padding-right: 10px;
39 text-align: right;
40 vertical-align: bottom;
41 padding-bottom: 5px;
42 color: #333;
43 font-size: 0.8em;
44 font-weight: bold;
45 white-space: nowrap;
46 }
47
48 /* The header across the top of the page */
49 div.header {
50 margin:10px 0px 10px 0px;
51 padding:1px 0px 0px 20px;
52 border-style:solid;
53 border-color:black;
54 border-width:1px 0px;
55 background-color:#eee;
56 }
57
58 /* The main menu bar that appears at the top left of the page beneath
59 ** the header. Width must be co-ordinated wdiv.mainmenu {
60 float: left;
61 margin-left: 10px;
62 margin-right: vertical-align: bottpadding:5px;
63 background-color:#eee;
64 border:1px solid #999;
65 width:8em;
66 }
67
68 /* Main menu is now a list */
69 diin menu is now a list */div.mainmenu a, di:none;
70 }
71 nav.mainmenu a, nav.mainmenu a:visited{
72 padding: 1px 10px 1px 10px;
73 color: #333;
74 div.mainmenu a:hover {
75 color: #eee;
76 background-color: #333;
77 }
78
79 /* Container for the sub-menu and content so they don't spread
80 ** out underneath the main menu */
81 #container {
82 padding-leftdidiv.submenu a, didi/* General settings for the en
--- a/skins/black_and_white/footer.txt
+++ b/skins/black_and_white/footer.txt
@@ -0,0 +1 @@
1
+<
--- a/skins/black_and_white/footer.txt
+++ b/skins/black_and_white/footer.txt
@@ -0,0 +1 @@
 
--- a/skins/black_and_white/footer.txt
+++ b/skins/black_and_white/footer.txt
@@ -0,0 +1 @@
1 <
--- a/skins/black_and_white/header.txt
+++ b/skins/black_and_white/header.txt
@@ -0,0 +1,43 @@
1
+<html>
2
+<head>
3
+<base href="$baseu>$<project_name>
4
+ </div>
5
+ <div class="title">$<title></div>
6
+ <diiv class="status"><th1>
7
+ if {[i puts "Logged in as $login"
8
+ } else {
9
+ in as $login"
10
+ } else {
11
+ }
12
+ </th1></div>
13
+</div>
14
+<diiter class} $mainmenu {
15
+ html "<a href='$home$index_page'>Htimeline'>Timelintree?ci=tip'>Filbrlist'>Branches</a>\n"taglist'>Tags</a>\n"
16
+}
17
+if {[anycap 23456] || [anoncap 2] || [anoncap 3]forum'>Forum</a>\n"[anoncap r]ticket'>Tickewiki'>Wiki</a>\n"
18
+}
19
+if {[hascap s]etup'>Admin<etup_ulist'>Users</a>\n"
20
+}
21
+if {[i puts "Logged in as $lohtml "<a href='$home/login'>Login<: $<title></title>
22
+<link rel="alternate" type="application/rss+xml" title="RSS Feed"
23
+ href="$home/timeline.rss">
24
+<link rel="styleshasd>
25
+<base href="$baseu>$<project_name>
26
+ </div>
27
+ <div class="title"<html>
28
+<ss} $mainmenu {
29
+ html "<a href='$home$index_page'>Htimeline'>Timelintree?ci=tip'>Filbrlist'>Branches</a>\n"taglist'>Tags</a>\n"
30
+}
31
+if {[anycap 23456] || [anoncap 2] |reportlisoncap 3]forum'>Forum</a>\n"[anoncap r]ticket'>Tickewikiv class="logo">
32
+ <img src="$logo_image_url" alt="logo">
33
+ <br />$<projhascap ="RSS Feed"
34
+ href="$home/tss="status"><th1>
35
+ if {[ihastatus"><th1>
36
+ if {[i puts "Logged in as $login"
37
+ } else {
38
+ in as $login"
39
+ } else {
40
+ }
41
+ </th1></div>
42
+</div>
43
+<diiter clas
--- a/skins/black_and_white/header.txt
+++ b/skins/black_and_white/header.txt
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/black_and_white/header.txt
+++ b/skins/black_and_white/header.txt
@@ -0,0 +1,43 @@
1 <html>
2 <head>
3 <base href="$baseu>$<project_name>
4 </div>
5 <div class="title">$<title></div>
6 <diiv class="status"><th1>
7 if {[i puts "Logged in as $login"
8 } else {
9 in as $login"
10 } else {
11 }
12 </th1></div>
13 </div>
14 <diiter class} $mainmenu {
15 html "<a href='$home$index_page'>Htimeline'>Timelintree?ci=tip'>Filbrlist'>Branches</a>\n"taglist'>Tags</a>\n"
16 }
17 if {[anycap 23456] || [anoncap 2] || [anoncap 3]forum'>Forum</a>\n"[anoncap r]ticket'>Tickewiki'>Wiki</a>\n"
18 }
19 if {[hascap s]etup'>Admin<etup_ulist'>Users</a>\n"
20 }
21 if {[i puts "Logged in as $lohtml "<a href='$home/login'>Login<: $<title></title>
22 <link rel="alternate" type="application/rss+xml" title="RSS Feed"
23 href="$home/timeline.rss">
24 <link rel="styleshasd>
25 <base href="$baseu>$<project_name>
26 </div>
27 <div class="title"<html>
28 <ss} $mainmenu {
29 html "<a href='$home$index_page'>Htimeline'>Timelintree?ci=tip'>Filbrlist'>Branches</a>\n"taglist'>Tags</a>\n"
30 }
31 if {[anycap 23456] || [anoncap 2] |reportlisoncap 3]forum'>Forum</a>\n"[anoncap r]ticket'>Tickewikiv class="logo">
32 <img src="$logo_image_url" alt="logo">
33 <br />$<projhascap ="RSS Feed"
34 href="$home/tss="status"><th1>
35 if {[ihastatus"><th1>
36 if {[i puts "Logged in as $login"
37 } else {
38 in as $login"
39 } else {
40 }
41 </th1></div>
42 </div>
43 <diiter clas
--- a/skins/default/css.txt
+++ b/skins/default/css.txt
@@ -0,0 +1,68 @@
1
+/* General settings for the entire page */
2
+body {
3
+ margin: 0ex 1ex;
4
+ padding: 0px;
5
+ background-color: white;
6
+ font-family: sans-serif;
7
+mx-text-size-adjust: none;
8
+}
9
+
10
+/* The project logo in the upper left-hand corner of each page */
11
+div.logo {
12
+ display: table-cell;
13
+ text-align: center;
14
+ vertical-align: bottom;
15
+ font-weight: bold;
16
+ co20or: #558195;
17
+ min-width: 50px;
18
+ white-space: nowrap;
19
+}
20
+
21
+/* The page title centered at the top of each page */
22
+div.title {
23
+ display: table-cell;
24
+ font-size: 2em;
25
+ font-weight: bold;
26
+ text-align: center;
27
+ padding: 0 0 0 1em;
28
+ color: #558195;
29
+ vertical-align: bottom;
30
+ width: 100%;
31
+}
32
+
33
+/* The login status message in the top right-hand corner */
34
+div.status {
35
+ display: table-cell;
36
+ text-align: right;
37
+ vertical-align: bottom;
38
+ color: #558195;
39
+ font-size: 0.8min-width: 20or: #558195e-space: nowrap;
40
+}
41
+
42
+/* The header across the top of the page */
43
+div.header {
44
+ display: table;
45
+ width: 100%;
46
+}
47
+
48
+/* The main menu bar that appears at the top of the page beneath
49
+** the header */
50
+diisplay: table;
51
+ winmenu {
52
+ padding: 5px;
53
+ font-size: 0.9em;
54
+ font-weight: bold;
55
+ text-align: center;
56
+ letter-spacing: 1px;
57
+ background-color: #558195;
58
+ border-top-left-radius: 8px;
59
+ border-top-right-radius: 8px;
60
+ color: white;
61
+}
62
+
63
+/* The submenu bar that *sometimes* appedis below the main menu */
64
+div.submenu, div.sectionmenu {
65
+ padding: 3px 10px 3px 0px;
66
+ font-size: 0.9em;
67
+ text-align: center;
68
+ background-color: div.mainmenu a, div
--- a/skins/default/css.txt
+++ b/skins/default/css.txt
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/default/css.txt
+++ b/skins/default/css.txt
@@ -0,0 +1,68 @@
1 /* General settings for the entire page */
2 body {
3 margin: 0ex 1ex;
4 padding: 0px;
5 background-color: white;
6 font-family: sans-serif;
7 mx-text-size-adjust: none;
8 }
9
10 /* The project logo in the upper left-hand corner of each page */
11 div.logo {
12 display: table-cell;
13 text-align: center;
14 vertical-align: bottom;
15 font-weight: bold;
16 co20or: #558195;
17 min-width: 50px;
18 white-space: nowrap;
19 }
20
21 /* The page title centered at the top of each page */
22 div.title {
23 display: table-cell;
24 font-size: 2em;
25 font-weight: bold;
26 text-align: center;
27 padding: 0 0 0 1em;
28 color: #558195;
29 vertical-align: bottom;
30 width: 100%;
31 }
32
33 /* The login status message in the top right-hand corner */
34 div.status {
35 display: table-cell;
36 text-align: right;
37 vertical-align: bottom;
38 color: #558195;
39 font-size: 0.8min-width: 20or: #558195e-space: nowrap;
40 }
41
42 /* The header across the top of the page */
43 div.header {
44 display: table;
45 width: 100%;
46 }
47
48 /* The main menu bar that appears at the top of the page beneath
49 ** the header */
50 diisplay: table;
51 winmenu {
52 padding: 5px;
53 font-size: 0.9em;
54 font-weight: bold;
55 text-align: center;
56 letter-spacing: 1px;
57 background-color: #558195;
58 border-top-left-radius: 8px;
59 border-top-right-radius: 8px;
60 color: white;
61 }
62
63 /* The submenu bar that *sometimes* appedis below the main menu */
64 div.submenu, div.sectionmenu {
65 padding: 3px 10px 3px 0px;
66 font-size: 0.9em;
67 text-align: center;
68 background-color: div.mainmenu a, div
--- a/skins/default/footer.txt
+++ b/skins/default/footer.txt
@@ -0,0 +1,3 @@
1
+<div class="footer">
2
+This page was generated in about
3
+<th1>puts [expr {([utime]+[stime]+1000)/100
--- a/skins/default/footer.txt
+++ b/skins/default/footer.txt
@@ -0,0 +1,3 @@
 
 
 
--- a/skins/default/footer.txt
+++ b/skins/default/footer.txt
@@ -0,0 +1,3 @@
1 <div class="footer">
2 This page was generated in about
3 <th1>puts [expr {([utime]+[stime]+1000)/100
--- a/skins/default/header.txt
+++ b/skins/default/header.txt
@@ -0,0 +1,3 @@
1
+reportlis� }her} Wiki wideonlhas {
2
+="her} Wiki wideonly
3
+}
--- a/skins/default/header.txt
+++ b/skins/default/header.txt
@@ -0,0 +1,3 @@
 
 
 
--- a/skins/default/header.txt
+++ b/skins/default/header.txt
@@ -0,0 +1,3 @@
1 reportlis� }her} Wiki wideonlhas {
2 ="her} Wiki wideonly
3 }
--- a/skins/eagle/css.txt
+++ b/skins/eagle/css.txt
@@ -0,0 +1 @@
1
+/#canvas#485D7B
--- a/skins/eagle/css.txt
+++ b/skins/eagle/css.txt
@@ -0,0 +1 @@
 
--- a/skins/eagle/css.txt
+++ b/skins/eagle/css.txt
@@ -0,0 +1 @@
1 /#canvas#485D7B
--- a/skins/eagle/footer.txt
+++ b/skins/eagle/footer.txt
@@ -0,0 +1,24 @@
1
+<div class="footer">
2
+ <th1>
3
+ proc getTclVersion {} {
4
+ if {[catch {tclEval info patchlevel} tclVersion] == 0} {
5
+ return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
6
+ }
7
+ return ""
8
+ }
9
+ proc getVersion { version } {
10
+ set length [string length $version]
11
+ return [string range $version 1 [expr {$length - 2}]]
12
+ }
13
+ set version [getVersion $manifest_version]
14
+ set tclVersion [getTclVersiowww.n]
15
+ set fossilUrl https://fossil-scm.org
16
+ set fossilDate [string range $manifest_date 0 9]T[string range $manifest_date 11 end]
17
+ </th1>
18
+ This page was generated in about
19
+ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
20
+ <a href="$fossilUrl/">Fossil</a>
21
+ version $release_version $tclVersion
22
+ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
23
+ <a href="$fossilUrl/index.html/timeline?c=$fossilDate&amp;div>
24
+</body></html>
--- a/skins/eagle/footer.txt
+++ b/skins/eagle/footer.txt
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/eagle/footer.txt
+++ b/skins/eagle/footer.txt
@@ -0,0 +1,24 @@
1 <div class="footer">
2 <th1>
3 proc getTclVersion {} {
4 if {[catch {tclEval info patchlevel} tclVersion] == 0} {
5 return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
6 }
7 return ""
8 }
9 proc getVersion { version } {
10 set length [string length $version]
11 return [string range $version 1 [expr {$length - 2}]]
12 }
13 set version [getVersion $manifest_version]
14 set tclVersion [getTclVersiowww.n]
15 set fossilUrl https://fossil-scm.org
16 set fossilDate [string range $manifest_date 0 9]T[string range $manifest_date 11 end]
17 </th1>
18 This page was generated in about
19 <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
20 <a href="$fossilUrl/">Fossil</a>
21 version $release_version $tclVersion
22 <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
23 <a href="$fossilUrl/index.html/timeline?c=$fossilDate&amp;div>
24 </body></html>
--- a/skins/eagle/header.txt
+++ b/skins/eagle/header.txt
@@ -0,0 +1,89 @@
1
+<html>
2
+<head>
3
+<base href="$baseurl/$current_page" />
4
+<title>$<project_name>: $<title></title>
5
+<link rel="alternate" type="application/rss+xml" title="RSS Feed"
6
+ href="$home/timeline.rss" />
7
+<link rel="stylesheet" href="$stylesheet_url" type="text/css"
8
+ media=<div class="header">
9
+ <div class="logo">
10
+ <th1>
11
+ ##
12
+ ## NOTE: The purpose of this procedure is to take the base URL of the
13
+ ## Fossil project and return the root of the entire web site using
14
+ ## the same URI scheme as the base URL (e.g. http or https).
15
+ ##
16
+ proc getLogoUrl { baseurl } {
17
+ set idx(first) [string first // $baseurl]
18
+ if {$idx(first) != -1} {
19
+ ##
20
+ ## NOTE: Skip second slash.
21
+ ##
22
+ set idx(first+1) [expr {$idx(first) + 2}]
23
+ ##
24
+ ## NOTE: (part 1) The [string first] command does NOT actually
25
+ ## support the optional startIndex argument as specified
26
+ ## in the TH1 support manual; therefore, we fake it by
27
+ ## using the [string range] command and then adding the
28
+ project_nameadding the
29
+ ## necessary offset to the result<th1>
30
+low). In Tc, we could use the following ins} elscript
31
+ </th1>
32
+ ##
33
+ set idx(nextRange) [string range $baseurl $idx(first+1) funcdivif {$iif(e){
34
+ ## NOTE: (part 2) Add thefunction f(n) {
35
+Add the nece}
36
+for the next slash (i.e the itial searnext) [exp}]
37
+ ##
38
+ ]
39
+ ##
40
+ ## }
41
+}
42
+next slash.
43
+ ><th1>
44
+set sitemap 0
45
+scheme and host fthe base URL.
46
+ ##
47
+ "updateClock();"$idx(first)]
48
+ sest [string range $baseurl $idx>
49
+ <th1>
50
+ ##
51
+ ## NOT
52
+<th1>
53
+proc menulink {url name} {
54
+name</a>\n"
55
+ }
56
+}
57
+menindex_page'>Home</a>\n"
58
+name</a>\n"
59
+ }
60
+}
61
+me/help'>Help<>$name</a>\n"
62
+ }
63
+}
64
+me/timeline'>Timeline</a>$name</a>\n"
65
+ }
66
+}
67
+me/tree?ci=tip'>Filhas>$name</a>\n"
68
+ }
69
+}
70
+me/brlist'>Branches</a>\n"
71
+>$name</a>\n"
72
+ }
73
+}
74
+hasaglist'>Tags</>$name</a>\n"
75
+ }
76
+}
77
+me/ticket'>Tickets</>$name</a>\n"
78
+ }
79
+}
80
+me/wikihashas name</a>\n"
81
+ }
82
+}
83
+me/setup_ulist'>Users</a>\n"<html>reportlisd>
84
+<base href="$baseuse href="$baseurl/$c/login'>Logout</a>\n"
85
+} else {
86
+>$name</a>\n"
87
+ }
88
+}
89
+me
--- a/skins/eagle/header.txt
+++ b/skins/eagle/header.txt
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/eagle/header.txt
+++ b/skins/eagle/header.txt
@@ -0,0 +1,89 @@
1 <html>
2 <head>
3 <base href="$baseurl/$current_page" />
4 <title>$<project_name>: $<title></title>
5 <link rel="alternate" type="application/rss+xml" title="RSS Feed"
6 href="$home/timeline.rss" />
7 <link rel="stylesheet" href="$stylesheet_url" type="text/css"
8 media=<div class="header">
9 <div class="logo">
10 <th1>
11 ##
12 ## NOTE: The purpose of this procedure is to take the base URL of the
13 ## Fossil project and return the root of the entire web site using
14 ## the same URI scheme as the base URL (e.g. http or https).
15 ##
16 proc getLogoUrl { baseurl } {
17 set idx(first) [string first // $baseurl]
18 if {$idx(first) != -1} {
19 ##
20 ## NOTE: Skip second slash.
21 ##
22 set idx(first+1) [expr {$idx(first) + 2}]
23 ##
24 ## NOTE: (part 1) The [string first] command does NOT actually
25 ## support the optional startIndex argument as specified
26 ## in the TH1 support manual; therefore, we fake it by
27 ## using the [string range] command and then adding the
28 project_nameadding the
29 ## necessary offset to the result<th1>
30 low). In Tc, we could use the following ins} elscript
31 </th1>
32 ##
33 set idx(nextRange) [string range $baseurl $idx(first+1) funcdivif {$iif(e){
34 ## NOTE: (part 2) Add thefunction f(n) {
35 Add the nece}
36 for the next slash (i.e the itial searnext) [exp}]
37 ##
38 ]
39 ##
40 ## }
41 }
42 next slash.
43 ><th1>
44 set sitemap 0
45 scheme and host fthe base URL.
46 ##
47 "updateClock();"$idx(first)]
48 sest [string range $baseurl $idx>
49 <th1>
50 ##
51 ## NOT
52 <th1>
53 proc menulink {url name} {
54 name</a>\n"
55 }
56 }
57 menindex_page'>Home</a>\n"
58 name</a>\n"
59 }
60 }
61 me/help'>Help<>$name</a>\n"
62 }
63 }
64 me/timeline'>Timeline</a>$name</a>\n"
65 }
66 }
67 me/tree?ci=tip'>Filhas>$name</a>\n"
68 }
69 }
70 me/brlist'>Branches</a>\n"
71 >$name</a>\n"
72 }
73 }
74 hasaglist'>Tags</>$name</a>\n"
75 }
76 }
77 me/ticket'>Tickets</>$name</a>\n"
78 }
79 }
80 me/wikihashas name</a>\n"
81 }
82 }
83 me/setup_ulist'>Users</a>\n"<html>reportlisd>
84 <base href="$baseuse href="$baseurl/$c/login'>Logout</a>\n"
85 } else {
86 >$name</a>\n"
87 }
88 }
89 me
--- a/skins/enhanced1/css.txt
+++ b/skins/enhanced1/css.txt
@@ -0,0 +1,68 @@
1
+/* General settings for the entire page */
2
+body {
3
+ margin: 0ex 1ex;
4
+ padding: 0px;
5
+ background-color: white;
6
+ font-family: sans-serif;
7
+mx-text-size-adjust: none;
8
+}
9
+
10
+/* The project logo in the upper left-hand corner of each page */
11
+div.logo {
12
+ display: table-cell;
13
+ text-align: center;
14
+ vertical-align: bottom;
15
+ font-weight: bold;
16
+ co20or: #558195;
17
+ min-width: 50px;
18
+ white-space: nowrap;
19
+}
20
+
21
+/* The page title centered at the top of each page */
22
+div.title {
23
+ display: table-cell;
24
+ font-size: 2em;
25
+ font-weight: bold;
26
+ text-align: center;
27
+ padding: 0 0 0 1em;
28
+ color: #558195;
29
+ vertical-align: bottom;
30
+ width: 100%;
31
+}
32
+
33
+/* The login status message in the top right-hand corner */
34
+div.status {
35
+ display: table-cell;
36
+ text-align: right;
37
+ vertical-align: bottom;
38
+ color: #558195;
39
+ font-size: 0.8min-width: 20or: #558195e-space: nowrap;
40
+}
41
+
42
+/* The header across the top of the page */
43
+div.header {
44
+ display: table;
45
+ width: 100%;
46
+}
47
+
48
+/* The main menu bar that appears at the top of the page beneath
49
+** the header */
50
+diisplay: table;
51
+ winmenu {
52
+ padding: 5px;
53
+ font-size: 0.9em;
54
+ font-weight: bold;
55
+ text-align: center;
56
+ letter-spacing: 1px;
57
+ background-color: #558195;
58
+ border-top-left-radius: 8px;
59
+ border-top-right-radius: 8px;
60
+ color: white;
61
+}
62
+
63
+/* The submenu bar that *sometimes* appedis below the main menu */
64
+div.submenu, div.sectionmenu {
65
+ padding: 3px 10px 3px 0px;
66
+ font-size: 0.9em;
67
+ text-align: center;
68
+ background-color: div.mainmenu a, div
--- a/skins/enhanced1/css.txt
+++ b/skins/enhanced1/css.txt
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/enhanced1/css.txt
+++ b/skins/enhanced1/css.txt
@@ -0,0 +1,68 @@
1 /* General settings for the entire page */
2 body {
3 margin: 0ex 1ex;
4 padding: 0px;
5 background-color: white;
6 font-family: sans-serif;
7 mx-text-size-adjust: none;
8 }
9
10 /* The project logo in the upper left-hand corner of each page */
11 div.logo {
12 display: table-cell;
13 text-align: center;
14 vertical-align: bottom;
15 font-weight: bold;
16 co20or: #558195;
17 min-width: 50px;
18 white-space: nowrap;
19 }
20
21 /* The page title centered at the top of each page */
22 div.title {
23 display: table-cell;
24 font-size: 2em;
25 font-weight: bold;
26 text-align: center;
27 padding: 0 0 0 1em;
28 color: #558195;
29 vertical-align: bottom;
30 width: 100%;
31 }
32
33 /* The login status message in the top right-hand corner */
34 div.status {
35 display: table-cell;
36 text-align: right;
37 vertical-align: bottom;
38 color: #558195;
39 font-size: 0.8min-width: 20or: #558195e-space: nowrap;
40 }
41
42 /* The header across the top of the page */
43 div.header {
44 display: table;
45 width: 100%;
46 }
47
48 /* The main menu bar that appears at the top of the page beneath
49 ** the header */
50 diisplay: table;
51 winmenu {
52 padding: 5px;
53 font-size: 0.9em;
54 font-weight: bold;
55 text-align: center;
56 letter-spacing: 1px;
57 background-color: #558195;
58 border-top-left-radius: 8px;
59 border-top-right-radius: 8px;
60 color: white;
61 }
62
63 /* The submenu bar that *sometimes* appedis below the main menu */
64 div.submenu, div.sectionmenu {
65 padding: 3px 10px 3px 0px;
66 font-size: 0.9em;
67 text-align: center;
68 background-color: div.mainmenu a, div
--- a/skins/enhanced1/footer.txt
+++ b/skins/enhanced1/footer.txt
@@ -0,0 +1,23 @@
1
+<div class="footer">
2
+ <th1>
3
+ proc getTclVersion {} {
4
+ if {[catch {tclEval info patchlevel} tclVersion] == 0} {
5
+ return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
6
+ }
7
+ return ""
8
+ }
9
+ proc getVersion { version } {
10
+ set length [string length $version]
11
+ return [string range $version 1 [expr {$length - 2}]]
12
+ }
13
+ set version [getVersion $manifest_version]
14
+ set tclVersion [getTclVersiowww.n]
15
+ set fossilUrl https://fossil-scm.org
16
+ e $manifest_date 11 end]
17
+ </th1>
18
+ This page was generated in about
19
+ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
20
+ <a href="$fossilUrl/">Fossil</a>
21
+ version $release_version $tclVersion
22
+ <a href="$fossilUrl/index.html/info/$version">$manifest_vermanifest_date&amp;div>
23
+</body></html>
--- a/skins/enhanced1/footer.txt
+++ b/skins/enhanced1/footer.txt
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/enhanced1/footer.txt
+++ b/skins/enhanced1/footer.txt
@@ -0,0 +1,23 @@
1 <div class="footer">
2 <th1>
3 proc getTclVersion {} {
4 if {[catch {tclEval info patchlevel} tclVersion] == 0} {
5 return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
6 }
7 return ""
8 }
9 proc getVersion { version } {
10 set length [string length $version]
11 return [string range $version 1 [expr {$length - 2}]]
12 }
13 set version [getVersion $manifest_version]
14 set tclVersion [getTclVersiowww.n]
15 set fossilUrl https://fossil-scm.org
16 e $manifest_date 11 end]
17 </th1>
18 This page was generated in about
19 <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
20 <a href="$fossilUrl/">Fossil</a>
21 version $release_version $tclVersion
22 <a href="$fossilUrl/index.html/info/$version">$manifest_vermanifest_date&amp;div>
23 </body></html>
--- a/skins/enhanced1/header.txt
+++ b/skins/enhanced1/header.txt
@@ -0,0 +1,89 @@
1
+<html>
2
+<head>
3
+<base href="$baseurl/$current_page" />
4
+<title>$<project_name>: $<title></title>
5
+<link rel="alternate" type="application/rss+xml" title="RSS Feed"
6
+ href="$home/timeline.rss" />
7
+<link rel="stylesheet" href="$stylesheet_url" type="text/css"
8
+ media=<div class="header">
9
+ <div class="logo">
10
+ <th1>
11
+ ##
12
+ ## NOTE: The purpose of this procedure is to take the base URL of the
13
+ ## Fossil project and return the root of the entire web site using
14
+ ## the same URI scheme as the base URL (e.g. http or https).
15
+ ##
16
+ proc getLogoUrl { baseurl } {
17
+ set idx(first) [string first // $baseurl]
18
+ if {$idx(first) != -1} {
19
+ ##
20
+ ## NOTE: Skip second slash.
21
+ ##
22
+ set idx(first+1) [expr {$idx(first) + 2}]
23
+ ##
24
+ ## NOTE: (part 1) The [string first] command does NOT actually
25
+ ## support the optional startIndex argument as specified
26
+ ## in the TH1 support manual; therefore, we fake it by
27
+ ## using the [stange] command and then adding the
28
+ project_nameadding the
29
+ ## necessary offset to the result<th1>
30
+low). In Tc, we could use the following ins} elscript
31
+ </th1>
32
+ ##
33
+ set idx(nextRange) [string range $baseurl $idx(first+1) funcdivif {$iif(e){
34
+ ## NOTE: (part 2) Add thefunction f(n) {
35
+Add the nece}
36
+for the next slash (i.e the itial searnext) [exp}]
37
+ ##
38
+ ]
39
+ ##
40
+ ## }
41
+}
42
+next slash.
43
+ ><th1>
44
+set sitemap 0
45
+scheme and host fthe base URL.
46
+ ##
47
+ "updateClock();"$idx(first)]
48
+ sest [string range $baseurl $idx>
49
+ <th1>
50
+ ##
51
+ ## NOT
52
+<th1>
53
+proc menulink {url name} {
54
+name</a>\n"
55
+ }
56
+}
57
+menindex_page'>Home</a>\n"
58
+name</a>\n"
59
+ }
60
+}
61
+me/help'>Help<>$name</a>\n"
62
+ }
63
+}
64
+me/timeline'>Timeline</a>$name</a>\n"
65
+ }
66
+}
67
+me/tree?ci=tip'>Filhas>$name</a>\n"
68
+ }
69
+}
70
+me/brlist'>Branches</a>\n"
71
+>$name</a>\n"
72
+ }
73
+}
74
+hasaglist'>Tags</>$name</a>\n"
75
+ }
76
+}
77
+me/ticket'>Tickets</>$name</a>\n"
78
+ }
79
+}
80
+me/wikihashas name</a>\n"
81
+ }
82
+}
83
+me/setup_ulist'>Users</a>\n"<html>reportlisd>
84
+<base href="$baseuse href="$baseurl/$c/login'>Logout</a>\n"
85
+} else {
86
+>$name</a>\n"
87
+ }
88
+}
89
+me
--- a/skins/enhanced1/header.txt
+++ b/skins/enhanced1/header.txt
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/enhanced1/header.txt
+++ b/skins/enhanced1/header.txt
@@ -0,0 +1,89 @@
1 <html>
2 <head>
3 <base href="$baseurl/$current_page" />
4 <title>$<project_name>: $<title></title>
5 <link rel="alternate" type="application/rss+xml" title="RSS Feed"
6 href="$home/timeline.rss" />
7 <link rel="stylesheet" href="$stylesheet_url" type="text/css"
8 media=<div class="header">
9 <div class="logo">
10 <th1>
11 ##
12 ## NOTE: The purpose of this procedure is to take the base URL of the
13 ## Fossil project and return the root of the entire web site using
14 ## the same URI scheme as the base URL (e.g. http or https).
15 ##
16 proc getLogoUrl { baseurl } {
17 set idx(first) [string first // $baseurl]
18 if {$idx(first) != -1} {
19 ##
20 ## NOTE: Skip second slash.
21 ##
22 set idx(first+1) [expr {$idx(first) + 2}]
23 ##
24 ## NOTE: (part 1) The [string first] command does NOT actually
25 ## support the optional startIndex argument as specified
26 ## in the TH1 support manual; therefore, we fake it by
27 ## using the [stange] command and then adding the
28 project_nameadding the
29 ## necessary offset to the result<th1>
30 low). In Tc, we could use the following ins} elscript
31 </th1>
32 ##
33 set idx(nextRange) [string range $baseurl $idx(first+1) funcdivif {$iif(e){
34 ## NOTE: (part 2) Add thefunction f(n) {
35 Add the nece}
36 for the next slash (i.e the itial searnext) [exp}]
37 ##
38 ]
39 ##
40 ## }
41 }
42 next slash.
43 ><th1>
44 set sitemap 0
45 scheme and host fthe base URL.
46 ##
47 "updateClock();"$idx(first)]
48 sest [string range $baseurl $idx>
49 <th1>
50 ##
51 ## NOT
52 <th1>
53 proc menulink {url name} {
54 name</a>\n"
55 }
56 }
57 menindex_page'>Home</a>\n"
58 name</a>\n"
59 }
60 }
61 me/help'>Help<>$name</a>\n"
62 }
63 }
64 me/timeline'>Timeline</a>$name</a>\n"
65 }
66 }
67 me/tree?ci=tip'>Filhas>$name</a>\n"
68 }
69 }
70 me/brlist'>Branches</a>\n"
71 >$name</a>\n"
72 }
73 }
74 hasaglist'>Tags</>$name</a>\n"
75 }
76 }
77 me/ticket'>Tickets</>$name</a>\n"
78 }
79 }
80 me/wikihashas name</a>\n"
81 }
82 }
83 me/setup_ulist'>Users</a>\n"<html>reportlisd>
84 <base href="$baseuse href="$baseurl/$c/login'>Logout</a>\n"
85 } else {
86 >$name</a>\n"
87 }
88 }
89 me
--- a/skins/etienne1/README.md
+++ b/skins/etienne1/README.md
@@ -0,0 +1 @@
1
+This skin was contributed by Étienne Deparis.
--- a/skins/etienne1/README.md
+++ b/skins/etienne1/README.md
@@ -0,0 +1 @@
 
--- a/skins/etienne1/README.md
+++ b/skins/etienne1/README.md
@@ -0,0 +1 @@
1 This skin was contributed by Étienne Deparis.
--- a/skins/etienne1/css.txt
+++ b/skins/etienne1/css.txt
@@ -0,0 +1,3 @@
1
+max-width: 33%.sub30max-width: width: 96max-max-width: 800px;5f9f}
2
+
3
+.submenu a:hover {bottom: 1px solid #fff;border: 0px,
--- a/skins/etienne1/css.txt
+++ b/skins/etienne1/css.txt
@@ -0,0 +1,3 @@
 
 
 
--- a/skins/etienne1/css.txt
+++ b/skins/etienne1/css.txt
@@ -0,0 +1,3 @@
1 max-width: 33%.sub30max-width: width: 96max-max-width: 800px;5f9f}
2
3 .submenu a:hover {bottom: 1px solid #fff;border: 0px,
--- a/skins/etienne1/footer.txt
+++ b/skins/etienne1/footer.txt
@@ -0,0 +1,3 @@
1
+<div class="footer">
2
+This page was generated in about
3
+<th1>puts [expr {([utime]+[stime]+1000)/100
--- a/skins/etienne1/footer.txt
+++ b/skins/etienne1/footer.txt
@@ -0,0 +1,3 @@
 
 
 
--- a/skins/etienne1/footer.txt
+++ b/skins/etienne1/footer.txt
@@ -0,0 +1,3 @@
1 <div class="footer">
2 This page was generated in about
3 <th1>puts [expr {([utime]+[stime]+1000)/100
--- a/skins/etienne1/header.txt
+++ b/skins/etienne1/header.txt
@@ -0,0 +1,27 @@
1
+<html>
2
+ <head>
3
+ <base href="$baseurl/$current_page" />
4
+ <title>$<project_name>: $<title></title>
5
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
6
+ href="$home/timeline.rss" />
7
+ <lihome/style.css?default" type="text/css"
8
+ media="screen" />
9
+ </head>
10
+
11
+ <bodyth1>
12
+ if {[info exheader">
13
+ t_name">
14
+ </a>
15
+ <<h1>$<project_name></h1>$<title>us"><th1>
16
+ 1>
17
+ if {[info exists login]} {
18
+ if {[info exists login]} {
19
+ } els$login — } els} } else {
20
+ t h$login</a>\n"
21
+ }
22
+ h1>
23
+ if {[info exmainmbtn' href='$proc menulink {url name} {
24
+ upvar current_page current
25
+ upvar home homa h <th1>
26
+proc isin {val lst} {
27
+ set tot [llreportlisrep
--- a/skins/etienne1/header.txt
+++ b/skins/etienne1/header.txt
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/etienne1/header.txt
+++ b/skins/etienne1/header.txt
@@ -0,0 +1,27 @@
1 <html>
2 <head>
3 <base href="$baseurl/$current_page" />
4 <title>$<project_name>: $<title></title>
5 <link rel="alternate" type="application/rss+xml" title="RSS Feed"
6 href="$home/timeline.rss" />
7 <lihome/style.css?default" type="text/css"
8 media="screen" />
9 </head>
10
11 <bodyth1>
12 if {[info exheader">
13 t_name">
14 </a>
15 <<h1>$<project_name></h1>$<title>us"><th1>
16 1>
17 if {[info exists login]} {
18 if {[info exists login]} {
19 } els$login — } els} } else {
20 t h$login</a>\n"
21 }
22 h1>
23 if {[info exmainmbtn' href='$proc menulink {url name} {
24 upvar current_page current
25 upvar home homa h <th1>
26 proc isin {val lst} {
27 set tot [llreportlisrep
--- a/skins/khaki/css.txt
+++ b/skins/khaki/css.txt
@@ -0,0 +1 @@
1
+/* General settings for t
--- a/skins/khaki/css.txt
+++ b/skins/khaki/css.txt
@@ -0,0 +1 @@
 
--- a/skins/khaki/css.txt
+++ b/skins/khaki/css.txt
@@ -0,0 +1 @@
1 /* General settings for t
--- a/skins/khaki/footer.txt
+++ b/skins/khaki/footer.txt
@@ -0,0 +1 @@
1
+<
--- a/skins/khaki/footer.txt
+++ b/skins/khaki/footer.txt
@@ -0,0 +1 @@
 
--- a/skins/khaki/footer.txt
+++ b/skins/khaki/footer.txt
@@ -0,0 +1 @@
1 <
--- a/skins/khaki/header.txt
+++ b/skins/khaki/header.txt
@@ -0,0 +1,18 @@
1
+<div class="header">
2
+ <div class="title">$<title></div>
3
+ <div class="status">
4
+ <div class="logo">$<project_name>if {[info exists login]} {
5
+ o exists login]} {
6
+ puts } else {
7
+ puts "Not logged in"
8
+ }
9
+ </th1></div>
10
+</he><th1>
11
+html "<a id='hbbtndiv>
12
+<dime/sitemap' aria-la
13
+<th1>
14
+home$index_page'>Homehome/timeline'>Timeline</home/tree?ci=tip'>Files<home/brlist'>Branches</a>\n"home/taglist'>Tags</a>\n"
15
+}
16
+if {[anycap 23456] || [anoncap 2] || [anoncap 3]} {home/forum'>Forum<home/ticket'>Tickets<home/wiki'>Wikihome/setup'>Admin</a>home/setup_ulist'>Users</a>\n"
17
+}
18
+ o exists loginoncap rhascap ohhascap ohascap hasreportlis
--- a/skins/khaki/header.txt
+++ b/skins/khaki/header.txt
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/khaki/header.txt
+++ b/skins/khaki/header.txt
@@ -0,0 +1,18 @@
1 <div class="header">
2 <div class="title">$<title></div>
3 <div class="status">
4 <div class="logo">$<project_name>if {[info exists login]} {
5 o exists login]} {
6 puts } else {
7 puts "Not logged in"
8 }
9 </th1></div>
10 </he><th1>
11 html "<a id='hbbtndiv>
12 <dime/sitemap' aria-la
13 <th1>
14 home$index_page'>Homehome/timeline'>Timeline</home/tree?ci=tip'>Files<home/brlist'>Branches</a>\n"home/taglist'>Tags</a>\n"
15 }
16 if {[anycap 23456] || [anoncap 2] || [anoncap 3]} {home/forum'>Forum<home/ticket'>Tickets<home/wiki'>Wikihome/setup'>Admin</a>home/setup_ulist'>Users</a>\n"
17 }
18 o exists loginoncap rhascap ohhascap ohascap hasreportlis
--- a/skins/plain_gray/css.txt
+++ b/skins/plain_gray/css.txt
@@ -0,0 +1,6 @@
1
+/* General settings for the entire page */
2
+body {
3
+ margin: 0ex 1ex;
4
+ padding: 0px;
5
+ background-color: white;
6
+ font-family: sans-serif;
--- a/skins/plain_gray/css.txt
+++ b/skins/plain_gray/css.txt
@@ -0,0 +1,6 @@
 
 
 
 
 
 
--- a/skins/plain_gray/css.txt
+++ b/skins/plain_gray/css.txt
@@ -0,0 +1,6 @@
1 /* General settings for the entire page */
2 body {
3 margin: 0ex 1ex;
4 padding: 0px;
5 background-color: white;
6 font-family: sans-serif;
--- a/skins/plain_gray/footer.txt
+++ b/skins/plain_gray/footer.txt
@@ -0,0 +1 @@
1
+<
--- a/skins/plain_gray/footer.txt
+++ b/skins/plain_gray/footer.txt
@@ -0,0 +1 @@
 
--- a/skins/plain_gray/footer.txt
+++ b/skins/plain_gray/footer.txt
@@ -0,0 +1 @@
1 <
--- a/skins/plain_gray/header.txt
+++ b/skins/plain_gray/header.txt
@@ -0,0 +1,13 @@
1
+<html>
2
+<head>
3
+<base href="$baseucap r: $<title></title>
4
+<link rel="alternate" type="application/rss+xml" title="RSS Feed"
5
+ href="$home/timeline.rss">
6
+<link rel="stylesheet" href="$stylesheet_url" type="text/css"
7
+ media="screen">
8
+</head>
9
+<body>
10
+<div class="headjoroncap rhashascap oase href="$baseucap r: $<tit<html>
11
+<head>
12
+<base href="$baseucap r: $<title></title>
13
+<link rel="alternathascap hasreportlis
--- a/skins/plain_gray/header.txt
+++ b/skins/plain_gray/header.txt
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/plain_gray/header.txt
+++ b/skins/plain_gray/header.txt
@@ -0,0 +1,13 @@
1 <html>
2 <head>
3 <base href="$baseucap r: $<title></title>
4 <link rel="alternate" type="application/rss+xml" title="RSS Feed"
5 href="$home/timeline.rss">
6 <link rel="stylesheet" href="$stylesheet_url" type="text/css"
7 media="screen">
8 </head>
9 <body>
10 <div class="headjoroncap rhashascap oase href="$baseucap r: $<tit<html>
11 <head>
12 <base href="$baseucap r: $<title></title>
13 <link rel="alternathascap hasreportlis
--- a/skins/rounded1/css.txt
+++ b/skins/rounded1/css.txt
@@ -0,0 +1,105 @@
1
+/* General settings for the entire page */
2
+html {
3
+ min-height: 100%;
4
+}
5
+body {
6
+ margin: 0ex 1ex;
7
+ padding: 0px;
8
+ background-color: white;
9
+ color: #333;
10
+ font-family: Verdana, sans-serif;
11
+ font-size: 0.8em;
12
+mx-text-size-adjust: none;
13
+}
14
+
15
+/* The project logo in the upper left-hand corner of each page */
16
+div.logo {
17
+ display: table-cell;
18
+ text-align: right;
19
+ vertical-align: bottom;
20
+ font-weight: normal;
21
+ white-space: nowrap;
22
+}
23
+
24
+/* Widths */
25
+div.header, div.mainmenu, div.submenu, div.content, div.footer {
26
+ max-width: 900px;
27
+ margin: auto;
28
+ padding: 3px 20px 3px 20px;
29
+ clear: both;
30
+}
31
+
32
+/* The page title at the top of each page */
33
+div.title {
34
+ display: table-cell;
35
+ padding-left: 10px;
36
+ font-size: 2em;
37
+ margin: 10px 0 10px -20px;
38
+ vertical-align: bottom;
39
+ text-align: left;
40
+ width: 80%;
41
+ font-family: Verdana, sans-serif;
42
+ font-weight: bold;
43
+ color: #558195;
44
+ text-shadow: 0px 2px 2px #999999;
45
+}
46
+
47
+/* The login status message in the top right-hand corner */
48
+div.status {
49
+ display: table-cell;
50
+ text-align: right;
51
+ vertical-align: bottom;
52
+ color: #333;
53
+ margin-right: -20px;
54
+ white-space: nowrap;
55
+}
56
+
57
+/* The main menu bar that appears at the top of the page beneath
58
+ ** the header */
59
+div.mainmenu {
60
+ text-align: center;
61
+ color: white;
62
+ border-top-left-radius: 5px;
63
+ border-top-right-radius: 5px;
64
+ vertical-align: middle;
65
+ padding-top: 8px;
66
+ padding-bottom: 8px;
67
+ background-color: #446979;
68
+ box-shadow: 0px 3px 4px #333333;
69
+}
70
+
71
+/* The submenu bar that *sometimes* appears below the main menu */
72
+div.submenu {
73
+ padding-top:10px;
74
+ padding-bottom:0;
75
+ text-align: right;
76
+ color: #000;
77
+ background-color: #fff;
78
+ height: 1.5em;
79
+ vertical-align:middle;
80
+ box-shadow: 0px 3px 4px #999;
81
+}
82
+div.mainmenu a, div.mainmenu a:visited {
83
+ padding: 3px 10px 3px 10px;
84
+ color: white;
85
+ text-decoration: none;
86
+}
87
+div.submenu a, div.submenu a:visited, .button, .button, div.submenu label,
88
+div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
89
+ padding: 2px 8px;
90
+ color: #000;
91
+ font-family: Arial;
92
+ text-decoration: none;
93
+ margin:auto;
94
+ border-radius: 5px;
95
+ background-color: #e0e0e0;
96
+ text-shadow: 0px -1px 0px #eee;
97
+ border: 1px solid #000;
98
+}
99
+
100
+div.mainmenu a:hover {
101
+ color: #000;
102
+ background-co cursor: pointercolor: white;
103
+}
104
+
105
+div.submenu a:hover, div: 10px 0
--- a/skins/rounded1/css.txt
+++ b/skins/rounded1/css.txt
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/rounded1/css.txt
+++ b/skins/rounded1/css.txt
@@ -0,0 +1,105 @@
1 /* General settings for the entire page */
2 html {
3 min-height: 100%;
4 }
5 body {
6 margin: 0ex 1ex;
7 padding: 0px;
8 background-color: white;
9 color: #333;
10 font-family: Verdana, sans-serif;
11 font-size: 0.8em;
12 mx-text-size-adjust: none;
13 }
14
15 /* The project logo in the upper left-hand corner of each page */
16 div.logo {
17 display: table-cell;
18 text-align: right;
19 vertical-align: bottom;
20 font-weight: normal;
21 white-space: nowrap;
22 }
23
24 /* Widths */
25 div.header, div.mainmenu, div.submenu, div.content, div.footer {
26 max-width: 900px;
27 margin: auto;
28 padding: 3px 20px 3px 20px;
29 clear: both;
30 }
31
32 /* The page title at the top of each page */
33 div.title {
34 display: table-cell;
35 padding-left: 10px;
36 font-size: 2em;
37 margin: 10px 0 10px -20px;
38 vertical-align: bottom;
39 text-align: left;
40 width: 80%;
41 font-family: Verdana, sans-serif;
42 font-weight: bold;
43 color: #558195;
44 text-shadow: 0px 2px 2px #999999;
45 }
46
47 /* The login status message in the top right-hand corner */
48 div.status {
49 display: table-cell;
50 text-align: right;
51 vertical-align: bottom;
52 color: #333;
53 margin-right: -20px;
54 white-space: nowrap;
55 }
56
57 /* The main menu bar that appears at the top of the page beneath
58 ** the header */
59 div.mainmenu {
60 text-align: center;
61 color: white;
62 border-top-left-radius: 5px;
63 border-top-right-radius: 5px;
64 vertical-align: middle;
65 padding-top: 8px;
66 padding-bottom: 8px;
67 background-color: #446979;
68 box-shadow: 0px 3px 4px #333333;
69 }
70
71 /* The submenu bar that *sometimes* appears below the main menu */
72 div.submenu {
73 padding-top:10px;
74 padding-bottom:0;
75 text-align: right;
76 color: #000;
77 background-color: #fff;
78 height: 1.5em;
79 vertical-align:middle;
80 box-shadow: 0px 3px 4px #999;
81 }
82 div.mainmenu a, div.mainmenu a:visited {
83 padding: 3px 10px 3px 10px;
84 color: white;
85 text-decoration: none;
86 }
87 div.submenu a, div.submenu a:visited, .button, .button, div.submenu label,
88 div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
89 padding: 2px 8px;
90 color: #000;
91 font-family: Arial;
92 text-decoration: none;
93 margin:auto;
94 border-radius: 5px;
95 background-color: #e0e0e0;
96 text-shadow: 0px -1px 0px #eee;
97 border: 1px solid #000;
98 }
99
100 div.mainmenu a:hover {
101 color: #000;
102 background-co cursor: pointercolor: white;
103 }
104
105 div.submenu a:hover, div: 10px 0
--- a/skins/rounded1/footer.txt
+++ b/skins/rounded1/footer.txt
@@ -0,0 +1 @@
1
+<
--- a/skins/rounded1/footer.txt
+++ b/skins/rounded1/footer.txt
@@ -0,0 +1 @@
 
--- a/skins/rounded1/footer.txt
+++ b/skins/rounded1/footer.txt
@@ -0,0 +1 @@
1 <
--- a/skins/rounded1/header.txt
+++ b/skins/rounded1/header.txt
@@ -0,0 +1,38 @@
1
+<div class="header">
2
+ <div class="logo">
3
+ <img src="$logo_image_url" alt="logo">
4
+ <br />$<project_name>
5
+ </div>
6
+ <div class="title">$<title></div>
7
+ <div class="status"><th1>
8
+ if {[info exists login]} {
9
+ puts "Logged in as $login"
10
+ } else {
11
+ puts "Not logged in"
12
+ }
13
+ </th1></div>
14
+</div>
15
+<div class="mainmenu">
16
+<th1>
17
+html "<a href='$home$index_page'>Home</a>\n"
18
+if {[anycap jor]} {
19
+ html "<a href='$home/} {
20
+ html "<a href='$home/timeline'>Timeline</a>\n"
21
+}
22
+if {[anoncap oh]} {
23
+ html "<a href='$home/tree?ci=tip'>Files</a>\n"
24
+}
25
+if {[anoncap o]} {
26
+ html "<a href='$home/brlist'>Branches</a>\n"
27
+ html "<a href='$home/tagoncap r]} {
28
+ html "<a href='$home/ticket'>Tickets</a>\n"
29
+}
30
+if {[anoncap j]} {
31
+ has"header">
32
+ <div class="logo">
33
+ <img src="$logo_image_url" alt="<div claeif {[hascap a]} {
34
+ html "<a href='$home/setup_ulist'>Users</a>\n"
35
+}
36
+ clashascap "<a href='$home/ticket'>Ticket} else {
37
+ html "<a href='$hhase {
38
+ html "<a href='$reportlislogin'>L
--- a/skins/rounded1/header.txt
+++ b/skins/rounded1/header.txt
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/skins/rounded1/header.txt
+++ b/skins/rounded1/header.txt
@@ -0,0 +1,38 @@
1 <div class="header">
2 <div class="logo">
3 <img src="$logo_image_url" alt="logo">
4 <br />$<project_name>
5 </div>
6 <div class="title">$<title></div>
7 <div class="status"><th1>
8 if {[info exists login]} {
9 puts "Logged in as $login"
10 } else {
11 puts "Not logged in"
12 }
13 </th1></div>
14 </div>
15 <div class="mainmenu">
16 <th1>
17 html "<a href='$home$index_page'>Home</a>\n"
18 if {[anycap jor]} {
19 html "<a href='$home/} {
20 html "<a href='$home/timeline'>Timeline</a>\n"
21 }
22 if {[anoncap oh]} {
23 html "<a href='$home/tree?ci=tip'>Files</a>\n"
24 }
25 if {[anoncap o]} {
26 html "<a href='$home/brlist'>Branches</a>\n"
27 html "<a href='$home/tagoncap r]} {
28 html "<a href='$home/ticket'>Tickets</a>\n"
29 }
30 if {[anoncap j]} {
31 has"header">
32 <div class="logo">
33 <img src="$logo_image_url" alt="<div claeif {[hascap a]} {
34 html "<a href='$home/setup_ulist'>Users</a>\n"
35 }
36 clashascap "<a href='$home/ticket'>Ticket} else {
37 html "<a href='$hhase {
38 html "<a href='$reportlislogin'>L
+2 -2
--- src/attach.c
+++ src/attach.c
@@ -90,12 +90,12 @@
9090
@ <li><p>
9191
@ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
9292
if( moderation_pending(attachid) ){
9393
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
9494
}
95
- @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
96
- @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
95
+ @ <br><a href="%R/attachview?%s(zUrlTail)">%h(zFilename)</a>
96
+ @ [<a href="%R/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
9797
if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
9898
if( zComment && zComment[0] ){
9999
@ %!w(zComment)<br />
100100
}
101101
if( zPage==0 && zTkt==0 ){
102102
--- src/attach.c
+++ src/attach.c
@@ -90,12 +90,12 @@
90 @ <li><p>
91 @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
92 if( moderation_pending(attachid) ){
93 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
94 }
95 @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
96 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
97 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
98 if( zComment && zComment[0] ){
99 @ %!w(zComment)<br />
100 }
101 if( zPage==0 && zTkt==0 ){
102
--- src/attach.c
+++ src/attach.c
@@ -90,12 +90,12 @@
90 @ <li><p>
91 @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
92 if( moderation_pending(attachid) ){
93 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
94 }
95 @ <br><a href="%R/attachview?%s(zUrlTail)">%h(zFilename)</a>
96 @ [<a href="%R/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
97 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
98 if( zComment && zComment[0] ){
99 @ %!w(zComment)<br />
100 }
101 if( zPage==0 && zTkt==0 ){
102
+154 -38
--- src/branch.c
+++ src/branch.c
@@ -179,47 +179,67 @@
179179
180180
/* Do an autosync push, if requested */
181181
if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries", 1));
182182
}
183183
184
+#if INTERFACE
185
+/*
186
+** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
187
+*/
188
+#define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */
189
+#define BRL_OPEN_ONLY 0x002 /* Show only open branches */
190
+#define BRL_BOTH 0x003 /* Show both open and closed branches */
191
+#define BRL_OPEN_CLOSED_MASK 0x003
192
+#define BRL_MTIME 0x004 /* Include lastest check-in time */
193
+#dfeine BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/
194
+
195
+#endif /* INTERFACE */
196
+
184197
/*
185198
** Prepare a query that will list branches.
186199
**
187200
** If (which<0) then the query pulls only closed branches. If
188201
** (which>0) then the query pulls all (closed and opened)
189202
** branches. Else the query pulls currently-opened branches.
190203
*/
191
-void branch_prepare_list_query(Stmt *pQuery, int which ){
192
- if( which < 0 ){
193
- db_prepare(pQuery,
194
- "SELECT value FROM tagxref"
195
- " WHERE tagid=%d AND value NOT NULL "
196
- "EXCEPT "
197
- "SELECT value FROM tagxref"
198
- " WHERE tagid=%d"
199
- " AND rid IN leaf"
200
- " AND NOT %z"
201
- " ORDER BY value COLLATE nocase /*sort*/",
202
- TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
203
- );
204
- }else if( which>0 ){
205
- db_prepare(pQuery,
206
- "SELECT DISTINCT value FROM tagxref"
207
- " WHERE tagid=%d AND value NOT NULL"
208
- " AND rid IN leaf"
209
- " ORDER BY value COLLATE nocase /*sort*/",
210
- TAG_BRANCH
211
- );
212
- }else{
213
- db_prepare(pQuery,
214
- "SELECT DISTINCT value FROM tagxref"
215
- " WHERE tagid=%d AND value NOT NULL"
216
- " AND rid IN leaf"
217
- " AND NOT %z"
218
- " ORDER BY value COLLATE nocase /*sort*/",
219
- TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
220
- );
204
+void branch_prepare_list_query(Stmt *pQuery, int brFlags){
205
+ switch( brFlags & BRL_OPEN_CLOSED_MASK ){
206
+ case BRL_CLOSED_ONLY: {
207
+ db_prepare(pQuery,
208
+ "SELECT value FROM tagxref"
209
+ " WHERE tagid=%d AND value NOT NULL "
210
+ "EXCEPT "
211
+ "SELECT value FROM tagxref"
212
+ " WHERE tagid=%d"
213
+ " AND rid IN leaf"
214
+ " AND NOT %z"
215
+ " ORDER BY value COLLATE nocase /*sort*/",
216
+ TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
217
+ );
218
+ break;
219
+ }
220
+ case BRL_BOTH: {
221
+ db_prepare(pQuery,
222
+ "SELECT DISTINCT value FROM tagxref"
223
+ " WHERE tagid=%d AND value NOT NULL"
224
+ " AND rid IN leaf"
225
+ " ORDER BY value COLLATE nocase /*sort*/",
226
+ TAG_BRANCH
227
+ );
228
+ break;
229
+ }
230
+ case BRL_OPEN_ONLY: {
231
+ db_prepare(pQuery,
232
+ "SELECT DISTINCT value FROM tagxref"
233
+ " WHERE tagid=%d AND value NOT NULL"
234
+ " AND rid IN leaf"
235
+ " AND NOT %z"
236
+ " ORDER BY value COLLATE nocase /*sort*/",
237
+ TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
238
+ );
239
+ break;
240
+ }
221241
}
222242
}
223243
224244
225245
/*
@@ -260,19 +280,20 @@
260280
branch_new();
261281
}else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
262282
Stmt q;
263283
int vid;
264284
char *zCurrent = 0;
265
- int showAll = find_option("all","a",0)!=0;
266
- int showClosed = find_option("closed","c",0)!=0;
285
+ int brFlags = BRL_OPEN_ONLY;
286
+ if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
287
+ if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;
267288
268289
if( g.localOpen ){
269290
vid = db_lget_int("checkout", 0);
270291
zCurrent = db_text(0, "SELECT value FROM tagxref"
271292
" WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
272293
}
273
- branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0));
294
+ branch_prepare_list_query(&q, brFlags);
274295
while( db_step(&q)==SQLITE_ROW ){
275296
const char *zBr = db_column_text(&q, 0);
276297
int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
277298
fossil_print("%s%s\n", (isCur ? "* " : " "), zBr);
278299
}
@@ -280,36 +301,131 @@
280301
}else{
281302
fossil_fatal("branch subcommand should be one of: "
282303
"new list ls");
283304
}
284305
}
306
+
307
+static const char brlistQuery[] =
308
+@ SELECT
309
+@ tagxref.value,
310
+@ max(event.mtime),
311
+@ EXISTS(SELECT 1 FROM tagxref AS tx
312
+@ WHERE tx.rid=tagxref.rid
313
+@ AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
314
+@ AND tx.tagtype>0),
315
+@ (SELECT tagxref.value
316
+@ FROM plink CROSS JOIN tagxref
317
+@ WHERE plink.pid=event.objid
318
+@ AND tagxref.rid=plink.cid
319
+@ AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
320
+@ AND tagtype>0),
321
+@ count(*),
322
+@ (SELECT uuid FROM blob WHERE rid=tagxref.rid)
323
+@ FROM tagxref, tag, event
324
+@ WHERE tagxref.tagid=tag.tagid
325
+@ AND tagxref.tagtype>0
326
+@ AND tag.tagname='branch'
327
+@ AND event.objid=tagxref.rid
328
+@ GROUP BY 1
329
+@ ORDER BY 2 DESC;
330
+;
331
+
332
+/*
333
+** This is the new-style branch-list page that shows the branch names
334
+** together with their ages (time of last check-in) and whether or not
335
+** they are closed or merged to another branch.
336
+**
337
+** Control jumps to this routine from brlist_page() (the /brlist handler)
338
+** if there are no query parameters.
339
+*/
340
+static void new_brlist_page(void){
341
+ Stmt q;
342
+ double rNow;
343
+ login_check_credentials();
344
+ if( !g.perm.Read ){ login_needed(); return; }
345
+ style_header("Branches");
346
+ style_adunit_config(ADUNIT_RIGHT_OK);
347
+ login_anonymous_available();
348
+
349
+ db_prepare(&q, brlistQuery/*works-like:""*/);
350
+ rNow = db_double(0.0, "SELECT julianday('now')");
351
+ @ <div class="brlist"><table id="branchlisttable">
352
+ @ <thead><tr>
353
+ @ <th>Branch Name</th>
354
+ @ <th>Age</th>
355
+ @ <th>Checkins</th>
356
+ @ <th>Status</th>
357
+ @ <th>Resolution</th>
358
+ @ </tr></thead><tbody>
359
+ while( db_step(&q)==SQLITE_ROW ){
360
+ const char *zBranch = db_column_text(&q, 0);
361
+ double rMtime = db_column_double(&q, 1);
362
+ int isClosed = db_column_int(&q, 2);
363
+ const char *zMergeTo = db_column_text(&q, 3);
364
+ int nCkin = db_column_int(&q, 4);
365
+ const char *zLastCkin = db_column_text(&q, 5);
366
+ char *zAge = human_readable_age(rNow - rMtime);
367
+ sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
368
+ if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
369
+ @ <tr>
370
+ @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td>
371
+ @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td>
372
+ @ <td>%d(nCkin)</td>
373
+ fossil_free(zAge);
374
+ @ <td>%s(isClosed?"closed":"")</td>
375
+ if( zMergeTo ){
376
+ @ <td>merged into
377
+ @ %z(href("%R/timeline?f=%s",zLastCkin))%h(zMergeTo)</a></td>
378
+ }else{
379
+ @ <td></td>
380
+ }
381
+ @ </tr>
382
+ }
383
+ @ </tbody></table></div>
384
+ db_finalize(&q);
385
+ output_table_sorting_javascript("branchlisttable","tkNtt",2);
386
+ style_footer();
387
+}
285388
286389
/*
287390
** WEBPAGE: brlist
391
+** Show a list of branches
392
+** Query parameters:
288393
**
289
-** Show a timeline of all branches
394
+** all Show all branches
395
+** closed Show only closed branches
396
+** open Show only open branches (default behavior)
397
+** colortest Show all branches with automatic color
290398
*/
291399
void brlist_page(void){
292400
Stmt q;
293401
int cnt;
294402
int showClosed = P("closed")!=0;
295403
int showAll = P("all")!=0;
404
+ int showOpen = P("open")!=0;
296405
int colorTest = P("colortest")!=0;
406
+ int brFlags = BRL_OPEN_ONLY;
297407
408
+ if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){
409
+ new_brlist_page();
410
+ return;
411
+ }
298412
login_check_credentials();
299413
if( !g.perm.Read ){ login_needed(); return; }
300414
if( colorTest ){
301415
showClosed = 0;
302416
showAll = 1;
303417
}
418
+ if( showAll ) brFlags = BRL_BOTH;
419
+ if( showClosed ) brFlags = BRL_CLOSED_ONLY;
304420
305421
style_header("%s", showClosed ? "Closed Branches" :
306422
showAll ? "All Branches" : "Open Branches");
307423
style_submenu_element("Timeline", "Timeline", "brtimeline");
308424
if( showClosed ){
309425
style_submenu_element("All", "All", "brlist?all");
310
- style_submenu_element("Open","Open","brlist");
426
+ style_submenu_element("Open","Open","brlist?open");
311427
}else if( showAll ){
312428
style_submenu_element("Closed", "Closed", "brlist?closed");
313429
style_submenu_element("Open","Open","brlist");
314430
}else{
315431
style_submenu_element("All", "All", "brlist?all");
@@ -335,21 +451,21 @@
335451
@ Closed branches are fixed and do not change (unless they are first
336452
@ reopened).</li>
337453
@ </ol>
338454
style_sidebox_end();
339455
340
- branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0));
456
+ branch_prepare_list_query(&q, brFlags);
341457
cnt = 0;
342458
while( db_step(&q)==SQLITE_ROW ){
343459
const char *zBr = db_column_text(&q, 0);
344460
if( cnt==0 ){
345461
if( colorTest ){
346462
@ <h2>Default background colors for all branches:</h2>
463
+ }else if( showClosed ){
464
+ @ <h2>Closed Branches:</h2>
347465
}else if( showAll ){
348466
@ <h2>All Branches:</h2>
349
- }else if( showClosed ){
350
- @ <h2>Closed Branches:</h2>
351467
}else{
352468
@ <h2>Open Branches:</h2>
353469
}
354470
@ <ul>
355471
cnt++;
356472
--- src/branch.c
+++ src/branch.c
@@ -179,47 +179,67 @@
179
180 /* Do an autosync push, if requested */
181 if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries", 1));
182 }
183
 
 
 
 
 
 
 
 
 
 
 
 
 
184 /*
185 ** Prepare a query that will list branches.
186 **
187 ** If (which<0) then the query pulls only closed branches. If
188 ** (which>0) then the query pulls all (closed and opened)
189 ** branches. Else the query pulls currently-opened branches.
190 */
191 void branch_prepare_list_query(Stmt *pQuery, int which ){
192 if( which < 0 ){
193 db_prepare(pQuery,
194 "SELECT value FROM tagxref"
195 " WHERE tagid=%d AND value NOT NULL "
196 "EXCEPT "
197 "SELECT value FROM tagxref"
198 " WHERE tagid=%d"
199 " AND rid IN leaf"
200 " AND NOT %z"
201 " ORDER BY value COLLATE nocase /*sort*/",
202 TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
203 );
204 }else if( which>0 ){
205 db_prepare(pQuery,
206 "SELECT DISTINCT value FROM tagxref"
207 " WHERE tagid=%d AND value NOT NULL"
208 " AND rid IN leaf"
209 " ORDER BY value COLLATE nocase /*sort*/",
210 TAG_BRANCH
211 );
212 }else{
213 db_prepare(pQuery,
214 "SELECT DISTINCT value FROM tagxref"
215 " WHERE tagid=%d AND value NOT NULL"
216 " AND rid IN leaf"
217 " AND NOT %z"
218 " ORDER BY value COLLATE nocase /*sort*/",
219 TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
220 );
 
 
 
 
 
 
 
221 }
222 }
223
224
225 /*
@@ -260,19 +280,20 @@
260 branch_new();
261 }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
262 Stmt q;
263 int vid;
264 char *zCurrent = 0;
265 int showAll = find_option("all","a",0)!=0;
266 int showClosed = find_option("closed","c",0)!=0;
 
267
268 if( g.localOpen ){
269 vid = db_lget_int("checkout", 0);
270 zCurrent = db_text(0, "SELECT value FROM tagxref"
271 " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
272 }
273 branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0));
274 while( db_step(&q)==SQLITE_ROW ){
275 const char *zBr = db_column_text(&q, 0);
276 int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
277 fossil_print("%s%s\n", (isCur ? "* " : " "), zBr);
278 }
@@ -280,36 +301,131 @@
280 }else{
281 fossil_fatal("branch subcommand should be one of: "
282 "new list ls");
283 }
284 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
286 /*
287 ** WEBPAGE: brlist
 
 
288 **
289 ** Show a timeline of all branches
 
 
 
290 */
291 void brlist_page(void){
292 Stmt q;
293 int cnt;
294 int showClosed = P("closed")!=0;
295 int showAll = P("all")!=0;
 
296 int colorTest = P("colortest")!=0;
 
297
 
 
 
 
298 login_check_credentials();
299 if( !g.perm.Read ){ login_needed(); return; }
300 if( colorTest ){
301 showClosed = 0;
302 showAll = 1;
303 }
 
 
304
305 style_header("%s", showClosed ? "Closed Branches" :
306 showAll ? "All Branches" : "Open Branches");
307 style_submenu_element("Timeline", "Timeline", "brtimeline");
308 if( showClosed ){
309 style_submenu_element("All", "All", "brlist?all");
310 style_submenu_element("Open","Open","brlist");
311 }else if( showAll ){
312 style_submenu_element("Closed", "Closed", "brlist?closed");
313 style_submenu_element("Open","Open","brlist");
314 }else{
315 style_submenu_element("All", "All", "brlist?all");
@@ -335,21 +451,21 @@
335 @ Closed branches are fixed and do not change (unless they are first
336 @ reopened).</li>
337 @ </ol>
338 style_sidebox_end();
339
340 branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0));
341 cnt = 0;
342 while( db_step(&q)==SQLITE_ROW ){
343 const char *zBr = db_column_text(&q, 0);
344 if( cnt==0 ){
345 if( colorTest ){
346 @ <h2>Default background colors for all branches:</h2>
 
 
347 }else if( showAll ){
348 @ <h2>All Branches:</h2>
349 }else if( showClosed ){
350 @ <h2>Closed Branches:</h2>
351 }else{
352 @ <h2>Open Branches:</h2>
353 }
354 @ <ul>
355 cnt++;
356
--- src/branch.c
+++ src/branch.c
@@ -179,47 +179,67 @@
179
180 /* Do an autosync push, if requested */
181 if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries", 1));
182 }
183
184 #if INTERFACE
185 /*
186 ** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
187 */
188 #define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */
189 #define BRL_OPEN_ONLY 0x002 /* Show only open branches */
190 #define BRL_BOTH 0x003 /* Show both open and closed branches */
191 #define BRL_OPEN_CLOSED_MASK 0x003
192 #define BRL_MTIME 0x004 /* Include lastest check-in time */
193 #dfeine BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/
194
195 #endif /* INTERFACE */
196
197 /*
198 ** Prepare a query that will list branches.
199 **
200 ** If (which<0) then the query pulls only closed branches. If
201 ** (which>0) then the query pulls all (closed and opened)
202 ** branches. Else the query pulls currently-opened branches.
203 */
204 void branch_prepare_list_query(Stmt *pQuery, int brFlags){
205 switch( brFlags & BRL_OPEN_CLOSED_MASK ){
206 case BRL_CLOSED_ONLY: {
207 db_prepare(pQuery,
208 "SELECT value FROM tagxref"
209 " WHERE tagid=%d AND value NOT NULL "
210 "EXCEPT "
211 "SELECT value FROM tagxref"
212 " WHERE tagid=%d"
213 " AND rid IN leaf"
214 " AND NOT %z"
215 " ORDER BY value COLLATE nocase /*sort*/",
216 TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
217 );
218 break;
219 }
220 case BRL_BOTH: {
221 db_prepare(pQuery,
222 "SELECT DISTINCT value FROM tagxref"
223 " WHERE tagid=%d AND value NOT NULL"
224 " AND rid IN leaf"
225 " ORDER BY value COLLATE nocase /*sort*/",
226 TAG_BRANCH
227 );
228 break;
229 }
230 case BRL_OPEN_ONLY: {
231 db_prepare(pQuery,
232 "SELECT DISTINCT value FROM tagxref"
233 " WHERE tagid=%d AND value NOT NULL"
234 " AND rid IN leaf"
235 " AND NOT %z"
236 " ORDER BY value COLLATE nocase /*sort*/",
237 TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
238 );
239 break;
240 }
241 }
242 }
243
244
245 /*
@@ -260,19 +280,20 @@
280 branch_new();
281 }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
282 Stmt q;
283 int vid;
284 char *zCurrent = 0;
285 int brFlags = BRL_OPEN_ONLY;
286 if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
287 if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;
288
289 if( g.localOpen ){
290 vid = db_lget_int("checkout", 0);
291 zCurrent = db_text(0, "SELECT value FROM tagxref"
292 " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
293 }
294 branch_prepare_list_query(&q, brFlags);
295 while( db_step(&q)==SQLITE_ROW ){
296 const char *zBr = db_column_text(&q, 0);
297 int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
298 fossil_print("%s%s\n", (isCur ? "* " : " "), zBr);
299 }
@@ -280,36 +301,131 @@
301 }else{
302 fossil_fatal("branch subcommand should be one of: "
303 "new list ls");
304 }
305 }
306
307 static const char brlistQuery[] =
308 @ SELECT
309 @ tagxref.value,
310 @ max(event.mtime),
311 @ EXISTS(SELECT 1 FROM tagxref AS tx
312 @ WHERE tx.rid=tagxref.rid
313 @ AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
314 @ AND tx.tagtype>0),
315 @ (SELECT tagxref.value
316 @ FROM plink CROSS JOIN tagxref
317 @ WHERE plink.pid=event.objid
318 @ AND tagxref.rid=plink.cid
319 @ AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
320 @ AND tagtype>0),
321 @ count(*),
322 @ (SELECT uuid FROM blob WHERE rid=tagxref.rid)
323 @ FROM tagxref, tag, event
324 @ WHERE tagxref.tagid=tag.tagid
325 @ AND tagxref.tagtype>0
326 @ AND tag.tagname='branch'
327 @ AND event.objid=tagxref.rid
328 @ GROUP BY 1
329 @ ORDER BY 2 DESC;
330 ;
331
332 /*
333 ** This is the new-style branch-list page that shows the branch names
334 ** together with their ages (time of last check-in) and whether or not
335 ** they are closed or merged to another branch.
336 **
337 ** Control jumps to this routine from brlist_page() (the /brlist handler)
338 ** if there are no query parameters.
339 */
340 static void new_brlist_page(void){
341 Stmt q;
342 double rNow;
343 login_check_credentials();
344 if( !g.perm.Read ){ login_needed(); return; }
345 style_header("Branches");
346 style_adunit_config(ADUNIT_RIGHT_OK);
347 login_anonymous_available();
348
349 db_prepare(&q, brlistQuery/*works-like:""*/);
350 rNow = db_double(0.0, "SELECT julianday('now')");
351 @ <div class="brlist"><table id="branchlisttable">
352 @ <thead><tr>
353 @ <th>Branch Name</th>
354 @ <th>Age</th>
355 @ <th>Checkins</th>
356 @ <th>Status</th>
357 @ <th>Resolution</th>
358 @ </tr></thead><tbody>
359 while( db_step(&q)==SQLITE_ROW ){
360 const char *zBranch = db_column_text(&q, 0);
361 double rMtime = db_column_double(&q, 1);
362 int isClosed = db_column_int(&q, 2);
363 const char *zMergeTo = db_column_text(&q, 3);
364 int nCkin = db_column_int(&q, 4);
365 const char *zLastCkin = db_column_text(&q, 5);
366 char *zAge = human_readable_age(rNow - rMtime);
367 sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
368 if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
369 @ <tr>
370 @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td>
371 @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td>
372 @ <td>%d(nCkin)</td>
373 fossil_free(zAge);
374 @ <td>%s(isClosed?"closed":"")</td>
375 if( zMergeTo ){
376 @ <td>merged into
377 @ %z(href("%R/timeline?f=%s",zLastCkin))%h(zMergeTo)</a></td>
378 }else{
379 @ <td></td>
380 }
381 @ </tr>
382 }
383 @ </tbody></table></div>
384 db_finalize(&q);
385 output_table_sorting_javascript("branchlisttable","tkNtt",2);
386 style_footer();
387 }
388
389 /*
390 ** WEBPAGE: brlist
391 ** Show a list of branches
392 ** Query parameters:
393 **
394 ** all Show all branches
395 ** closed Show only closed branches
396 ** open Show only open branches (default behavior)
397 ** colortest Show all branches with automatic color
398 */
399 void brlist_page(void){
400 Stmt q;
401 int cnt;
402 int showClosed = P("closed")!=0;
403 int showAll = P("all")!=0;
404 int showOpen = P("open")!=0;
405 int colorTest = P("colortest")!=0;
406 int brFlags = BRL_OPEN_ONLY;
407
408 if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){
409 new_brlist_page();
410 return;
411 }
412 login_check_credentials();
413 if( !g.perm.Read ){ login_needed(); return; }
414 if( colorTest ){
415 showClosed = 0;
416 showAll = 1;
417 }
418 if( showAll ) brFlags = BRL_BOTH;
419 if( showClosed ) brFlags = BRL_CLOSED_ONLY;
420
421 style_header("%s", showClosed ? "Closed Branches" :
422 showAll ? "All Branches" : "Open Branches");
423 style_submenu_element("Timeline", "Timeline", "brtimeline");
424 if( showClosed ){
425 style_submenu_element("All", "All", "brlist?all");
426 style_submenu_element("Open","Open","brlist?open");
427 }else if( showAll ){
428 style_submenu_element("Closed", "Closed", "brlist?closed");
429 style_submenu_element("Open","Open","brlist");
430 }else{
431 style_submenu_element("All", "All", "brlist?all");
@@ -335,21 +451,21 @@
451 @ Closed branches are fixed and do not change (unless they are first
452 @ reopened).</li>
453 @ </ol>
454 style_sidebox_end();
455
456 branch_prepare_list_query(&q, brFlags);
457 cnt = 0;
458 while( db_step(&q)==SQLITE_ROW ){
459 const char *zBr = db_column_text(&q, 0);
460 if( cnt==0 ){
461 if( colorTest ){
462 @ <h2>Default background colors for all branches:</h2>
463 }else if( showClosed ){
464 @ <h2>Closed Branches:</h2>
465 }else if( showAll ){
466 @ <h2>All Branches:</h2>
 
 
467 }else{
468 @ <h2>Open Branches:</h2>
469 }
470 @ <ul>
471 cnt++;
472
+10 -3
--- src/browse.c
+++ src/browse.c
@@ -133,10 +133,11 @@
133133
if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
134134
login_check_credentials();
135135
if( !g.perm.Read ){ login_needed(); return; }
136136
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
137137
style_header("File List");
138
+ style_adunit_config(ADUNIT_RIGHT_OK);
138139
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
139140
pathelementFunc, 0, 0);
140141
url_initialize(&sURI, "dir");
141142
142143
/* If the name= parameter is an empty string, make it a NULL pointer */
@@ -555,10 +556,11 @@
555556
style_header("Folder Hierarchy");
556557
}else{
557558
showDirOnly = 0;
558559
style_header("File Tree");
559560
}
561
+ style_adunit_config(ADUNIT_RIGHT_OK);
560562
if( P("expand")!=0 ){
561563
startExpanded = 1;
562564
url_add_parameter(&sURI, "expand", "1");
563565
}else{
564566
startExpanded = 0;
@@ -635,10 +637,12 @@
635637
}
636638
if( linkTip ){
637639
style_submenu_element("Tip", "Tip", "%s",
638640
url_render(&sURI, "ci", "tip", 0, 0));
639641
}
642
+ style_submenu_element("Flat-View", "Flat-View", "%s",
643
+ url_render(&sURI, "type", "flat", 0, 0));
640644
641645
/* Compute the file hierarchy.
642646
*/
643647
if( zCI ){
644648
Stmt q;
@@ -652,10 +656,13 @@
652656
);
653657
while( db_step(&q)==SQLITE_ROW ){
654658
const char *zFile = db_column_text(&q,0);
655659
const char *zUuid = db_column_text(&q,1);
656660
double mtime = db_column_double(&q,2);
661
+ if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){
662
+ continue;
663
+ }
657664
if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
658665
tree_add_node(&sTree, zFile, zUuid, mtime);
659666
nFile++;
660667
}
661668
db_finalize(&q);
@@ -931,11 +938,11 @@
931938
932939
/*
933940
** SQL used to compute the age of all files in checkin :ckin whose
934941
** names match :glob
935942
*/
936
-static const char zComputeFileAgeSetup[] =
943
+static const char zComputeFileAgeSetup[] =
937944
@ CREATE TABLE IF NOT EXISTS temp.fileage(
938945
@ fnid INTEGER PRIMARY KEY,
939946
@ fid INTEGER,
940947
@ mid INTEGER,
941948
@ mtime DATETIME,
@@ -942,11 +949,11 @@
942949
@ pathname TEXT
943950
@ );
944951
@ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
945952
;
946953
947
-static const char zComputeFileAgeRun[] =
954
+static const char zComputeFileAgeRun[] =
948955
@ WITH RECURSIVE
949956
@ ckin(x) AS (VALUES(:ckin) UNION ALL
950957
@ SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
951958
@ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
952959
@ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@@ -1068,11 +1075,11 @@
10681075
style_header("File Ages");
10691076
zGlob = P("glob");
10701077
compute_fileage(rid,zGlob);
10711078
db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
10721079
1073
- @ <h2>Files in
1080
+ @ <h2>Files in
10741081
@ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
10751082
if( zGlob && zGlob[0] ){
10761083
@ that match "%h(zGlob)" and
10771084
}
10781085
@ ordered by check-in time</h2>
10791086
--- src/browse.c
+++ src/browse.c
@@ -133,10 +133,11 @@
133 if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
134 login_check_credentials();
135 if( !g.perm.Read ){ login_needed(); return; }
136 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
137 style_header("File List");
 
138 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
139 pathelementFunc, 0, 0);
140 url_initialize(&sURI, "dir");
141
142 /* If the name= parameter is an empty string, make it a NULL pointer */
@@ -555,10 +556,11 @@
555 style_header("Folder Hierarchy");
556 }else{
557 showDirOnly = 0;
558 style_header("File Tree");
559 }
 
560 if( P("expand")!=0 ){
561 startExpanded = 1;
562 url_add_parameter(&sURI, "expand", "1");
563 }else{
564 startExpanded = 0;
@@ -635,10 +637,12 @@
635 }
636 if( linkTip ){
637 style_submenu_element("Tip", "Tip", "%s",
638 url_render(&sURI, "ci", "tip", 0, 0));
639 }
 
 
640
641 /* Compute the file hierarchy.
642 */
643 if( zCI ){
644 Stmt q;
@@ -652,10 +656,13 @@
652 );
653 while( db_step(&q)==SQLITE_ROW ){
654 const char *zFile = db_column_text(&q,0);
655 const char *zUuid = db_column_text(&q,1);
656 double mtime = db_column_double(&q,2);
 
 
 
657 if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
658 tree_add_node(&sTree, zFile, zUuid, mtime);
659 nFile++;
660 }
661 db_finalize(&q);
@@ -931,11 +938,11 @@
931
932 /*
933 ** SQL used to compute the age of all files in checkin :ckin whose
934 ** names match :glob
935 */
936 static const char zComputeFileAgeSetup[] =
937 @ CREATE TABLE IF NOT EXISTS temp.fileage(
938 @ fnid INTEGER PRIMARY KEY,
939 @ fid INTEGER,
940 @ mid INTEGER,
941 @ mtime DATETIME,
@@ -942,11 +949,11 @@
942 @ pathname TEXT
943 @ );
944 @ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
945 ;
946
947 static const char zComputeFileAgeRun[] =
948 @ WITH RECURSIVE
949 @ ckin(x) AS (VALUES(:ckin) UNION ALL
950 @ SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
951 @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
952 @ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@@ -1068,11 +1075,11 @@
1068 style_header("File Ages");
1069 zGlob = P("glob");
1070 compute_fileage(rid,zGlob);
1071 db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
1072
1073 @ <h2>Files in
1074 @ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
1075 if( zGlob && zGlob[0] ){
1076 @ that match "%h(zGlob)" and
1077 }
1078 @ ordered by check-in time</h2>
1079
--- src/browse.c
+++ src/browse.c
@@ -133,10 +133,11 @@
133 if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
134 login_check_credentials();
135 if( !g.perm.Read ){ login_needed(); return; }
136 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
137 style_header("File List");
138 style_adunit_config(ADUNIT_RIGHT_OK);
139 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
140 pathelementFunc, 0, 0);
141 url_initialize(&sURI, "dir");
142
143 /* If the name= parameter is an empty string, make it a NULL pointer */
@@ -555,10 +556,11 @@
556 style_header("Folder Hierarchy");
557 }else{
558 showDirOnly = 0;
559 style_header("File Tree");
560 }
561 style_adunit_config(ADUNIT_RIGHT_OK);
562 if( P("expand")!=0 ){
563 startExpanded = 1;
564 url_add_parameter(&sURI, "expand", "1");
565 }else{
566 startExpanded = 0;
@@ -635,10 +637,12 @@
637 }
638 if( linkTip ){
639 style_submenu_element("Tip", "Tip", "%s",
640 url_render(&sURI, "ci", "tip", 0, 0));
641 }
642 style_submenu_element("Flat-View", "Flat-View", "%s",
643 url_render(&sURI, "type", "flat", 0, 0));
644
645 /* Compute the file hierarchy.
646 */
647 if( zCI ){
648 Stmt q;
@@ -652,10 +656,13 @@
656 );
657 while( db_step(&q)==SQLITE_ROW ){
658 const char *zFile = db_column_text(&q,0);
659 const char *zUuid = db_column_text(&q,1);
660 double mtime = db_column_double(&q,2);
661 if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){
662 continue;
663 }
664 if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
665 tree_add_node(&sTree, zFile, zUuid, mtime);
666 nFile++;
667 }
668 db_finalize(&q);
@@ -931,11 +938,11 @@
938
939 /*
940 ** SQL used to compute the age of all files in checkin :ckin whose
941 ** names match :glob
942 */
943 static const char zComputeFileAgeSetup[] =
944 @ CREATE TABLE IF NOT EXISTS temp.fileage(
945 @ fnid INTEGER PRIMARY KEY,
946 @ fid INTEGER,
947 @ mid INTEGER,
948 @ mtime DATETIME,
@@ -942,11 +949,11 @@
949 @ pathname TEXT
950 @ );
951 @ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
952 ;
953
954 static const char zComputeFileAgeRun[] =
955 @ WITH RECURSIVE
956 @ ckin(x) AS (VALUES(:ckin) UNION ALL
957 @ SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
958 @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
959 @ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@@ -1068,11 +1075,11 @@
1075 style_header("File Ages");
1076 zGlob = P("glob");
1077 compute_fileage(rid,zGlob);
1078 db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
1079
1080 @ <h2>Files in
1081 @ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
1082 if( zGlob && zGlob[0] ){
1083 @ that match "%h(zGlob)" and
1084 }
1085 @ ordered by check-in time</h2>
1086
+10 -3
--- src/browse.c
+++ src/browse.c
@@ -133,10 +133,11 @@
133133
if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
134134
login_check_credentials();
135135
if( !g.perm.Read ){ login_needed(); return; }
136136
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
137137
style_header("File List");
138
+ style_adunit_config(ADUNIT_RIGHT_OK);
138139
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
139140
pathelementFunc, 0, 0);
140141
url_initialize(&sURI, "dir");
141142
142143
/* If the name= parameter is an empty string, make it a NULL pointer */
@@ -555,10 +556,11 @@
555556
style_header("Folder Hierarchy");
556557
}else{
557558
showDirOnly = 0;
558559
style_header("File Tree");
559560
}
561
+ style_adunit_config(ADUNIT_RIGHT_OK);
560562
if( P("expand")!=0 ){
561563
startExpanded = 1;
562564
url_add_parameter(&sURI, "expand", "1");
563565
}else{
564566
startExpanded = 0;
@@ -635,10 +637,12 @@
635637
}
636638
if( linkTip ){
637639
style_submenu_element("Tip", "Tip", "%s",
638640
url_render(&sURI, "ci", "tip", 0, 0));
639641
}
642
+ style_submenu_element("Flat-View", "Flat-View", "%s",
643
+ url_render(&sURI, "type", "flat", 0, 0));
640644
641645
/* Compute the file hierarchy.
642646
*/
643647
if( zCI ){
644648
Stmt q;
@@ -652,10 +656,13 @@
652656
);
653657
while( db_step(&q)==SQLITE_ROW ){
654658
const char *zFile = db_column_text(&q,0);
655659
const char *zUuid = db_column_text(&q,1);
656660
double mtime = db_column_double(&q,2);
661
+ if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){
662
+ continue;
663
+ }
657664
if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
658665
tree_add_node(&sTree, zFile, zUuid, mtime);
659666
nFile++;
660667
}
661668
db_finalize(&q);
@@ -931,11 +938,11 @@
931938
932939
/*
933940
** SQL used to compute the age of all files in checkin :ckin whose
934941
** names match :glob
935942
*/
936
-static const char zComputeFileAgeSetup[] =
943
+static const char zComputeFileAgeSetup[] =
937944
@ CREATE TABLE IF NOT EXISTS temp.fileage(
938945
@ fnid INTEGER PRIMARY KEY,
939946
@ fid INTEGER,
940947
@ mid INTEGER,
941948
@ mtime DATETIME,
@@ -942,11 +949,11 @@
942949
@ pathname TEXT
943950
@ );
944951
@ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
945952
;
946953
947
-static const char zComputeFileAgeRun[] =
954
+static const char zComputeFileAgeRun[] =
948955
@ WITH RECURSIVE
949956
@ ckin(x) AS (VALUES(:ckin) UNION ALL
950957
@ SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
951958
@ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
952959
@ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@@ -1068,11 +1075,11 @@
10681075
style_header("File Ages");
10691076
zGlob = P("glob");
10701077
compute_fileage(rid,zGlob);
10711078
db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
10721079
1073
- @ <h2>Files in
1080
+ @ <h2>Files in
10741081
@ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
10751082
if( zGlob && zGlob[0] ){
10761083
@ that match "%h(zGlob)" and
10771084
}
10781085
@ ordered by check-in time</h2>
10791086
--- src/browse.c
+++ src/browse.c
@@ -133,10 +133,11 @@
133 if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
134 login_check_credentials();
135 if( !g.perm.Read ){ login_needed(); return; }
136 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
137 style_header("File List");
 
138 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
139 pathelementFunc, 0, 0);
140 url_initialize(&sURI, "dir");
141
142 /* If the name= parameter is an empty string, make it a NULL pointer */
@@ -555,10 +556,11 @@
555 style_header("Folder Hierarchy");
556 }else{
557 showDirOnly = 0;
558 style_header("File Tree");
559 }
 
560 if( P("expand")!=0 ){
561 startExpanded = 1;
562 url_add_parameter(&sURI, "expand", "1");
563 }else{
564 startExpanded = 0;
@@ -635,10 +637,12 @@
635 }
636 if( linkTip ){
637 style_submenu_element("Tip", "Tip", "%s",
638 url_render(&sURI, "ci", "tip", 0, 0));
639 }
 
 
640
641 /* Compute the file hierarchy.
642 */
643 if( zCI ){
644 Stmt q;
@@ -652,10 +656,13 @@
652 );
653 while( db_step(&q)==SQLITE_ROW ){
654 const char *zFile = db_column_text(&q,0);
655 const char *zUuid = db_column_text(&q,1);
656 double mtime = db_column_double(&q,2);
 
 
 
657 if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
658 tree_add_node(&sTree, zFile, zUuid, mtime);
659 nFile++;
660 }
661 db_finalize(&q);
@@ -931,11 +938,11 @@
931
932 /*
933 ** SQL used to compute the age of all files in checkin :ckin whose
934 ** names match :glob
935 */
936 static const char zComputeFileAgeSetup[] =
937 @ CREATE TABLE IF NOT EXISTS temp.fileage(
938 @ fnid INTEGER PRIMARY KEY,
939 @ fid INTEGER,
940 @ mid INTEGER,
941 @ mtime DATETIME,
@@ -942,11 +949,11 @@
942 @ pathname TEXT
943 @ );
944 @ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
945 ;
946
947 static const char zComputeFileAgeRun[] =
948 @ WITH RECURSIVE
949 @ ckin(x) AS (VALUES(:ckin) UNION ALL
950 @ SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
951 @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
952 @ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@@ -1068,11 +1075,11 @@
1068 style_header("File Ages");
1069 zGlob = P("glob");
1070 compute_fileage(rid,zGlob);
1071 db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
1072
1073 @ <h2>Files in
1074 @ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
1075 if( zGlob && zGlob[0] ){
1076 @ that match "%h(zGlob)" and
1077 }
1078 @ ordered by check-in time</h2>
1079
--- src/browse.c
+++ src/browse.c
@@ -133,10 +133,11 @@
133 if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
134 login_check_credentials();
135 if( !g.perm.Read ){ login_needed(); return; }
136 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
137 style_header("File List");
138 style_adunit_config(ADUNIT_RIGHT_OK);
139 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
140 pathelementFunc, 0, 0);
141 url_initialize(&sURI, "dir");
142
143 /* If the name= parameter is an empty string, make it a NULL pointer */
@@ -555,10 +556,11 @@
556 style_header("Folder Hierarchy");
557 }else{
558 showDirOnly = 0;
559 style_header("File Tree");
560 }
561 style_adunit_config(ADUNIT_RIGHT_OK);
562 if( P("expand")!=0 ){
563 startExpanded = 1;
564 url_add_parameter(&sURI, "expand", "1");
565 }else{
566 startExpanded = 0;
@@ -635,10 +637,12 @@
637 }
638 if( linkTip ){
639 style_submenu_element("Tip", "Tip", "%s",
640 url_render(&sURI, "ci", "tip", 0, 0));
641 }
642 style_submenu_element("Flat-View", "Flat-View", "%s",
643 url_render(&sURI, "type", "flat", 0, 0));
644
645 /* Compute the file hierarchy.
646 */
647 if( zCI ){
648 Stmt q;
@@ -652,10 +656,13 @@
656 );
657 while( db_step(&q)==SQLITE_ROW ){
658 const char *zFile = db_column_text(&q,0);
659 const char *zUuid = db_column_text(&q,1);
660 double mtime = db_column_double(&q,2);
661 if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){
662 continue;
663 }
664 if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
665 tree_add_node(&sTree, zFile, zUuid, mtime);
666 nFile++;
667 }
668 db_finalize(&q);
@@ -931,11 +938,11 @@
938
939 /*
940 ** SQL used to compute the age of all files in checkin :ckin whose
941 ** names match :glob
942 */
943 static const char zComputeFileAgeSetup[] =
944 @ CREATE TABLE IF NOT EXISTS temp.fileage(
945 @ fnid INTEGER PRIMARY KEY,
946 @ fid INTEGER,
947 @ mid INTEGER,
948 @ mtime DATETIME,
@@ -942,11 +949,11 @@
949 @ pathname TEXT
950 @ );
951 @ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
952 ;
953
954 static const char zComputeFileAgeRun[] =
955 @ WITH RECURSIVE
956 @ ckin(x) AS (VALUES(:ckin) UNION ALL
957 @ SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
958 @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
959 @ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@@ -1068,11 +1075,11 @@
1075 style_header("File Ages");
1076 zGlob = P("glob");
1077 compute_fileage(rid,zGlob);
1078 db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");
1079
1080 @ <h2>Files in
1081 @ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
1082 if( zGlob && zGlob[0] ){
1083 @ that match "%h(zGlob)" and
1084 }
1085 @ ordered by check-in time</h2>
1086
+10 -2
--- src/builtin.c
+++ src/builtin.c
@@ -31,22 +31,30 @@
3131
3232
/*
3333
** Return a pointer to built-in content
3434
*/
3535
const unsigned char *builtin_file(const char *zFilename, int *piSize){
36
- int lwr, upr, i;
36
+ int lwr, upr, i, c;
3737
lwr = 0;
3838
upr = sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]) - 1;
3939
while( upr>=lwr ){
4040
i = (upr+lwr)/2;
41
- if( strcmp(aBuiltinFiles[i].zName,zFilename)==0 ){
41
+ c = strcmp(aBuiltinFiles[i].zName,zFilename);
42
+ if( c<0 ){
43
+ lwr = i+1;
44
+ }else if( c>0 ){
45
+ upr = i-1;
46
+ }else{
4247
if( piSize ) *piSize = aBuiltinFiles[i].nByte;
4348
return aBuiltinFiles[i].pData;
4449
}
4550
}
4651
if( piSize ) *piSize = 0;
4752
return 0;
53
+}
54
+const char *builtin_text(const char *zFilename){
55
+ return (char*)builtin_file(zFilename, 0);
4856
}
4957
5058
/*
5159
** COMMAND: test-builtin-list
5260
**
5361
--- src/builtin.c
+++ src/builtin.c
@@ -31,22 +31,30 @@
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;
37 lwr = 0;
38 upr = sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]) - 1;
39 while( upr>=lwr ){
40 i = (upr+lwr)/2;
41 if( strcmp(aBuiltinFiles[i].zName,zFilename)==0 ){
 
 
 
 
 
42 if( piSize ) *piSize = aBuiltinFiles[i].nByte;
43 return aBuiltinFiles[i].pData;
44 }
45 }
46 if( piSize ) *piSize = 0;
47 return 0;
 
 
 
48 }
49
50 /*
51 ** COMMAND: test-builtin-list
52 **
53
--- src/builtin.c
+++ src/builtin.c
@@ -31,22 +31,30 @@
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 = sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]) - 1;
39 while( upr>=lwr ){
40 i = (upr+lwr)/2;
41 c = strcmp(aBuiltinFiles[i].zName,zFilename);
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
58 /*
59 ** COMMAND: test-builtin-list
60 **
61
+4 -1
--- src/cgi.c
+++ src/cgi.c
@@ -108,10 +108,13 @@
108108
** if it does and false if it does not.
109109
*/
110110
int cgi_header_contains(const char *zNeedle){
111111
return strstr(blob_str(&cgiContent[0]), zNeedle)!=0;
112112
}
113
+int cgi_body_contains(const char *zNeedle){
114
+ return strstr(blob_str(&cgiContent[1]), zNeedle)!=0;
115
+}
113116
114117
/*
115118
** Append reply content to what already exists.
116119
*/
117120
void cgi_append_content(const char *zData, int nAmt){
@@ -1753,11 +1756,11 @@
17531756
fd = dup(connection);
17541757
if( fd!=0 ) nErr++;
17551758
close(1);
17561759
fd = dup(connection);
17571760
if( fd!=1 ) nErr++;
1758
- if( !g.fHttpTrace && !g.fSqlTrace ){
1761
+ if( !g.fAnyTrace ){
17591762
close(2);
17601763
fd = dup(connection);
17611764
if( fd!=2 ) nErr++;
17621765
}
17631766
close(connection);
17641767
--- src/cgi.c
+++ src/cgi.c
@@ -108,10 +108,13 @@
108 ** if it does and false if it does not.
109 */
110 int cgi_header_contains(const char *zNeedle){
111 return strstr(blob_str(&cgiContent[0]), zNeedle)!=0;
112 }
 
 
 
113
114 /*
115 ** Append reply content to what already exists.
116 */
117 void cgi_append_content(const char *zData, int nAmt){
@@ -1753,11 +1756,11 @@
1753 fd = dup(connection);
1754 if( fd!=0 ) nErr++;
1755 close(1);
1756 fd = dup(connection);
1757 if( fd!=1 ) nErr++;
1758 if( !g.fHttpTrace && !g.fSqlTrace ){
1759 close(2);
1760 fd = dup(connection);
1761 if( fd!=2 ) nErr++;
1762 }
1763 close(connection);
1764
--- src/cgi.c
+++ src/cgi.c
@@ -108,10 +108,13 @@
108 ** if it does and false if it does not.
109 */
110 int cgi_header_contains(const char *zNeedle){
111 return strstr(blob_str(&cgiContent[0]), zNeedle)!=0;
112 }
113 int cgi_body_contains(const char *zNeedle){
114 return strstr(blob_str(&cgiContent[1]), zNeedle)!=0;
115 }
116
117 /*
118 ** Append reply content to what already exists.
119 */
120 void cgi_append_content(const char *zData, int nAmt){
@@ -1753,11 +1756,11 @@
1756 fd = dup(connection);
1757 if( fd!=0 ) nErr++;
1758 close(1);
1759 fd = dup(connection);
1760 if( fd!=1 ) nErr++;
1761 if( !g.fAnyTrace ){
1762 close(2);
1763 fd = dup(connection);
1764 if( fd!=2 ) nErr++;
1765 }
1766 close(connection);
1767
+13 -5
--- src/checkin.c
+++ src/checkin.c
@@ -213,11 +213,11 @@
213213
int showHdr = find_option("header",0,0)!=0;
214214
int verboseFlag = find_option("verbose","v",0)!=0;
215215
int cwdRelative = 0;
216216
db_must_be_within_tree();
217217
cwdRelative = determine_cwd_relative_option();
218
-
218
+
219219
/* We should be done with options.. */
220220
verify_all_options();
221221
222222
print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
223223
}
@@ -249,11 +249,11 @@
249249
int verboseFlag = find_option("verbose","v",0)!=0;
250250
int cwdRelative = 0;
251251
db_must_be_within_tree();
252252
/* 012345678901234 */
253253
cwdRelative = determine_cwd_relative_option();
254
-
254
+
255255
/* We should be done with options.. */
256256
verify_all_options();
257257
258258
fossil_print("repository: %s\n", db_repository_filename());
259259
fossil_print("local-root: %s\n", g.zLocalRoot);
@@ -262,11 +262,11 @@
262262
}
263263
vid = db_lget_int("checkout", 0);
264264
if( vid ){
265265
show_common_info(vid, "checkout:", 1, 1);
266266
}
267
- db_record_repository_filename(0);
267
+ db_record_repository_filename(0);
268268
print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
269269
}
270270
271271
/*
272272
** COMMAND: ls
@@ -480,11 +480,11 @@
480480
const char *zPathname, *zDisplayName;
481481
482482
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
483483
db_must_be_within_tree();
484484
cwdRelative = determine_cwd_relative_option();
485
-
485
+
486486
/* We should be done with options.. */
487487
verify_all_options();
488488
489489
if( zIgnoreFlag==0 ){
490490
zIgnoreFlag = db_get("ignore-glob", 0);
@@ -498,10 +498,11 @@
498498
" ORDER BY 1",
499499
fossil_all_reserved_names(0)
500500
);
501501
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
502502
blob_zero(&rewrittenPathname);
503
+ g.allowSymlinks = 1; /* Report on symbolic links */
503504
while( db_step(&q)==SQLITE_ROW ){
504505
zDisplayName = zPathname = db_column_text(&q, 0);
505506
if( cwdRelative ) {
506507
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
507508
file_relative_name(zFullName, &rewrittenPathname, 0);
@@ -563,10 +564,11 @@
563564
** argument. Matching files, if any, are removed
564565
** prior to checking for any empty directories;
565566
** therefore, directories that contain only files
566567
** that were removed will be removed as well.
567568
** -f|--force Remove files without prompting.
569
+** --verily Shorthand for: -f --emptydirs --dotfiles
568570
** --clean <CSG> Never prompt for files matching this
569571
** comma separated list of glob patterns.
570572
** --ignore <CSG> Ignore files matching patterns from the
571573
** comma separated list of glob patterns.
572574
** --keep <CSG> Keep files matching this comma separated
@@ -601,10 +603,15 @@
601603
zIgnoreFlag = find_option("ignore",0,1);
602604
verboseFlag = find_option("verbose","v",0)!=0;
603605
zKeepFlag = find_option("keep",0,1);
604606
zCleanFlag = find_option("clean",0,1);
605607
db_must_be_within_tree();
608
+ if( find_option("verily",0,0)!=0 ){
609
+ allFileFlag = allDirFlag = 1;
610
+ emptyDirsFlag = 1;
611
+ scanFlags |= SCAN_ALL;
612
+ }
606613
if( zIgnoreFlag==0 ){
607614
zIgnoreFlag = db_get("ignore-glob", 0);
608615
}
609616
if( zKeepFlag==0 ){
610617
zKeepFlag = db_get("keep-glob", 0);
@@ -615,10 +622,11 @@
615622
verify_all_options();
616623
pIgnore = glob_create(zIgnoreFlag);
617624
pKeep = glob_create(zKeepFlag);
618625
pClean = glob_create(zCleanFlag);
619626
nRoot = (int)strlen(g.zLocalRoot);
627
+ g.allowSymlinks = 1; /* Find symlinks too */
620628
if( !dirsOnlyFlag ){
621629
Stmt q;
622630
Blob repo;
623631
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
624632
db_prepare(&q,
@@ -1720,11 +1728,11 @@
17201728
17211729
/*
17221730
** Do not allow a commit against a closed leaf unless the commit
17231731
** ends up on a different branch.
17241732
*/
1725
- if(
1733
+ if(
17261734
/* parent checkin has the "closed" tag... */
17271735
db_exists("SELECT 1 FROM tagxref"
17281736
" WHERE tagid=%d AND rid=%d AND tagtype>0",
17291737
TAG_CLOSED, vid)
17301738
/* ... and the new checkin has no --branch option or the --branch
17311739
--- src/checkin.c
+++ src/checkin.c
@@ -213,11 +213,11 @@
213 int showHdr = find_option("header",0,0)!=0;
214 int verboseFlag = find_option("verbose","v",0)!=0;
215 int cwdRelative = 0;
216 db_must_be_within_tree();
217 cwdRelative = determine_cwd_relative_option();
218
219 /* We should be done with options.. */
220 verify_all_options();
221
222 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
223 }
@@ -249,11 +249,11 @@
249 int verboseFlag = find_option("verbose","v",0)!=0;
250 int cwdRelative = 0;
251 db_must_be_within_tree();
252 /* 012345678901234 */
253 cwdRelative = determine_cwd_relative_option();
254
255 /* We should be done with options.. */
256 verify_all_options();
257
258 fossil_print("repository: %s\n", db_repository_filename());
259 fossil_print("local-root: %s\n", g.zLocalRoot);
@@ -262,11 +262,11 @@
262 }
263 vid = db_lget_int("checkout", 0);
264 if( vid ){
265 show_common_info(vid, "checkout:", 1, 1);
266 }
267 db_record_repository_filename(0);
268 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
269 }
270
271 /*
272 ** COMMAND: ls
@@ -480,11 +480,11 @@
480 const char *zPathname, *zDisplayName;
481
482 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
483 db_must_be_within_tree();
484 cwdRelative = determine_cwd_relative_option();
485
486 /* We should be done with options.. */
487 verify_all_options();
488
489 if( zIgnoreFlag==0 ){
490 zIgnoreFlag = db_get("ignore-glob", 0);
@@ -498,10 +498,11 @@
498 " ORDER BY 1",
499 fossil_all_reserved_names(0)
500 );
501 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
502 blob_zero(&rewrittenPathname);
 
503 while( db_step(&q)==SQLITE_ROW ){
504 zDisplayName = zPathname = db_column_text(&q, 0);
505 if( cwdRelative ) {
506 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
507 file_relative_name(zFullName, &rewrittenPathname, 0);
@@ -563,10 +564,11 @@
563 ** argument. Matching files, if any, are removed
564 ** prior to checking for any empty directories;
565 ** therefore, directories that contain only files
566 ** that were removed will be removed as well.
567 ** -f|--force Remove files without prompting.
 
568 ** --clean <CSG> Never prompt for files matching this
569 ** comma separated list of glob patterns.
570 ** --ignore <CSG> Ignore files matching patterns from the
571 ** comma separated list of glob patterns.
572 ** --keep <CSG> Keep files matching this comma separated
@@ -601,10 +603,15 @@
601 zIgnoreFlag = find_option("ignore",0,1);
602 verboseFlag = find_option("verbose","v",0)!=0;
603 zKeepFlag = find_option("keep",0,1);
604 zCleanFlag = find_option("clean",0,1);
605 db_must_be_within_tree();
 
 
 
 
 
606 if( zIgnoreFlag==0 ){
607 zIgnoreFlag = db_get("ignore-glob", 0);
608 }
609 if( zKeepFlag==0 ){
610 zKeepFlag = db_get("keep-glob", 0);
@@ -615,10 +622,11 @@
615 verify_all_options();
616 pIgnore = glob_create(zIgnoreFlag);
617 pKeep = glob_create(zKeepFlag);
618 pClean = glob_create(zCleanFlag);
619 nRoot = (int)strlen(g.zLocalRoot);
 
620 if( !dirsOnlyFlag ){
621 Stmt q;
622 Blob repo;
623 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
624 db_prepare(&q,
@@ -1720,11 +1728,11 @@
1720
1721 /*
1722 ** Do not allow a commit against a closed leaf unless the commit
1723 ** ends up on a different branch.
1724 */
1725 if(
1726 /* parent checkin has the "closed" tag... */
1727 db_exists("SELECT 1 FROM tagxref"
1728 " WHERE tagid=%d AND rid=%d AND tagtype>0",
1729 TAG_CLOSED, vid)
1730 /* ... and the new checkin has no --branch option or the --branch
1731
--- src/checkin.c
+++ src/checkin.c
@@ -213,11 +213,11 @@
213 int showHdr = find_option("header",0,0)!=0;
214 int verboseFlag = find_option("verbose","v",0)!=0;
215 int cwdRelative = 0;
216 db_must_be_within_tree();
217 cwdRelative = determine_cwd_relative_option();
218
219 /* We should be done with options.. */
220 verify_all_options();
221
222 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
223 }
@@ -249,11 +249,11 @@
249 int verboseFlag = find_option("verbose","v",0)!=0;
250 int cwdRelative = 0;
251 db_must_be_within_tree();
252 /* 012345678901234 */
253 cwdRelative = determine_cwd_relative_option();
254
255 /* We should be done with options.. */
256 verify_all_options();
257
258 fossil_print("repository: %s\n", db_repository_filename());
259 fossil_print("local-root: %s\n", g.zLocalRoot);
@@ -262,11 +262,11 @@
262 }
263 vid = db_lget_int("checkout", 0);
264 if( vid ){
265 show_common_info(vid, "checkout:", 1, 1);
266 }
267 db_record_repository_filename(0);
268 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
269 }
270
271 /*
272 ** COMMAND: ls
@@ -480,11 +480,11 @@
480 const char *zPathname, *zDisplayName;
481
482 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
483 db_must_be_within_tree();
484 cwdRelative = determine_cwd_relative_option();
485
486 /* We should be done with options.. */
487 verify_all_options();
488
489 if( zIgnoreFlag==0 ){
490 zIgnoreFlag = db_get("ignore-glob", 0);
@@ -498,10 +498,11 @@
498 " ORDER BY 1",
499 fossil_all_reserved_names(0)
500 );
501 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
502 blob_zero(&rewrittenPathname);
503 g.allowSymlinks = 1; /* Report on symbolic links */
504 while( db_step(&q)==SQLITE_ROW ){
505 zDisplayName = zPathname = db_column_text(&q, 0);
506 if( cwdRelative ) {
507 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
508 file_relative_name(zFullName, &rewrittenPathname, 0);
@@ -563,10 +564,11 @@
564 ** argument. Matching files, if any, are removed
565 ** prior to checking for any empty directories;
566 ** therefore, directories that contain only files
567 ** that were removed will be removed as well.
568 ** -f|--force Remove files without prompting.
569 ** --verily Shorthand for: -f --emptydirs --dotfiles
570 ** --clean <CSG> Never prompt for files matching this
571 ** comma separated list of glob patterns.
572 ** --ignore <CSG> Ignore files matching patterns from the
573 ** comma separated list of glob patterns.
574 ** --keep <CSG> Keep files matching this comma separated
@@ -601,10 +603,15 @@
603 zIgnoreFlag = find_option("ignore",0,1);
604 verboseFlag = find_option("verbose","v",0)!=0;
605 zKeepFlag = find_option("keep",0,1);
606 zCleanFlag = find_option("clean",0,1);
607 db_must_be_within_tree();
608 if( find_option("verily",0,0)!=0 ){
609 allFileFlag = allDirFlag = 1;
610 emptyDirsFlag = 1;
611 scanFlags |= SCAN_ALL;
612 }
613 if( zIgnoreFlag==0 ){
614 zIgnoreFlag = db_get("ignore-glob", 0);
615 }
616 if( zKeepFlag==0 ){
617 zKeepFlag = db_get("keep-glob", 0);
@@ -615,10 +622,11 @@
622 verify_all_options();
623 pIgnore = glob_create(zIgnoreFlag);
624 pKeep = glob_create(zKeepFlag);
625 pClean = glob_create(zCleanFlag);
626 nRoot = (int)strlen(g.zLocalRoot);
627 g.allowSymlinks = 1; /* Find symlinks too */
628 if( !dirsOnlyFlag ){
629 Stmt q;
630 Blob repo;
631 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
632 db_prepare(&q,
@@ -1720,11 +1728,11 @@
1728
1729 /*
1730 ** Do not allow a commit against a closed leaf unless the commit
1731 ** ends up on a different branch.
1732 */
1733 if(
1734 /* parent checkin has the "closed" tag... */
1735 db_exists("SELECT 1 FROM tagxref"
1736 " WHERE tagid=%d AND rid=%d AND tagtype>0",
1737 TAG_CLOSED, vid)
1738 /* ... and the new checkin has no --branch option or the --branch
1739
+14 -11
--- src/clone.c
+++ src/clone.c
@@ -83,11 +83,11 @@
8383
** COMMAND: clone
8484
**
8585
** Usage: %fossil clone ?OPTIONS? URL FILENAME
8686
**
8787
** Make a clone of a repository specified by URL in the local
88
-** file named FILENAME.
88
+** file named FILENAME.
8989
**
9090
** URL must be in one of the following form: ([...] mean optional)
9191
** HTTP/HTTPS protocol:
9292
** http[s]://[userid[:password]@]host[:port][/path]
9393
**
@@ -96,50 +96,53 @@
9696
** [?fossil=path/to/fossil.exe]
9797
**
9898
** Filesystem:
9999
** [file://]path/to/repo.fossil
100100
**
101
-** Note: For ssh and filesystem, path must have an extra leading
101
+** Note: For ssh and filesystem, path must have an extra leading
102102
** '/' to use an absolute path.
103103
**
104104
** By default, your current login name is used to create the default
105105
** admin user. This can be overridden using the -A|--admin-user
106106
** parameter.
107107
**
108108
** Options:
109109
** --admin-user|-A USERNAME Make USERNAME the administrator
110110
** --once Don't save url.
111
-** --private Also clone private branches
111
+** --private Also clone private branches
112112
** --ssl-identity=filename Use the SSL identity if requested by the server
113113
** --ssh-command|-c 'command' Use this SSH command
114114
** --httpauth|-B 'user:pass' Add HTTP Basic Authorization to requests
115
+** --verbose Show more statistics in output
115116
**
116117
** See also: init
117118
*/
118119
void clone_cmd(void){
119120
char *zPassword;
120121
const char *zDefaultUser; /* Optional name of the default user */
121122
const char *zHttpAuth; /* HTTP Authorization user:pass information */
122123
int nErr = 0;
123
- int bPrivate = 0; /* Also clone private branches */
124124
int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
125
+ int syncFlags = SYNC_CLONE;
125126
126
- if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
127
+ /* Also clone private branches */
128
+ if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
127129
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
130
+ if( find_option("verbose",0,0)!=0) syncFlags |= SYNC_VERBOSE;
128131
zHttpAuth = find_option("httpauth","B",1);
129132
zDefaultUser = find_option("admin-user","A",1);
130133
clone_ssh_find_options();
131134
url_proxy_options();
132
-
135
+
133136
/* We should be done with options.. */
134137
verify_all_options();
135138
136139
if( g.argc < 4 ){
137140
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
138141
}
139142
db_open_config(0);
140
- if( file_size(g.argv[3])>0 ){
143
+ if( -1 != file_size(g.argv[3]) ){
141144
fossil_fatal("file already exists: %s", g.argv[3]);
142145
}
143146
144147
url_parse(g.argv[2], urlFlags);
145148
if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
@@ -147,11 +150,11 @@
147150
file_copy(g.url.name, g.argv[3]);
148151
db_close(1);
149152
db_open_repository(g.argv[3]);
150153
db_record_repository_filename(g.argv[3]);
151154
url_remember();
152
- if( !bPrivate ) delete_private_content();
155
+ if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
153156
shun_artifacts();
154157
db_create_default_users(1, zDefaultUser);
155158
if( zDefaultUser ){
156159
g.zLogin = zDefaultUser;
157160
}else{
@@ -184,11 +187,11 @@
184187
);
185188
url_enable_proxy(0);
186189
clone_ssh_db_set_options();
187190
url_get_password_if_needed();
188191
g.xlinkClusterOnly = 1;
189
- nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
192
+ nErr = client_sync(syncFlags,CONFIGSET_ALL,0);
190193
g.xlinkClusterOnly = 0;
191194
verify_cancel();
192195
db_end_transaction(0);
193196
db_close(1);
194197
if( nErr ){
@@ -207,11 +210,11 @@
207210
db_end_transaction(0);
208211
}
209212
210213
/*
211214
** If user chooses to use HTTP Authentication over unencrypted HTTP,
212
-** remember decision. Otherwise, if the URL is being changed and no
215
+** remember decision. Otherwise, if the URL is being changed and no
213216
** preference has been indicated, err on the safe side and revert the
214217
** decision. Set the global preference if the URL is not being changed.
215218
*/
216219
void remember_or_get_http_auth(
217220
const char *zHttpAuth, /* Credentials in the form "user:password" */
@@ -266,13 +269,13 @@
266269
g.zSshCmd = mprintf("%s", zSshCmd);
267270
}
268271
}
269272
270273
/*
271
-** Set SSH options discovered in global variables (set from command line
274
+** Set SSH options discovered in global variables (set from command line
272275
** options).
273276
*/
274277
void clone_ssh_db_set_options(void){
275278
if( g.zSshCmd && g.zSshCmd[0] ){
276279
db_set("ssh-command", g.zSshCmd, 0);
277280
}
278281
}
279282
--- src/clone.c
+++ src/clone.c
@@ -83,11 +83,11 @@
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URL FILENAME
86 **
87 ** Make a clone of a repository specified by URL in the local
88 ** file named FILENAME.
89 **
90 ** URL must be in one of the following form: ([...] mean optional)
91 ** HTTP/HTTPS protocol:
92 ** http[s]://[userid[:password]@]host[:port][/path]
93 **
@@ -96,50 +96,53 @@
96 ** [?fossil=path/to/fossil.exe]
97 **
98 ** Filesystem:
99 ** [file://]path/to/repo.fossil
100 **
101 ** Note: For ssh and filesystem, path must have an extra leading
102 ** '/' to use an absolute path.
103 **
104 ** By default, your current login name is used to create the default
105 ** admin user. This can be overridden using the -A|--admin-user
106 ** parameter.
107 **
108 ** Options:
109 ** --admin-user|-A USERNAME Make USERNAME the administrator
110 ** --once Don't save url.
111 ** --private Also clone private branches
112 ** --ssl-identity=filename Use the SSL identity if requested by the server
113 ** --ssh-command|-c 'command' Use this SSH command
114 ** --httpauth|-B 'user:pass' Add HTTP Basic Authorization to requests
 
115 **
116 ** See also: init
117 */
118 void clone_cmd(void){
119 char *zPassword;
120 const char *zDefaultUser; /* Optional name of the default user */
121 const char *zHttpAuth; /* HTTP Authorization user:pass information */
122 int nErr = 0;
123 int bPrivate = 0; /* Also clone private branches */
124 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
 
125
126 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
 
127 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
 
128 zHttpAuth = find_option("httpauth","B",1);
129 zDefaultUser = find_option("admin-user","A",1);
130 clone_ssh_find_options();
131 url_proxy_options();
132
133 /* We should be done with options.. */
134 verify_all_options();
135
136 if( g.argc < 4 ){
137 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
138 }
139 db_open_config(0);
140 if( file_size(g.argv[3])>0 ){
141 fossil_fatal("file already exists: %s", g.argv[3]);
142 }
143
144 url_parse(g.argv[2], urlFlags);
145 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
@@ -147,11 +150,11 @@
147 file_copy(g.url.name, g.argv[3]);
148 db_close(1);
149 db_open_repository(g.argv[3]);
150 db_record_repository_filename(g.argv[3]);
151 url_remember();
152 if( !bPrivate ) delete_private_content();
153 shun_artifacts();
154 db_create_default_users(1, zDefaultUser);
155 if( zDefaultUser ){
156 g.zLogin = zDefaultUser;
157 }else{
@@ -184,11 +187,11 @@
184 );
185 url_enable_proxy(0);
186 clone_ssh_db_set_options();
187 url_get_password_if_needed();
188 g.xlinkClusterOnly = 1;
189 nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
190 g.xlinkClusterOnly = 0;
191 verify_cancel();
192 db_end_transaction(0);
193 db_close(1);
194 if( nErr ){
@@ -207,11 +210,11 @@
207 db_end_transaction(0);
208 }
209
210 /*
211 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
212 ** remember decision. Otherwise, if the URL is being changed and no
213 ** preference has been indicated, err on the safe side and revert the
214 ** decision. Set the global preference if the URL is not being changed.
215 */
216 void remember_or_get_http_auth(
217 const char *zHttpAuth, /* Credentials in the form "user:password" */
@@ -266,13 +269,13 @@
266 g.zSshCmd = mprintf("%s", zSshCmd);
267 }
268 }
269
270 /*
271 ** Set SSH options discovered in global variables (set from command line
272 ** options).
273 */
274 void clone_ssh_db_set_options(void){
275 if( g.zSshCmd && g.zSshCmd[0] ){
276 db_set("ssh-command", g.zSshCmd, 0);
277 }
278 }
279
--- src/clone.c
+++ src/clone.c
@@ -83,11 +83,11 @@
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URL FILENAME
86 **
87 ** Make a clone of a repository specified by URL in the local
88 ** file named FILENAME.
89 **
90 ** URL must be in one of the following form: ([...] mean optional)
91 ** HTTP/HTTPS protocol:
92 ** http[s]://[userid[:password]@]host[:port][/path]
93 **
@@ -96,50 +96,53 @@
96 ** [?fossil=path/to/fossil.exe]
97 **
98 ** Filesystem:
99 ** [file://]path/to/repo.fossil
100 **
101 ** Note: For ssh and filesystem, path must have an extra leading
102 ** '/' to use an absolute path.
103 **
104 ** By default, your current login name is used to create the default
105 ** admin user. This can be overridden using the -A|--admin-user
106 ** parameter.
107 **
108 ** Options:
109 ** --admin-user|-A USERNAME Make USERNAME the administrator
110 ** --once Don't save url.
111 ** --private Also clone private branches
112 ** --ssl-identity=filename Use the SSL identity if requested by the server
113 ** --ssh-command|-c 'command' Use this SSH command
114 ** --httpauth|-B 'user:pass' Add HTTP Basic Authorization to requests
115 ** --verbose Show more statistics in output
116 **
117 ** See also: init
118 */
119 void clone_cmd(void){
120 char *zPassword;
121 const char *zDefaultUser; /* Optional name of the default user */
122 const char *zHttpAuth; /* HTTP Authorization user:pass information */
123 int nErr = 0;
 
124 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
125 int syncFlags = SYNC_CLONE;
126
127 /* Also clone private branches */
128 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
129 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
130 if( find_option("verbose",0,0)!=0) syncFlags |= SYNC_VERBOSE;
131 zHttpAuth = find_option("httpauth","B",1);
132 zDefaultUser = find_option("admin-user","A",1);
133 clone_ssh_find_options();
134 url_proxy_options();
135
136 /* We should be done with options.. */
137 verify_all_options();
138
139 if( g.argc < 4 ){
140 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
141 }
142 db_open_config(0);
143 if( -1 != file_size(g.argv[3]) ){
144 fossil_fatal("file already exists: %s", g.argv[3]);
145 }
146
147 url_parse(g.argv[2], urlFlags);
148 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
@@ -147,11 +150,11 @@
150 file_copy(g.url.name, g.argv[3]);
151 db_close(1);
152 db_open_repository(g.argv[3]);
153 db_record_repository_filename(g.argv[3]);
154 url_remember();
155 if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
156 shun_artifacts();
157 db_create_default_users(1, zDefaultUser);
158 if( zDefaultUser ){
159 g.zLogin = zDefaultUser;
160 }else{
@@ -184,11 +187,11 @@
187 );
188 url_enable_proxy(0);
189 clone_ssh_db_set_options();
190 url_get_password_if_needed();
191 g.xlinkClusterOnly = 1;
192 nErr = client_sync(syncFlags,CONFIGSET_ALL,0);
193 g.xlinkClusterOnly = 0;
194 verify_cancel();
195 db_end_transaction(0);
196 db_close(1);
197 if( nErr ){
@@ -207,11 +210,11 @@
210 db_end_transaction(0);
211 }
212
213 /*
214 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
215 ** remember decision. Otherwise, if the URL is being changed and no
216 ** preference has been indicated, err on the safe side and revert the
217 ** decision. Set the global preference if the URL is not being changed.
218 */
219 void remember_or_get_http_auth(
220 const char *zHttpAuth, /* Credentials in the form "user:password" */
@@ -266,13 +269,13 @@
269 g.zSshCmd = mprintf("%s", zSshCmd);
270 }
271 }
272
273 /*
274 ** Set SSH options discovered in global variables (set from command line
275 ** options).
276 */
277 void clone_ssh_db_set_options(void){
278 if( g.zSshCmd && g.zSshCmd[0] ){
279 db_set("ssh-command", g.zSshCmd, 0);
280 }
281 }
282
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -276,11 +276,11 @@
276276
277277
/* Certain functions are guaranteed to return a string that is safe
278278
** for use with %s */
279279
z = next_non_whitespace(z, &len, &eType);
280280
for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){
281
- if( eType==TK_ID
281
+ if( eType==TK_ID
282282
&& strncmp(z, azSafeFunc[i], len)==0
283283
&& strlen(azSafeFunc[i])==len
284284
){
285285
return 1;
286286
}
@@ -291,11 +291,11 @@
291291
if( is_string_expr(z) ) return 1;
292292
293293
/* If the "safe-for-%s" comment appears in the argument, then
294294
** let it through */
295295
if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1;
296
-
296
+
297297
return 0;
298298
}
299299
300300
/*
301301
** Processing flags
@@ -460,11 +460,11 @@
460460
for(i=len-1; i>0 && isspace(z[i]); i--){ z[i] = 0; }
461461
z += len + 1;
462462
}
463463
acType = (char*)&azArg[nArg];
464464
if( fmtArg>nArg ){
465
- printf("%s:%d: too few arguments to %.*s()\n",
465
+ printf("%s:%d: too few arguments to %.*s()\n",
466466
zFilename, lnFCall, szFName, zFCall);
467467
nErr++;
468468
}else{
469469
const char *zFmt = azArg[fmtArg-1];
470470
const char *zOverride = strstr(zFmt, "/*works-like:");
@@ -537,11 +537,11 @@
537537
nCurly--;
538538
}else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID
539539
&& (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){
540540
nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags);
541541
}
542
- }
542
+ }
543543
zPrev = z;
544544
ePrev = eToken;
545545
szPrev = szToken;
546546
lnPrev = ln;
547547
}
548548
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -276,11 +276,11 @@
276
277 /* Certain functions are guaranteed to return a string that is safe
278 ** for use with %s */
279 z = next_non_whitespace(z, &len, &eType);
280 for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){
281 if( eType==TK_ID
282 && strncmp(z, azSafeFunc[i], len)==0
283 && strlen(azSafeFunc[i])==len
284 ){
285 return 1;
286 }
@@ -291,11 +291,11 @@
291 if( is_string_expr(z) ) return 1;
292
293 /* If the "safe-for-%s" comment appears in the argument, then
294 ** let it through */
295 if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1;
296
297 return 0;
298 }
299
300 /*
301 ** Processing flags
@@ -460,11 +460,11 @@
460 for(i=len-1; i>0 && isspace(z[i]); i--){ z[i] = 0; }
461 z += len + 1;
462 }
463 acType = (char*)&azArg[nArg];
464 if( fmtArg>nArg ){
465 printf("%s:%d: too few arguments to %.*s()\n",
466 zFilename, lnFCall, szFName, zFCall);
467 nErr++;
468 }else{
469 const char *zFmt = azArg[fmtArg-1];
470 const char *zOverride = strstr(zFmt, "/*works-like:");
@@ -537,11 +537,11 @@
537 nCurly--;
538 }else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID
539 && (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){
540 nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags);
541 }
542 }
543 zPrev = z;
544 ePrev = eToken;
545 szPrev = szToken;
546 lnPrev = ln;
547 }
548
--- src/codecheck1.c
+++ src/codecheck1.c
@@ -276,11 +276,11 @@
276
277 /* Certain functions are guaranteed to return a string that is safe
278 ** for use with %s */
279 z = next_non_whitespace(z, &len, &eType);
280 for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){
281 if( eType==TK_ID
282 && strncmp(z, azSafeFunc[i], len)==0
283 && strlen(azSafeFunc[i])==len
284 ){
285 return 1;
286 }
@@ -291,11 +291,11 @@
291 if( is_string_expr(z) ) return 1;
292
293 /* If the "safe-for-%s" comment appears in the argument, then
294 ** let it through */
295 if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1;
296
297 return 0;
298 }
299
300 /*
301 ** Processing flags
@@ -460,11 +460,11 @@
460 for(i=len-1; i>0 && isspace(z[i]); i--){ z[i] = 0; }
461 z += len + 1;
462 }
463 acType = (char*)&azArg[nArg];
464 if( fmtArg>nArg ){
465 printf("%s:%d: too few arguments to %.*s()\n",
466 zFilename, lnFCall, szFName, zFCall);
467 nErr++;
468 }else{
469 const char *zFmt = azArg[fmtArg-1];
470 const char *zOverride = strstr(zFmt, "/*works-like:");
@@ -537,11 +537,11 @@
537 nCurly--;
538 }else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID
539 && (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){
540 nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags);
541 }
542 }
543 zPrev = z;
544 ePrev = eToken;
545 szPrev = szToken;
546 lnPrev = ln;
547 }
548
--- src/configure.c
+++ src/configure.c
@@ -97,10 +97,11 @@
9797
{ "timeline-max-comment", CONFIGSET_SKIN },
9898
{ "timeline-plaintext", CONFIGSET_SKIN },
9999
{ "adunit", CONFIGSET_SKIN },
100100
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
101101
{ "adunit-omit-if-user", CONFIGSET_SKIN },
102
+ { "white-foreground", CONFIGSET_SKIN },
102103
#ifdef FOSSIL_ENABLE_TH1_DOCS
103104
{ "th1-docs", CONFIGSET_TH1 },
104105
#endif
105106
#ifdef FOSSIL_ENABLE_TH1_HOOKS
106107
{ "th1-hooks", CONFIGSET_TH1 },
@@ -989,5 +990,196 @@
989990
fossil_fatal("METHOD should be one of:"
990991
" export import merge pull push reset");
991992
}
992993
configure_rebuild();
993994
}
995
+
996
+
997
+/*
998
+** COMMAND: test-var-list
999
+**
1000
+** Usage: %fossil test-var-list ?PATTERN? ?--unset? ?--mtime?
1001
+**
1002
+** Show the content of the CONFIG table in a repository. If PATTERN is
1003
+** specified, then only show the entries that match that glob pattern.
1004
+** Last modification time is shown if the --mtime option is present.
1005
+**
1006
+** If the --unset option is included, then entries are deleted rather than
1007
+** being displayed. WARNING! This cannot be undone. Be sure you know what
1008
+** you are doing! The --unset option only works if there is a PATTERN.
1009
+** Probably you should run the command once without --unset to make sure
1010
+** you know exactly what is being deleted.
1011
+**
1012
+** If not in an open check-out, use the -R REPO option to specify a
1013
+** a repository.
1014
+*/
1015
+void test_var_list_cmd(void){
1016
+ Stmt q;
1017
+ int i, j;
1018
+ const char *zPattern = 0;
1019
+ int doUnset;
1020
+ int showMtime;
1021
+ Blob sql;
1022
+ Blob ans;
1023
+ unsigned char zTrans[1000];
1024
+
1025
+ doUnset = find_option("unset",0,0)!=0;
1026
+ showMtime = find_option("mtime",0,0)!=0;
1027
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1028
+ verify_all_options();
1029
+ if( g.argc>=3 ){
1030
+ zPattern = g.argv[2];
1031
+ }
1032
+ blob_init(&sql,0,0);
1033
+ blob_appendf(&sql, "SELECT name, value, datetime(mtime,'unixepoch')"
1034
+ " FROM config");
1035
+ if( zPattern ){
1036
+ blob_appendf(&sql, " WHERE name GLOB %Q", zPattern);
1037
+ }
1038
+ if( showMtime ){
1039
+ blob_appendf(&sql, " ORDER BY mtime, name");
1040
+ }else{
1041
+ blob_appendf(&sql, " ORDER BY name");
1042
+ }
1043
+ db_prepare(&q, "%s", blob_str(&sql)/*safe-for-%s*/);
1044
+ blob_reset(&sql);
1045
+#define MX_VAL 40
1046
+#define MX_NM 28
1047
+#define MX_LONGNM 60
1048
+ while( db_step(&q)==SQLITE_ROW ){
1049
+ const char *zName = db_column_text(&q,0);
1050
+ int nName = db_column_bytes(&q,0);
1051
+ const char *zValue = db_column_text(&q,1);
1052
+ int szValue = db_column_bytes(&q,1);
1053
+ const char *zMTime = db_column_text(&q,2);
1054
+ for(i=j=0; j<MX_VAL && zValue[i]; i++){
1055
+ unsigned char c = (unsigned char)zValue[i];
1056
+ if( c>=' ' && c<='~' ){
1057
+ zTrans[j++] = c;
1058
+ }else{
1059
+ zTrans[j++] = '\\';
1060
+ if( c=='\n' ){
1061
+ zTrans[j++] = 'n';
1062
+ }else if( c=='\r' ){
1063
+ zTrans[j++] = 'r';
1064
+ }else if( c=='\t' ){
1065
+ zTrans[j++] = 't';
1066
+ }else{
1067
+ zTrans[j++] = '0' + ((c>>6)&7);
1068
+ zTrans[j++] = '0' + ((c>>3)&7);
1069
+ zTrans[j++] = '0' + (c&7);
1070
+ }
1071
+ }
1072
+ }
1073
+ zTrans[j] = 0;
1074
+ if( i<szValue ){
1075
+ sqlite3_snprintf(sizeof(zTrans)-j, (char*)zTrans+j, "...+%d", szValue-i);
1076
+ j += (int)strlen((char*)zTrans+j);
1077
+ }
1078
+ if( showMtime ){
1079
+ fossil_print("%s:%*s%s\n", zName, 58-nName, "", zMTime);
1080
+ }else if( nName<MX_NM-2 ){
1081
+ fossil_print("%s:%*s%s\n", zName, MX_NM-1-nName, "", zTrans);
1082
+ }else if( nName<MX_LONGNM-2 && j<10 ){
1083
+ fossil_print("%s:%*s%s\n", zName, MX_LONGNM-1-nName, "", zTrans);
1084
+ }else{
1085
+ fossil_print("%s:\n%*s%s\n", zName, MX_NM, "", zTrans);
1086
+ }
1087
+ }
1088
+ db_finalize(&q);
1089
+ if( zPattern && doUnset ){
1090
+ prompt_user("Delete all of the above? (y/N)? ", &ans);
1091
+ if( blob_str(&ans)[0]=='y' || blob_str(&ans)[0]=='Y' ){
1092
+ db_multi_exec("DELETE FROM config WHERE name GLOB %Q", zPattern);
1093
+ }
1094
+ blob_reset(&ans);
1095
+ }
1096
+}
1097
+
1098
+/*
1099
+** COMMAND: test-var-get
1100
+**
1101
+** Usage: %fossil test-var-get VAR ?FILE?
1102
+**
1103
+** Write the text of the VAR variable into FILE. If FILE is "-"
1104
+** or is omitted then output goes to standard output. VAR can be a
1105
+** GLOB pattern.
1106
+**
1107
+** If not in an open check-out, use the -R REPO option to specify a
1108
+** a repository.
1109
+*/
1110
+void test_var_get_cmd(void){
1111
+ const char *zVar;
1112
+ const char *zFile;
1113
+ int n;
1114
+ Blob x;
1115
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1116
+ verify_all_options();
1117
+ if( g.argc<3 ){
1118
+ usage("VAR ?FILE?");
1119
+ }
1120
+ zVar = g.argv[2];
1121
+ zFile = g.argc>=4 ? g.argv[3] : "-";
1122
+ n = db_int(0, "SELECT count(*) FROM config WHERE name GLOB %Q", zVar);
1123
+ if( n==0 ){
1124
+ fossil_fatal("no match for %Q", zVar);
1125
+ }
1126
+ if( n>1 ){
1127
+ fossil_fatal("multiple matches: %s",
1128
+ db_text(0, "SELECT group_concat(quote(name),', ') FROM ("
1129
+ " SELECT name FROM config WHERE name GLOB %Q ORDER BY 1)",
1130
+ zVar));
1131
+ }
1132
+ blob_init(&x,0,0);
1133
+ db_blob(&x, "SELECT value FROM config WHERE name GLOB %Q", zVar);
1134
+ blob_write_to_file(&x, zFile);
1135
+}
1136
+
1137
+/*
1138
+** COMMAND: test-var-set
1139
+**
1140
+** Usage: %fossil test-var-set VAR ?VALUE? ?--file FILE?
1141
+**
1142
+** Store VALUE or the content of FILE (exactly one of which must be
1143
+** supplied) into variable VAR. Use a FILE of "-" to read from
1144
+** standard input.
1145
+**
1146
+** WARNING: changing the value of a variable can interfere with the
1147
+** operation of Fossil. Be sure you know what you are doing.
1148
+**
1149
+** Use "--blob FILE" instead of "--file FILE" to load a binary blob
1150
+** such as a GIF.
1151
+*/
1152
+void test_var_set_cmd(void){
1153
+ const char *zVar;
1154
+ const char *zFile;
1155
+ const char *zBlob;
1156
+ Blob x;
1157
+ Stmt ins;
1158
+ zFile = find_option("file",0,1);
1159
+ zBlob = find_option("blob",0,1);
1160
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1161
+ verify_all_options();
1162
+ if( g.argc<3 || (zFile==0 && zBlob==0 && g.argc<4) ){
1163
+ usage("VAR ?VALUE? ?--file FILE?");
1164
+ }
1165
+ zVar = g.argv[2];
1166
+ if( zFile ){
1167
+ if( zBlob ) fossil_fatal("cannot do both --file or --blob");
1168
+ blob_read_from_file(&x, zFile);
1169
+ }else if( zBlob ){
1170
+ blob_read_from_file(&x, zBlob);
1171
+ }else{
1172
+ blob_init(&x,g.argv[3],-1);
1173
+ }
1174
+ db_prepare(&ins,
1175
+ "REPLACE INTO config(name,value,mtime)"
1176
+ "VALUES(%Q,:val,now())", zVar);
1177
+ if( zBlob ){
1178
+ db_bind_blob(&ins, ":val", &x);
1179
+ }else{
1180
+ db_bind_text(&ins, ":val", blob_str(&x));
1181
+ }
1182
+ db_step(&ins);
1183
+ db_finalize(&ins);
1184
+ blob_reset(&x);
1185
+}
9941186
--- src/configure.c
+++ src/configure.c
@@ -97,10 +97,11 @@
97 { "timeline-max-comment", CONFIGSET_SKIN },
98 { "timeline-plaintext", CONFIGSET_SKIN },
99 { "adunit", CONFIGSET_SKIN },
100 { "adunit-omit-if-admin", CONFIGSET_SKIN },
101 { "adunit-omit-if-user", CONFIGSET_SKIN },
 
102 #ifdef FOSSIL_ENABLE_TH1_DOCS
103 { "th1-docs", CONFIGSET_TH1 },
104 #endif
105 #ifdef FOSSIL_ENABLE_TH1_HOOKS
106 { "th1-hooks", CONFIGSET_TH1 },
@@ -989,5 +990,196 @@
989 fossil_fatal("METHOD should be one of:"
990 " export import merge pull push reset");
991 }
992 configure_rebuild();
993 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
994
--- src/configure.c
+++ src/configure.c
@@ -97,10 +97,11 @@
97 { "timeline-max-comment", CONFIGSET_SKIN },
98 { "timeline-plaintext", CONFIGSET_SKIN },
99 { "adunit", CONFIGSET_SKIN },
100 { "adunit-omit-if-admin", CONFIGSET_SKIN },
101 { "adunit-omit-if-user", CONFIGSET_SKIN },
102 { "white-foreground", CONFIGSET_SKIN },
103 #ifdef FOSSIL_ENABLE_TH1_DOCS
104 { "th1-docs", CONFIGSET_TH1 },
105 #endif
106 #ifdef FOSSIL_ENABLE_TH1_HOOKS
107 { "th1-hooks", CONFIGSET_TH1 },
@@ -989,5 +990,196 @@
990 fossil_fatal("METHOD should be one of:"
991 " export import merge pull push reset");
992 }
993 configure_rebuild();
994 }
995
996
997 /*
998 ** COMMAND: test-var-list
999 **
1000 ** Usage: %fossil test-var-list ?PATTERN? ?--unset? ?--mtime?
1001 **
1002 ** Show the content of the CONFIG table in a repository. If PATTERN is
1003 ** specified, then only show the entries that match that glob pattern.
1004 ** Last modification time is shown if the --mtime option is present.
1005 **
1006 ** If the --unset option is included, then entries are deleted rather than
1007 ** being displayed. WARNING! This cannot be undone. Be sure you know what
1008 ** you are doing! The --unset option only works if there is a PATTERN.
1009 ** Probably you should run the command once without --unset to make sure
1010 ** you know exactly what is being deleted.
1011 **
1012 ** If not in an open check-out, use the -R REPO option to specify a
1013 ** a repository.
1014 */
1015 void test_var_list_cmd(void){
1016 Stmt q;
1017 int i, j;
1018 const char *zPattern = 0;
1019 int doUnset;
1020 int showMtime;
1021 Blob sql;
1022 Blob ans;
1023 unsigned char zTrans[1000];
1024
1025 doUnset = find_option("unset",0,0)!=0;
1026 showMtime = find_option("mtime",0,0)!=0;
1027 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1028 verify_all_options();
1029 if( g.argc>=3 ){
1030 zPattern = g.argv[2];
1031 }
1032 blob_init(&sql,0,0);
1033 blob_appendf(&sql, "SELECT name, value, datetime(mtime,'unixepoch')"
1034 " FROM config");
1035 if( zPattern ){
1036 blob_appendf(&sql, " WHERE name GLOB %Q", zPattern);
1037 }
1038 if( showMtime ){
1039 blob_appendf(&sql, " ORDER BY mtime, name");
1040 }else{
1041 blob_appendf(&sql, " ORDER BY name");
1042 }
1043 db_prepare(&q, "%s", blob_str(&sql)/*safe-for-%s*/);
1044 blob_reset(&sql);
1045 #define MX_VAL 40
1046 #define MX_NM 28
1047 #define MX_LONGNM 60
1048 while( db_step(&q)==SQLITE_ROW ){
1049 const char *zName = db_column_text(&q,0);
1050 int nName = db_column_bytes(&q,0);
1051 const char *zValue = db_column_text(&q,1);
1052 int szValue = db_column_bytes(&q,1);
1053 const char *zMTime = db_column_text(&q,2);
1054 for(i=j=0; j<MX_VAL && zValue[i]; i++){
1055 unsigned char c = (unsigned char)zValue[i];
1056 if( c>=' ' && c<='~' ){
1057 zTrans[j++] = c;
1058 }else{
1059 zTrans[j++] = '\\';
1060 if( c=='\n' ){
1061 zTrans[j++] = 'n';
1062 }else if( c=='\r' ){
1063 zTrans[j++] = 'r';
1064 }else if( c=='\t' ){
1065 zTrans[j++] = 't';
1066 }else{
1067 zTrans[j++] = '0' + ((c>>6)&7);
1068 zTrans[j++] = '0' + ((c>>3)&7);
1069 zTrans[j++] = '0' + (c&7);
1070 }
1071 }
1072 }
1073 zTrans[j] = 0;
1074 if( i<szValue ){
1075 sqlite3_snprintf(sizeof(zTrans)-j, (char*)zTrans+j, "...+%d", szValue-i);
1076 j += (int)strlen((char*)zTrans+j);
1077 }
1078 if( showMtime ){
1079 fossil_print("%s:%*s%s\n", zName, 58-nName, "", zMTime);
1080 }else if( nName<MX_NM-2 ){
1081 fossil_print("%s:%*s%s\n", zName, MX_NM-1-nName, "", zTrans);
1082 }else if( nName<MX_LONGNM-2 && j<10 ){
1083 fossil_print("%s:%*s%s\n", zName, MX_LONGNM-1-nName, "", zTrans);
1084 }else{
1085 fossil_print("%s:\n%*s%s\n", zName, MX_NM, "", zTrans);
1086 }
1087 }
1088 db_finalize(&q);
1089 if( zPattern && doUnset ){
1090 prompt_user("Delete all of the above? (y/N)? ", &ans);
1091 if( blob_str(&ans)[0]=='y' || blob_str(&ans)[0]=='Y' ){
1092 db_multi_exec("DELETE FROM config WHERE name GLOB %Q", zPattern);
1093 }
1094 blob_reset(&ans);
1095 }
1096 }
1097
1098 /*
1099 ** COMMAND: test-var-get
1100 **
1101 ** Usage: %fossil test-var-get VAR ?FILE?
1102 **
1103 ** Write the text of the VAR variable into FILE. If FILE is "-"
1104 ** or is omitted then output goes to standard output. VAR can be a
1105 ** GLOB pattern.
1106 **
1107 ** If not in an open check-out, use the -R REPO option to specify a
1108 ** a repository.
1109 */
1110 void test_var_get_cmd(void){
1111 const char *zVar;
1112 const char *zFile;
1113 int n;
1114 Blob x;
1115 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1116 verify_all_options();
1117 if( g.argc<3 ){
1118 usage("VAR ?FILE?");
1119 }
1120 zVar = g.argv[2];
1121 zFile = g.argc>=4 ? g.argv[3] : "-";
1122 n = db_int(0, "SELECT count(*) FROM config WHERE name GLOB %Q", zVar);
1123 if( n==0 ){
1124 fossil_fatal("no match for %Q", zVar);
1125 }
1126 if( n>1 ){
1127 fossil_fatal("multiple matches: %s",
1128 db_text(0, "SELECT group_concat(quote(name),', ') FROM ("
1129 " SELECT name FROM config WHERE name GLOB %Q ORDER BY 1)",
1130 zVar));
1131 }
1132 blob_init(&x,0,0);
1133 db_blob(&x, "SELECT value FROM config WHERE name GLOB %Q", zVar);
1134 blob_write_to_file(&x, zFile);
1135 }
1136
1137 /*
1138 ** COMMAND: test-var-set
1139 **
1140 ** Usage: %fossil test-var-set VAR ?VALUE? ?--file FILE?
1141 **
1142 ** Store VALUE or the content of FILE (exactly one of which must be
1143 ** supplied) into variable VAR. Use a FILE of "-" to read from
1144 ** standard input.
1145 **
1146 ** WARNING: changing the value of a variable can interfere with the
1147 ** operation of Fossil. Be sure you know what you are doing.
1148 **
1149 ** Use "--blob FILE" instead of "--file FILE" to load a binary blob
1150 ** such as a GIF.
1151 */
1152 void test_var_set_cmd(void){
1153 const char *zVar;
1154 const char *zFile;
1155 const char *zBlob;
1156 Blob x;
1157 Stmt ins;
1158 zFile = find_option("file",0,1);
1159 zBlob = find_option("blob",0,1);
1160 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
1161 verify_all_options();
1162 if( g.argc<3 || (zFile==0 && zBlob==0 && g.argc<4) ){
1163 usage("VAR ?VALUE? ?--file FILE?");
1164 }
1165 zVar = g.argv[2];
1166 if( zFile ){
1167 if( zBlob ) fossil_fatal("cannot do both --file or --blob");
1168 blob_read_from_file(&x, zFile);
1169 }else if( zBlob ){
1170 blob_read_from_file(&x, zBlob);
1171 }else{
1172 blob_init(&x,g.argv[3],-1);
1173 }
1174 db_prepare(&ins,
1175 "REPLACE INTO config(name,value,mtime)"
1176 "VALUES(%Q,:val,now())", zVar);
1177 if( zBlob ){
1178 db_bind_blob(&ins, ":val", &x);
1179 }else{
1180 db_bind_text(&ins, ":val", blob_str(&x));
1181 }
1182 db_step(&ins);
1183 db_finalize(&ins);
1184 blob_reset(&x);
1185 }
1186
+102 -33
--- src/db.c
+++ src/db.c
@@ -735,10 +735,18 @@
735735
sqlite3_result_int64(context, time(0));
736736
}
737737
738738
/*
739739
** Function to return the check-in time for a file.
740
+**
741
+** checkin_mtime(CKINID,RID)
742
+**
743
+** CKINID: The RID for the manifest for a check-in.
744
+** RID: The RID of a file in CKINID for which the check-in time
745
+** is desired.
746
+**
747
+** Returns: The check-in time in seconds since 1970.
740748
*/
741749
void db_checkin_mtime_function(
742750
sqlite3_context *context,
743751
int argc,
744752
sqlite3_value **argv
@@ -749,17 +757,25 @@
749757
if( rc==0 ){
750758
sqlite3_result_int64(context, mtime);
751759
}
752760
}
753761
762
+/*
763
+** SQL wrapper around the symbolic_name_to_rid() C-language API.
764
+** Examples:
765
+**
766
+** symbolic_name_to_rid('trunk');
767
+** symbolic_name_to_rid('trunk','w');
768
+**
769
+*/
754770
void db_sym2rid_function(
755771
sqlite3_context *context,
756772
int argc,
757773
sqlite3_value **argv
758774
){
759
- char const * arg;
760
- char const * type;
775
+ const char *arg;
776
+ const char *type;
761777
if(1 != argc && 2 != argc){
762778
sqlite3_result_error(context, "Expecting one or two arguments", -1);
763779
return;
764780
}
765781
arg = (const char*)sqlite3_value_text(argv[0]);
@@ -778,10 +794,25 @@
778794
sqlite3_result_int64(context, rid);
779795
}
780796
}
781797
}
782798
799
+/*
800
+** Register the SQL functions that are useful both to the internal
801
+** representation and to the "fossil sql" command.
802
+*/
803
+void db_add_aux_functions(sqlite3 *db){
804
+ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
805
+ db_checkin_mtime_function, 0, 0);
806
+ sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0,
807
+ db_sym2rid_function, 0, 0);
808
+ sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0,
809
+ db_sym2rid_function, 0, 0);
810
+ sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0,
811
+ db_now_function, 0, 0);
812
+}
813
+
783814
784815
/*
785816
** Open a database file. Return a pointer to the new database
786817
** connection. An error results in process abort.
787818
*/
@@ -798,13 +829,10 @@
798829
if( rc!=SQLITE_OK ){
799830
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
800831
}
801832
sqlite3_busy_timeout(db, 5000);
802833
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
803
- sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0);
804
- sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
805
- db_checkin_mtime_function, 0, 0);
806834
sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
807835
sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
808836
sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
809837
sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
810838
sqlite3_create_function(
@@ -811,21 +839,14 @@
811839
db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
812840
);
813841
sqlite3_create_function(
814842
db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
815843
);
816
- sqlite3_create_function(
817
- db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, db_sym2rid_function,
818
- 0, 0
819
- );
820
- sqlite3_create_function(
821
- db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, db_sym2rid_function,
822
- 0, 0
823
- );
824844
if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
825
- re_add_sql_func(db);
826
- foci_register(db);
845
+ db_add_aux_functions(db);
846
+ re_add_sql_func(db); /* The REGEXP operator */
847
+ foci_register(db); /* The "files_of_checkin" virtual table */
827848
sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
828849
return db;
829850
}
830851
831852
@@ -906,30 +927,35 @@
906927
char *zHome;
907928
if( g.zConfigDbName ){
908929
if( useAttach==g.useAttach ) return;
909930
db_close_config();
910931
}
911
-#if defined(_WIN32) || defined(__CYGWIN__)
912
- zHome = fossil_getenv("LOCALAPPDATA");
913
- if( zHome==0 ){
914
- zHome = fossil_getenv("APPDATA");
915
- if( zHome==0 ){
916
- char *zDrive = fossil_getenv("HOMEDRIVE");
917
- zHome = fossil_getenv("HOMEPATH");
918
- if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome);
932
+ zHome = fossil_getenv("FOSSIL_HOME");
933
+#if defined(_WIN32) || defined(__CYGWIN__)
934
+ if( zHome==0 ){
935
+ zHome = fossil_getenv("LOCALAPPDATA");
936
+ if( zHome==0 ){
937
+ zHome = fossil_getenv("APPDATA");
938
+ if( zHome==0 ){
939
+ char *zDrive = fossil_getenv("HOMEDRIVE");
940
+ char *zPath = fossil_getenv("HOMEPATH");
941
+ if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath);
942
+ }
919943
}
920944
}
921945
if( zHome==0 ){
922
- fossil_fatal("cannot locate home directory - "
923
- "please set the LOCALAPPDATA or APPDATA or HOMEPATH "
924
- "environment variables");
946
+ fossil_fatal("cannot locate home directory - please set the "
947
+ "FOSSIL_HOME, LOCALAPPDATA, APPDATA, or HOMEPATH "
948
+ "environment variables");
925949
}
926950
#else
927
- zHome = fossil_getenv("HOME");
951
+ if( zHome==0 ){
952
+ zHome = fossil_getenv("HOME");
953
+ }
928954
if( zHome==0 ){
929
- fossil_fatal("cannot locate home directory - "
930
- "please set the HOME environment variable");
955
+ fossil_fatal("cannot locate home directory - please set the "
956
+ "FOSSIL_HOME or HOME environment variables");
931957
}
932958
#endif
933959
if( file_isdir(zHome)!=1 ){
934960
fossil_fatal("invalid home directory: %s", zHome);
935961
}
@@ -1149,10 +1175,37 @@
11491175
g.zRepositoryName = mprintf("%s", zDbName);
11501176
db_open_or_attach(g.zRepositoryName, "repository", 0);
11511177
g.repositoryOpen = 1;
11521178
/* Cache "allow-symlinks" option, because we'll need it on every stat call */
11531179
g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1180
+ g.zAuxSchema = db_get("aux-schema","");
1181
+
1182
+ /* Verify that the PLINK table has a new column added by the
1183
+ ** 2014-11-28 schema change. Create it if necessary. This code
1184
+ ** can be removed in the future, once all users have upgraded to the
1185
+ ** 2014-11-28 or later schema.
1186
+ */
1187
+ if( !db_table_has_column("repository","plink","baseid") ){
1188
+ db_multi_exec(
1189
+ "ALTER TABLE %s.plink ADD COLUMN baseid;", db_name("repository")
1190
+ );
1191
+ }
1192
+
1193
+ /* Verify that the MLINK table has the newer columns added by the
1194
+ ** 2015-01-24 schema change. Create them if necessary. This code
1195
+ ** can be removed in the future, once all users have upgraded to the
1196
+ ** 2015-01-24 or later schema.
1197
+ */
1198
+ if( !db_table_has_column("repository","mlink","isaux") ){
1199
+ db_begin_transaction();
1200
+ db_multi_exec(
1201
+ "ALTER TABLE %s.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
1202
+ "ALTER TABLE %s.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;",
1203
+ db_name("repository"), db_name("repository")
1204
+ );
1205
+ db_end_transaction(0);
1206
+ }
11541207
}
11551208
11561209
/*
11571210
** Flags for the db_find_and_open_repository() function.
11581211
*/
@@ -1216,11 +1269,10 @@
12161269
12171270
/*
12181271
** Return TRUE if the schema is out-of-date
12191272
*/
12201273
int db_schema_is_outofdate(void){
1221
- if( g.zAuxSchema==0 ) g.zAuxSchema = db_get("aux-schema","");
12221274
return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0
12231275
|| strcmp(g.zAuxSchema,AUX_SCHEMA_MAX)>0;
12241276
}
12251277
12261278
/*
@@ -1334,10 +1386,22 @@
13341386
while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
13351387
fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
13361388
}
13371389
}
13381390
db_close_config();
1391
+
1392
+ /* If the localdb (the check-out database) is open and if it has
1393
+ ** a lot of unused free space, then VACUUM it as we shut down.
1394
+ */
1395
+ if( g.localOpen && strcmp(db_name("localdb"),"main")==0 ){
1396
+ int nFree = db_int(0, "PRAGMA main.freelist_count");
1397
+ int nTotal = db_int(0, "PRAGMA main.page_count");
1398
+ if( nFree>nTotal/4 ){
1399
+ db_multi_exec("VACUUM;");
1400
+ }
1401
+ }
1402
+
13391403
if( g.db ){
13401404
sqlite3_wal_checkpoint(g.db, 0);
13411405
sqlite3_close(g.db);
13421406
g.db = 0;
13431407
g.zMainDbType = 0;
@@ -1401,13 +1465,13 @@
14011465
" WHERE login=%Q", zUser
14021466
);
14031467
if( !setupUserOnly ){
14041468
db_multi_exec(
14051469
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
1406
- " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1470
+ " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');"
14071471
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
1408
- " VALUES('nobody','','gjor','Nobody');"
1472
+ " VALUES('nobody','','gjorz','Nobody');"
14091473
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
14101474
" VALUES('developer','','dei','Dev');"
14111475
"INSERT OR IGNORE INTO user(login,pw,cap,info)"
14121476
" VALUES('reader','','kptw','Reader');"
14131477
);
@@ -1618,10 +1682,15 @@
16181682
verify_all_options();
16191683
16201684
if( g.argc!=3 ){
16211685
usage("REPOSITORY-NAME");
16221686
}
1687
+
1688
+ if( -1 != file_size(g.argv[2]) ){
1689
+ fossil_fatal("file already exists: %s", g.argv[2]);
1690
+ }
1691
+
16231692
db_create_repository(g.argv[2]);
16241693
db_open_repository(g.argv[2]);
16251694
db_open_config(0);
16261695
if( zTemplate ) db_attach(zTemplate, "settingSrc");
16271696
db_begin_transaction();
@@ -2637,11 +2706,11 @@
26372706
}
26382707
}
26392708
}else{
26402709
isManifest = 0;
26412710
while( ctrlSettings[i].name
2642
- && strncmp(ctrlSettings[i].name, zName, n)==0
2711
+ && strncmp(ctrlSettings[i].name, zName, n)==0
26432712
){
26442713
print_setting(&ctrlSettings[i], db_open_local(0));
26452714
i++;
26462715
}
26472716
}
26482717
--- src/db.c
+++ src/db.c
@@ -735,10 +735,18 @@
735 sqlite3_result_int64(context, time(0));
736 }
737
738 /*
739 ** Function to return the check-in time for a file.
 
 
 
 
 
 
 
 
740 */
741 void db_checkin_mtime_function(
742 sqlite3_context *context,
743 int argc,
744 sqlite3_value **argv
@@ -749,17 +757,25 @@
749 if( rc==0 ){
750 sqlite3_result_int64(context, mtime);
751 }
752 }
753
 
 
 
 
 
 
 
 
754 void db_sym2rid_function(
755 sqlite3_context *context,
756 int argc,
757 sqlite3_value **argv
758 ){
759 char const * arg;
760 char const * type;
761 if(1 != argc && 2 != argc){
762 sqlite3_result_error(context, "Expecting one or two arguments", -1);
763 return;
764 }
765 arg = (const char*)sqlite3_value_text(argv[0]);
@@ -778,10 +794,25 @@
778 sqlite3_result_int64(context, rid);
779 }
780 }
781 }
782
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
784 /*
785 ** Open a database file. Return a pointer to the new database
786 ** connection. An error results in process abort.
787 */
@@ -798,13 +829,10 @@
798 if( rc!=SQLITE_OK ){
799 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
800 }
801 sqlite3_busy_timeout(db, 5000);
802 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
803 sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0);
804 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
805 db_checkin_mtime_function, 0, 0);
806 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
807 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
808 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
809 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
810 sqlite3_create_function(
@@ -811,21 +839,14 @@
811 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
812 );
813 sqlite3_create_function(
814 db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
815 );
816 sqlite3_create_function(
817 db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, db_sym2rid_function,
818 0, 0
819 );
820 sqlite3_create_function(
821 db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, db_sym2rid_function,
822 0, 0
823 );
824 if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
825 re_add_sql_func(db);
826 foci_register(db);
 
827 sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
828 return db;
829 }
830
831
@@ -906,30 +927,35 @@
906 char *zHome;
907 if( g.zConfigDbName ){
908 if( useAttach==g.useAttach ) return;
909 db_close_config();
910 }
911 #if defined(_WIN32) || defined(__CYGWIN__)
912 zHome = fossil_getenv("LOCALAPPDATA");
913 if( zHome==0 ){
914 zHome = fossil_getenv("APPDATA");
915 if( zHome==0 ){
916 char *zDrive = fossil_getenv("HOMEDRIVE");
917 zHome = fossil_getenv("HOMEPATH");
918 if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome);
 
 
 
919 }
920 }
921 if( zHome==0 ){
922 fossil_fatal("cannot locate home directory - "
923 "please set the LOCALAPPDATA or APPDATA or HOMEPATH "
924 "environment variables");
925 }
926 #else
927 zHome = fossil_getenv("HOME");
 
 
928 if( zHome==0 ){
929 fossil_fatal("cannot locate home directory - "
930 "please set the HOME environment variable");
931 }
932 #endif
933 if( file_isdir(zHome)!=1 ){
934 fossil_fatal("invalid home directory: %s", zHome);
935 }
@@ -1149,10 +1175,37 @@
1149 g.zRepositoryName = mprintf("%s", zDbName);
1150 db_open_or_attach(g.zRepositoryName, "repository", 0);
1151 g.repositoryOpen = 1;
1152 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1153 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1154 }
1155
1156 /*
1157 ** Flags for the db_find_and_open_repository() function.
1158 */
@@ -1216,11 +1269,10 @@
1216
1217 /*
1218 ** Return TRUE if the schema is out-of-date
1219 */
1220 int db_schema_is_outofdate(void){
1221 if( g.zAuxSchema==0 ) g.zAuxSchema = db_get("aux-schema","");
1222 return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0
1223 || strcmp(g.zAuxSchema,AUX_SCHEMA_MAX)>0;
1224 }
1225
1226 /*
@@ -1334,10 +1386,22 @@
1334 while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
1335 fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
1336 }
1337 }
1338 db_close_config();
 
 
 
 
 
 
 
 
 
 
 
 
1339 if( g.db ){
1340 sqlite3_wal_checkpoint(g.db, 0);
1341 sqlite3_close(g.db);
1342 g.db = 0;
1343 g.zMainDbType = 0;
@@ -1401,13 +1465,13 @@
1401 " WHERE login=%Q", zUser
1402 );
1403 if( !setupUserOnly ){
1404 db_multi_exec(
1405 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1406 " VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
1407 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1408 " VALUES('nobody','','gjor','Nobody');"
1409 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1410 " VALUES('developer','','dei','Dev');"
1411 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1412 " VALUES('reader','','kptw','Reader');"
1413 );
@@ -1618,10 +1682,15 @@
1618 verify_all_options();
1619
1620 if( g.argc!=3 ){
1621 usage("REPOSITORY-NAME");
1622 }
 
 
 
 
 
1623 db_create_repository(g.argv[2]);
1624 db_open_repository(g.argv[2]);
1625 db_open_config(0);
1626 if( zTemplate ) db_attach(zTemplate, "settingSrc");
1627 db_begin_transaction();
@@ -2637,11 +2706,11 @@
2637 }
2638 }
2639 }else{
2640 isManifest = 0;
2641 while( ctrlSettings[i].name
2642 && strncmp(ctrlSettings[i].name, zName, n)==0
2643 ){
2644 print_setting(&ctrlSettings[i], db_open_local(0));
2645 i++;
2646 }
2647 }
2648
--- src/db.c
+++ src/db.c
@@ -735,10 +735,18 @@
735 sqlite3_result_int64(context, time(0));
736 }
737
738 /*
739 ** Function to return the check-in time for a file.
740 **
741 ** checkin_mtime(CKINID,RID)
742 **
743 ** CKINID: The RID for the manifest for a check-in.
744 ** RID: The RID of a file in CKINID for which the check-in time
745 ** is desired.
746 **
747 ** Returns: The check-in time in seconds since 1970.
748 */
749 void db_checkin_mtime_function(
750 sqlite3_context *context,
751 int argc,
752 sqlite3_value **argv
@@ -749,17 +757,25 @@
757 if( rc==0 ){
758 sqlite3_result_int64(context, mtime);
759 }
760 }
761
762 /*
763 ** SQL wrapper around the symbolic_name_to_rid() C-language API.
764 ** Examples:
765 **
766 ** symbolic_name_to_rid('trunk');
767 ** symbolic_name_to_rid('trunk','w');
768 **
769 */
770 void db_sym2rid_function(
771 sqlite3_context *context,
772 int argc,
773 sqlite3_value **argv
774 ){
775 const char *arg;
776 const char *type;
777 if(1 != argc && 2 != argc){
778 sqlite3_result_error(context, "Expecting one or two arguments", -1);
779 return;
780 }
781 arg = (const char*)sqlite3_value_text(argv[0]);
@@ -778,10 +794,25 @@
794 sqlite3_result_int64(context, rid);
795 }
796 }
797 }
798
799 /*
800 ** Register the SQL functions that are useful both to the internal
801 ** representation and to the "fossil sql" command.
802 */
803 void db_add_aux_functions(sqlite3 *db){
804 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
805 db_checkin_mtime_function, 0, 0);
806 sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0,
807 db_sym2rid_function, 0, 0);
808 sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0,
809 db_sym2rid_function, 0, 0);
810 sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0,
811 db_now_function, 0, 0);
812 }
813
814
815 /*
816 ** Open a database file. Return a pointer to the new database
817 ** connection. An error results in process abort.
818 */
@@ -798,13 +829,10 @@
829 if( rc!=SQLITE_OK ){
830 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
831 }
832 sqlite3_busy_timeout(db, 5000);
833 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
 
 
 
834 sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
835 sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
836 sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
837 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
838 sqlite3_create_function(
@@ -811,21 +839,14 @@
839 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
840 );
841 sqlite3_create_function(
842 db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
843 );
 
 
 
 
 
 
 
 
844 if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
845 db_add_aux_functions(db);
846 re_add_sql_func(db); /* The REGEXP operator */
847 foci_register(db); /* The "files_of_checkin" virtual table */
848 sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
849 return db;
850 }
851
852
@@ -906,30 +927,35 @@
927 char *zHome;
928 if( g.zConfigDbName ){
929 if( useAttach==g.useAttach ) return;
930 db_close_config();
931 }
932 zHome = fossil_getenv("FOSSIL_HOME");
933 #if defined(_WIN32) || defined(__CYGWIN__)
934 if( zHome==0 ){
935 zHome = fossil_getenv("LOCALAPPDATA");
936 if( zHome==0 ){
937 zHome = fossil_getenv("APPDATA");
938 if( zHome==0 ){
939 char *zDrive = fossil_getenv("HOMEDRIVE");
940 char *zPath = fossil_getenv("HOMEPATH");
941 if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath);
942 }
943 }
944 }
945 if( zHome==0 ){
946 fossil_fatal("cannot locate home directory - please set the "
947 "FOSSIL_HOME, LOCALAPPDATA, APPDATA, or HOMEPATH "
948 "environment variables");
949 }
950 #else
951 if( zHome==0 ){
952 zHome = fossil_getenv("HOME");
953 }
954 if( zHome==0 ){
955 fossil_fatal("cannot locate home directory - please set the "
956 "FOSSIL_HOME or HOME environment variables");
957 }
958 #endif
959 if( file_isdir(zHome)!=1 ){
960 fossil_fatal("invalid home directory: %s", zHome);
961 }
@@ -1149,10 +1175,37 @@
1175 g.zRepositoryName = mprintf("%s", zDbName);
1176 db_open_or_attach(g.zRepositoryName, "repository", 0);
1177 g.repositoryOpen = 1;
1178 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1179 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1180 g.zAuxSchema = db_get("aux-schema","");
1181
1182 /* Verify that the PLINK table has a new column added by the
1183 ** 2014-11-28 schema change. Create it if necessary. This code
1184 ** can be removed in the future, once all users have upgraded to the
1185 ** 2014-11-28 or later schema.
1186 */
1187 if( !db_table_has_column("repository","plink","baseid") ){
1188 db_multi_exec(
1189 "ALTER TABLE %s.plink ADD COLUMN baseid;", db_name("repository")
1190 );
1191 }
1192
1193 /* Verify that the MLINK table has the newer columns added by the
1194 ** 2015-01-24 schema change. Create them if necessary. This code
1195 ** can be removed in the future, once all users have upgraded to the
1196 ** 2015-01-24 or later schema.
1197 */
1198 if( !db_table_has_column("repository","mlink","isaux") ){
1199 db_begin_transaction();
1200 db_multi_exec(
1201 "ALTER TABLE %s.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
1202 "ALTER TABLE %s.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;",
1203 db_name("repository"), db_name("repository")
1204 );
1205 db_end_transaction(0);
1206 }
1207 }
1208
1209 /*
1210 ** Flags for the db_find_and_open_repository() function.
1211 */
@@ -1216,11 +1269,10 @@
1269
1270 /*
1271 ** Return TRUE if the schema is out-of-date
1272 */
1273 int db_schema_is_outofdate(void){
 
1274 return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0
1275 || strcmp(g.zAuxSchema,AUX_SCHEMA_MAX)>0;
1276 }
1277
1278 /*
@@ -1334,10 +1386,22 @@
1386 while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
1387 fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
1388 }
1389 }
1390 db_close_config();
1391
1392 /* If the localdb (the check-out database) is open and if it has
1393 ** a lot of unused free space, then VACUUM it as we shut down.
1394 */
1395 if( g.localOpen && strcmp(db_name("localdb"),"main")==0 ){
1396 int nFree = db_int(0, "PRAGMA main.freelist_count");
1397 int nTotal = db_int(0, "PRAGMA main.page_count");
1398 if( nFree>nTotal/4 ){
1399 db_multi_exec("VACUUM;");
1400 }
1401 }
1402
1403 if( g.db ){
1404 sqlite3_wal_checkpoint(g.db, 0);
1405 sqlite3_close(g.db);
1406 g.db = 0;
1407 g.zMainDbType = 0;
@@ -1401,13 +1465,13 @@
1465 " WHERE login=%Q", zUser
1466 );
1467 if( !setupUserOnly ){
1468 db_multi_exec(
1469 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1470 " VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');"
1471 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1472 " VALUES('nobody','','gjorz','Nobody');"
1473 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1474 " VALUES('developer','','dei','Dev');"
1475 "INSERT OR IGNORE INTO user(login,pw,cap,info)"
1476 " VALUES('reader','','kptw','Reader');"
1477 );
@@ -1618,10 +1682,15 @@
1682 verify_all_options();
1683
1684 if( g.argc!=3 ){
1685 usage("REPOSITORY-NAME");
1686 }
1687
1688 if( -1 != file_size(g.argv[2]) ){
1689 fossil_fatal("file already exists: %s", g.argv[2]);
1690 }
1691
1692 db_create_repository(g.argv[2]);
1693 db_open_repository(g.argv[2]);
1694 db_open_config(0);
1695 if( zTemplate ) db_attach(zTemplate, "settingSrc");
1696 db_begin_transaction();
@@ -2637,11 +2706,11 @@
2706 }
2707 }
2708 }else{
2709 isManifest = 0;
2710 while( ctrlSettings[i].name
2711 && strncmp(ctrlSettings[i].name, zName, n)==0
2712 ){
2713 print_setting(&ctrlSettings[i], db_open_local(0));
2714 i++;
2715 }
2716 }
2717
+1 -1
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -17,11 +17,11 @@
1717
**
1818
** This module implements the interface to the delta generator.
1919
*/
2020
#include "config.h"
2121
#include "deltacmd.h"
22
-
22
+
2323
/*
2424
** Create a delta that describes the change from pOriginal to pTarget
2525
** and put that delta in pDelta. The pDelta blob is assumed to be
2626
** uninitialized.
2727
*/
2828
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -17,11 +17,11 @@
17 **
18 ** This module implements the interface to the delta generator.
19 */
20 #include "config.h"
21 #include "deltacmd.h"
22
23 /*
24 ** Create a delta that describes the change from pOriginal to pTarget
25 ** and put that delta in pDelta. The pDelta blob is assumed to be
26 ** uninitialized.
27 */
28
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -17,11 +17,11 @@
17 **
18 ** This module implements the interface to the delta generator.
19 */
20 #include "config.h"
21 #include "deltacmd.h"
22
23 /*
24 ** Create a delta that describes the change from pOriginal to pTarget
25 ** and put that delta in pDelta. The pDelta blob is assumed to be
26 ** uninitialized.
27 */
28
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,5 +1,14 @@
1
+# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
2
+# to this file, then runs this file using "tclsh" in order to display the
3
+# graphical diff in a separate window. A typical "set fossilcmd" line
4
+# looks like this:
5
+#
6
+# set fossilcmd {| "./fossil" diff --html -y -i -v}
7
+#
8
+# This header comment is stripped off by the "mkbuiltin.c" program.
9
+#
110
set prog {
211
package require Tk
312
413
array set CFG {
514
TITLE {Fossil Diff}
615
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,5 +1,14 @@
 
 
 
 
 
 
 
 
 
1 set prog {
2 package require Tk
3
4 array set CFG {
5 TITLE {Fossil Diff}
6
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,5 +1,14 @@
1 # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
2 # to this file, then runs this file using "tclsh" in order to display the
3 # graphical diff in a separate window. A typical "set fossilcmd" line
4 # looks like this:
5 #
6 # set fossilcmd {| "./fossil" diff --html -y -i -v}
7 #
8 # This header comment is stripped off by the "mkbuiltin.c" program.
9 #
10 set prog {
11 package require Tk
12
13 array set CFG {
14 TITLE {Fossil Diff}
15
+130 -126
--- src/doc.c
+++ src/doc.c
@@ -350,150 +350,145 @@
350350
int i;
351351
for(i=2; i<g.argc; i++){
352352
fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
353353
}
354354
}
355
+
356
+/*
357
+** Look for a file named zName in the checkin with RID=vid. Load the content
358
+** of that file into pContent and return the RID for the file. Or return 0
359
+** if the file is not found or could not be loaded.
360
+*/
361
+int doc_load_content(int vid, const char *zName, Blob *pContent){
362
+ int rid; /* The RID of the file being loaded */
363
+ if( !db_table_exists("repository","vcache") ){
364
+ db_multi_exec(
365
+ "CREATE TABLE IF NOT EXISTS vcache(\n"
366
+ " vid INTEGER, -- checkin ID\n"
367
+ " fname TEXT, -- filename\n"
368
+ " rid INTEGER, -- artifact ID\n"
369
+ " PRIMARY KEY(vid,fname)\n"
370
+ ") WITHOUT ROWID"
371
+ );
372
+ }
373
+ if( !db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){
374
+ db_multi_exec(
375
+ "DELETE FROM vcache;\n"
376
+ "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;\n"
377
+ "INSERT INTO vcache(vid,fname,rid)"
378
+ " SELECT checkinID, filename, blob.rid FROM foci, blob"
379
+ " WHERE blob.uuid=foci.uuid"
380
+ " AND foci.checkinID=%d;",
381
+ vid
382
+ );
383
+ }
384
+ rid = db_int(0, "SELECT rid FROM vcache"
385
+ " WHERE vid=%d AND fname=%Q", vid, zName);
386
+ if( rid && content_get(rid, pContent)==0 ){
387
+ rid = 0;
388
+ }
389
+ return rid;
390
+}
355391
356392
/*
357393
** WEBPAGE: doc
358
-** URL: /doc?name=BASELINE/PATH
359
-** URL: /doc/BASELINE/PATH
360
-**
361
-** BASELINE can be either a baseline uuid prefix or magic words "tip"
362
-** to mean the most recently checked in baseline or "ckout" to mean the
363
-** content of the local checkout, if any. PATH is the relative pathname
364
-** of some file. This method returns the file content.
365
-**
366
-** If PATH matches the patterns *.wiki or *.txt then formatting content
367
-** is added before returning the file. For all other names, the content
368
-** is returned straight without any interpretation or processing.
394
+** URL: /doc?name=CHECKIN/FILE
395
+** URL: /doc/CHECKIN/FILE
396
+**
397
+** CHECKIN can be either tag or SHA1 hash or timestamp identifying a
398
+** particular check, or the name of a branch (meaning the most recent
399
+** check-in on that branch) or one of various magic words:
400
+**
401
+** "tip" means the most recent check-in
402
+**
403
+** "ckout" means the current check-out, if the server is run from
404
+** within a check-out, otherwise it is the same as "tip"
405
+**
406
+** FILE is the name of a file to delivered up as a webpage. FILE is relative
407
+** to the root of the source tree of the repository. The FILE must
408
+** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
409
+** directly from disk and need not be a managed file.
410
+**
411
+** The "ckout" CHECKIN is intended for development - to provide a mechanism
412
+** for looking at what a file will look like using the /doc webpage after
413
+** it gets checked in.
414
+**
415
+** The file extension is used to decide how to render the file.
416
+**
417
+** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki",
418
+** and "FILE/index.md" are in that order. If none of those are found,
419
+** then FILE is completely replaced by "404.md" and tried. If that is
420
+** not found, then a default 404 screen is generated.
369421
*/
370422
void doc_page(void){
371423
const char *zName; /* Argument to the /doc page */
424
+ const char *zOrigName = "?"; /* Original document name */
372425
const char *zMime; /* Document MIME type */
373
- int vid = 0; /* Artifact of baseline */
426
+ char *zCheckin = "tip"; /* The checkin holding the document */
427
+ int vid = 0; /* Artifact of checkin */
374428
int rid = 0; /* Artifact of file */
375429
int i; /* Loop counter */
376430
Blob filebody; /* Content of the documentation file */
377
- char zBaseline[UUID_SIZE+1]; /* Baseline UUID */
431
+ int nMiss = (-1); /* Failed attempts to find the document */
432
+ static const char *const azSuffix[] = {
433
+ "index.html", "index.wiki", "index.md"
434
+ };
378435
379436
login_check_credentials();
380437
if( !g.perm.Read ){ login_needed(); return; }
381
- zName = PD("name", "tip/index.wiki");
382
- for(i=0; zName[i] && zName[i]!='/'; i++){}
383
- if( zName[i]==0 || i>UUID_SIZE ){
384
- zName = "index.html";
385
- goto doc_not_found;
386
- }
387
- g.zPath = mprintf("%s/%s", g.zPath, zName);
388
- memcpy(zBaseline, zName, i);
389
- zBaseline[i] = 0;
390
- zName += i;
391
- while( zName[0]=='/' ){ zName++; }
392
- if( !file_is_simple_pathname(zName, 1) ){
393
- int n = strlen(zName);
394
- if( n>0 && zName[n-1]=='/' ){
395
- zName = mprintf("%sindex.html", zName);
396
- if( !file_is_simple_pathname(zName, 1) ){
397
- goto doc_not_found;
398
- }
399
- }else{
400
- goto doc_not_found;
401
- }
402
- }
403
- if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local(0)==0 ){
404
- sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip");
405
- }
406
- if( fossil_strcmp(zBaseline,"ckout")==0 ){
407
- /* Read from the local checkout */
408
- char *zFullpath;
409
- db_must_be_within_tree();
410
- zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
411
- if( !file_isfile(zFullpath) ){
412
- goto doc_not_found;
413
- }
414
- if( blob_read_from_file(&filebody, zFullpath)<0 ){
415
- goto doc_not_found;
416
- }
417
- }else{
418
- db_begin_transaction();
419
- if( fossil_strcmp(zBaseline,"tip")==0 ){
420
- vid = db_int(0, "SELECT objid FROM event WHERE type='ci'"
421
- " ORDER BY mtime DESC LIMIT 1");
422
- }else{
423
- vid = name_to_typed_rid(zBaseline, "ci");
424
- }
425
-
426
- /* Create the baseline cache if it does not already exist */
427
- db_multi_exec(
428
- "CREATE TABLE IF NOT EXISTS vcache(\n"
429
- " vid INTEGER, -- baseline ID\n"
430
- " fname TEXT, -- filename\n"
431
- " rid INTEGER, -- artifact ID\n"
432
- " UNIQUE(vid,fname,rid)\n"
433
- ")"
434
- );
435
-
436
-
437
-
438
- /* Check to see if the documentation file artifact ID is contained
439
- ** in the baseline cache */
440
- rid = db_int(0, "SELECT rid FROM vcache"
441
- " WHERE vid=%d AND fname=%Q", vid, zName);
442
- if( rid==0 && db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){
443
- goto doc_not_found;
444
- }
445
-
446
- if( rid==0 ){
447
- Stmt s;
448
- Manifest *pM;
449
- ManifestFile *pFile;
450
-
451
- /* Add the vid baseline to the cache */
452
- if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
453
- db_multi_exec("DELETE FROM vcache");
454
- }
455
- pM = manifest_get(vid, CFTYPE_MANIFEST, 0);
456
- if( pM==0 ){
457
- goto doc_not_found;
458
- }
459
- db_prepare(&s,
460
- "INSERT INTO vcache(vid,fname,rid)"
461
- " SELECT %d, :fname, rid FROM blob"
462
- " WHERE uuid=:uuid",
463
- vid
464
- );
465
- manifest_file_rewind(pM);
466
- while( (pFile = manifest_file_next(pM,0))!=0 ){
467
- db_bind_text(&s, ":fname", pFile->zName);
468
- db_bind_text(&s, ":uuid", pFile->zUuid);
469
- db_step(&s);
470
- db_reset(&s);
471
- }
472
- db_finalize(&s);
473
- manifest_destroy(pM);
474
-
475
- /* Try again to find the file */
476
- rid = db_int(0, "SELECT rid FROM vcache"
477
- " WHERE vid=%d AND fname=%Q", vid, zName);
478
- }
479
- if( rid==0 ){
480
- goto doc_not_found;
481
- }
482
-
483
- /* Get the file content */
484
- if( content_get(rid, &filebody)==0 ){
485
- goto doc_not_found;
486
- }
487
- db_end_transaction(0);
488
- }
438
+ db_begin_transaction();
439
+ while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){
440
+ zName = PD("name", "tip/index.wiki");
441
+ for(i=0; zName[i] && zName[i]!='/'; i++){}
442
+ zCheckin = mprintf("%.*s", i, zName);
443
+ if( fossil_strcmp(zCheckin,"ckout")==0 && db_open_local(0)==0 ){
444
+ zCheckin = "tip";
445
+ }
446
+ if( nMiss==ArraySize(azSuffix) ){
447
+ zName = "404.md";
448
+ }else if( zName[i]==0 ){
449
+ assert( nMiss>=0 && nMiss<ArraySize(azSuffix) );
450
+ zName = azSuffix[nMiss];
451
+ }else{
452
+ zName += i;
453
+ }
454
+ while( zName[0]=='/' ){ zName++; }
455
+ g.zPath = mprintf("%s/%s/%s", g.zPath, zCheckin, zName);
456
+ if( nMiss==0 ) zOrigName = zName;
457
+ if( !file_is_simple_pathname(zName, 1) ){
458
+ if( sqlite3_strglob("*/", zName)==0 ){
459
+ assert( nMiss>=0 && nMiss<ArraySize(azSuffix) );
460
+ zName = mprintf("%s%s", zName, azSuffix[nMiss]);
461
+ if( !file_is_simple_pathname(zName, 1) ){
462
+ goto doc_not_found;
463
+ }
464
+ }else{
465
+ goto doc_not_found;
466
+ }
467
+ }
468
+ if( fossil_strcmp(zCheckin,"ckout")==0 ){
469
+ /* Read from the local checkout */
470
+ char *zFullpath;
471
+ db_must_be_within_tree();
472
+ zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
473
+ if( file_isfile(zFullpath)
474
+ && blob_read_from_file(&filebody, zFullpath)>0 ){
475
+ rid = 1; /* Fake RID just to get the loop to end */
476
+ }
477
+ fossil_free(zFullpath);
478
+ }else{
479
+ vid = name_to_typed_rid(zCheckin, "ci");
480
+ rid = doc_load_content(vid, zName, &filebody);
481
+ }
482
+ }
483
+ if( rid==0 ) goto doc_not_found;
489484
blob_to_utf8_no_bom(&filebody, 0);
490485
491486
/* The file is now contained in the filebody blob. Deliver the
492487
** file to the user
493488
*/
494
- zMime = P("mimetype");
489
+ zMime = nMiss==0 ? P("mimetype") : 0;
495490
if( zMime==0 ){
496491
zMime = mimetype_from_name(zName);
497492
}
498493
Th_Store("doc_name", zName);
499494
Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
@@ -500,10 +495,11 @@
500495
" FROM blob WHERE rid=%d", vid));
501496
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
502497
" WHERE objid=%d AND type='ci'", vid));
503498
if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
504499
Blob title, tail;
500
+ style_adunit_config(ADUNIT_RIGHT_OK);
505501
if( wiki_find_title(&filebody, &title, &tail) ){
506502
style_header("%s", blob_str(&title));
507503
wiki_convert(&tail, 0, WIKI_BUTTONS);
508504
}else{
509505
style_header("Documentation");
@@ -515,11 +511,12 @@
515511
Blob tail = BLOB_INITIALIZER;
516512
markdown_to_html(&filebody, &title, &tail);
517513
if( blob_size(&title)>0 ){
518514
style_header("%s", blob_str(&title));
519515
}else{
520
- style_header("Documentation");
516
+ style_header("%s", nMiss>=ArraySize(azSuffix)?
517
+ "Not Found" : "Documentation");
521518
}
522519
blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail));
523520
style_footer();
524521
}else if( fossil_strcmp(zMime, "text/plain")==0 ){
525522
style_header("Documentation");
@@ -536,18 +533,25 @@
536533
#endif
537534
}else{
538535
cgi_set_content_type(zMime);
539536
cgi_set_content(&filebody);
540537
}
538
+ if( nMiss>=ArraySize(azSuffix) ) cgi_set_status(404, "Not Found");
539
+ db_end_transaction(0);
541540
return;
542541
543
-doc_not_found:
544542
/* Jump here when unable to locate the document */
543
+doc_not_found:
545544
db_end_transaction(0);
546
- style_header("Document Not Found");
547
- @ <p>No such document: %h(zName)</p>
545
+ cgi_set_status(404, "Not Found");
546
+ style_header("Not Found");
547
+ @ <p>Document %h(zOrigName) not found
548
+ if( fossil_strcmp(zCheckin,"ckout")!=0 ){
549
+ @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a>
550
+ }
548551
style_footer();
552
+ db_end_transaction(0);
549553
return;
550554
}
551555
552556
/*
553557
** The default logo.
554558
--- src/doc.c
+++ src/doc.c
@@ -350,150 +350,145 @@
350 int i;
351 for(i=2; i<g.argc; i++){
352 fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
353 }
354 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
356 /*
357 ** WEBPAGE: doc
358 ** URL: /doc?name=BASELINE/PATH
359 ** URL: /doc/BASELINE/PATH
360 **
361 ** BASELINE can be either a baseline uuid prefix or magic words "tip"
362 ** to mean the most recently checked in baseline or "ckout" to mean the
363 ** content of the local checkout, if any. PATH is the relative pathname
364 ** of some file. This method returns the file content.
365 **
366 ** If PATH matches the patterns *.wiki or *.txt then formatting content
367 ** is added before returning the file. For all other names, the content
368 ** is returned straight without any interpretation or processing.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369 */
370 void doc_page(void){
371 const char *zName; /* Argument to the /doc page */
 
372 const char *zMime; /* Document MIME type */
373 int vid = 0; /* Artifact of baseline */
 
374 int rid = 0; /* Artifact of file */
375 int i; /* Loop counter */
376 Blob filebody; /* Content of the documentation file */
377 char zBaseline[UUID_SIZE+1]; /* Baseline UUID */
 
 
 
378
379 login_check_credentials();
380 if( !g.perm.Read ){ login_needed(); return; }
381 zName = PD("name", "tip/index.wiki");
382 for(i=0; zName[i] && zName[i]!='/'; i++){}
383 if( zName[i]==0 || i>UUID_SIZE ){
384 zName = "index.html";
385 goto doc_not_found;
386 }
387 g.zPath = mprintf("%s/%s", g.zPath, zName);
388 memcpy(zBaseline, zName, i);
389 zBaseline[i] = 0;
390 zName += i;
391 while( zName[0]=='/' ){ zName++; }
392 if( !file_is_simple_pathname(zName, 1) ){
393 int n = strlen(zName);
394 if( n>0 && zName[n-1]=='/' ){
395 zName = mprintf("%sindex.html", zName);
396 if( !file_is_simple_pathname(zName, 1) ){
397 goto doc_not_found;
398 }
399 }else{
400 goto doc_not_found;
401 }
402 }
403 if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local(0)==0 ){
404 sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip");
405 }
406 if( fossil_strcmp(zBaseline,"ckout")==0 ){
407 /* Read from the local checkout */
408 char *zFullpath;
409 db_must_be_within_tree();
410 zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
411 if( !file_isfile(zFullpath) ){
412 goto doc_not_found;
413 }
414 if( blob_read_from_file(&filebody, zFullpath)<0 ){
415 goto doc_not_found;
416 }
417 }else{
418 db_begin_transaction();
419 if( fossil_strcmp(zBaseline,"tip")==0 ){
420 vid = db_int(0, "SELECT objid FROM event WHERE type='ci'"
421 " ORDER BY mtime DESC LIMIT 1");
422 }else{
423 vid = name_to_typed_rid(zBaseline, "ci");
424 }
425
426 /* Create the baseline cache if it does not already exist */
427 db_multi_exec(
428 "CREATE TABLE IF NOT EXISTS vcache(\n"
429 " vid INTEGER, -- baseline ID\n"
430 " fname TEXT, -- filename\n"
431 " rid INTEGER, -- artifact ID\n"
432 " UNIQUE(vid,fname,rid)\n"
433 ")"
434 );
435
436
437
438 /* Check to see if the documentation file artifact ID is contained
439 ** in the baseline cache */
440 rid = db_int(0, "SELECT rid FROM vcache"
441 " WHERE vid=%d AND fname=%Q", vid, zName);
442 if( rid==0 && db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){
443 goto doc_not_found;
444 }
445
446 if( rid==0 ){
447 Stmt s;
448 Manifest *pM;
449 ManifestFile *pFile;
450
451 /* Add the vid baseline to the cache */
452 if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
453 db_multi_exec("DELETE FROM vcache");
454 }
455 pM = manifest_get(vid, CFTYPE_MANIFEST, 0);
456 if( pM==0 ){
457 goto doc_not_found;
458 }
459 db_prepare(&s,
460 "INSERT INTO vcache(vid,fname,rid)"
461 " SELECT %d, :fname, rid FROM blob"
462 " WHERE uuid=:uuid",
463 vid
464 );
465 manifest_file_rewind(pM);
466 while( (pFile = manifest_file_next(pM,0))!=0 ){
467 db_bind_text(&s, ":fname", pFile->zName);
468 db_bind_text(&s, ":uuid", pFile->zUuid);
469 db_step(&s);
470 db_reset(&s);
471 }
472 db_finalize(&s);
473 manifest_destroy(pM);
474
475 /* Try again to find the file */
476 rid = db_int(0, "SELECT rid FROM vcache"
477 " WHERE vid=%d AND fname=%Q", vid, zName);
478 }
479 if( rid==0 ){
480 goto doc_not_found;
481 }
482
483 /* Get the file content */
484 if( content_get(rid, &filebody)==0 ){
485 goto doc_not_found;
486 }
487 db_end_transaction(0);
488 }
489 blob_to_utf8_no_bom(&filebody, 0);
490
491 /* The file is now contained in the filebody blob. Deliver the
492 ** file to the user
493 */
494 zMime = P("mimetype");
495 if( zMime==0 ){
496 zMime = mimetype_from_name(zName);
497 }
498 Th_Store("doc_name", zName);
499 Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
@@ -500,10 +495,11 @@
500 " FROM blob WHERE rid=%d", vid));
501 Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
502 " WHERE objid=%d AND type='ci'", vid));
503 if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
504 Blob title, tail;
 
505 if( wiki_find_title(&filebody, &title, &tail) ){
506 style_header("%s", blob_str(&title));
507 wiki_convert(&tail, 0, WIKI_BUTTONS);
508 }else{
509 style_header("Documentation");
@@ -515,11 +511,12 @@
515 Blob tail = BLOB_INITIALIZER;
516 markdown_to_html(&filebody, &title, &tail);
517 if( blob_size(&title)>0 ){
518 style_header("%s", blob_str(&title));
519 }else{
520 style_header("Documentation");
 
521 }
522 blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail));
523 style_footer();
524 }else if( fossil_strcmp(zMime, "text/plain")==0 ){
525 style_header("Documentation");
@@ -536,18 +533,25 @@
536 #endif
537 }else{
538 cgi_set_content_type(zMime);
539 cgi_set_content(&filebody);
540 }
 
 
541 return;
542
543 doc_not_found:
544 /* Jump here when unable to locate the document */
 
545 db_end_transaction(0);
546 style_header("Document Not Found");
547 @ <p>No such document: %h(zName)</p>
 
 
 
 
548 style_footer();
 
549 return;
550 }
551
552 /*
553 ** The default logo.
554
--- src/doc.c
+++ src/doc.c
@@ -350,150 +350,145 @@
350 int i;
351 for(i=2; i<g.argc; i++){
352 fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
353 }
354 }
355
356 /*
357 ** Look for a file named zName in the checkin with RID=vid. Load the content
358 ** of that file into pContent and return the RID for the file. Or return 0
359 ** if the file is not found or could not be loaded.
360 */
361 int doc_load_content(int vid, const char *zName, Blob *pContent){
362 int rid; /* The RID of the file being loaded */
363 if( !db_table_exists("repository","vcache") ){
364 db_multi_exec(
365 "CREATE TABLE IF NOT EXISTS vcache(\n"
366 " vid INTEGER, -- checkin ID\n"
367 " fname TEXT, -- filename\n"
368 " rid INTEGER, -- artifact ID\n"
369 " PRIMARY KEY(vid,fname)\n"
370 ") WITHOUT ROWID"
371 );
372 }
373 if( !db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){
374 db_multi_exec(
375 "DELETE FROM vcache;\n"
376 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;\n"
377 "INSERT INTO vcache(vid,fname,rid)"
378 " SELECT checkinID, filename, blob.rid FROM foci, blob"
379 " WHERE blob.uuid=foci.uuid"
380 " AND foci.checkinID=%d;",
381 vid
382 );
383 }
384 rid = db_int(0, "SELECT rid FROM vcache"
385 " WHERE vid=%d AND fname=%Q", vid, zName);
386 if( rid && content_get(rid, pContent)==0 ){
387 rid = 0;
388 }
389 return rid;
390 }
391
392 /*
393 ** WEBPAGE: doc
394 ** URL: /doc?name=CHECKIN/FILE
395 ** URL: /doc/CHECKIN/FILE
396 **
397 ** CHECKIN can be either tag or SHA1 hash or timestamp identifying a
398 ** particular check, or the name of a branch (meaning the most recent
399 ** check-in on that branch) or one of various magic words:
400 **
401 ** "tip" means the most recent check-in
402 **
403 ** "ckout" means the current check-out, if the server is run from
404 ** within a check-out, otherwise it is the same as "tip"
405 **
406 ** FILE is the name of a file to delivered up as a webpage. FILE is relative
407 ** to the root of the source tree of the repository. The FILE must
408 ** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
409 ** directly from disk and need not be a managed file.
410 **
411 ** The "ckout" CHECKIN is intended for development - to provide a mechanism
412 ** for looking at what a file will look like using the /doc webpage after
413 ** it gets checked in.
414 **
415 ** The file extension is used to decide how to render the file.
416 **
417 ** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki",
418 ** and "FILE/index.md" are in that order. If none of those are found,
419 ** then FILE is completely replaced by "404.md" and tried. If that is
420 ** not found, then a default 404 screen is generated.
421 */
422 void doc_page(void){
423 const char *zName; /* Argument to the /doc page */
424 const char *zOrigName = "?"; /* Original document name */
425 const char *zMime; /* Document MIME type */
426 char *zCheckin = "tip"; /* The checkin holding the document */
427 int vid = 0; /* Artifact of checkin */
428 int rid = 0; /* Artifact of file */
429 int i; /* Loop counter */
430 Blob filebody; /* Content of the documentation file */
431 int nMiss = (-1); /* Failed attempts to find the document */
432 static const char *const azSuffix[] = {
433 "index.html", "index.wiki", "index.md"
434 };
435
436 login_check_credentials();
437 if( !g.perm.Read ){ login_needed(); return; }
438 db_begin_transaction();
439 while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){
440 zName = PD("name", "tip/index.wiki");
441 for(i=0; zName[i] && zName[i]!='/'; i++){}
442 zCheckin = mprintf("%.*s", i, zName);
443 if( fossil_strcmp(zCheckin,"ckout")==0 && db_open_local(0)==0 ){
444 zCheckin = "tip";
445 }
446 if( nMiss==ArraySize(azSuffix) ){
447 zName = "404.md";
448 }else if( zName[i]==0 ){
449 assert( nMiss>=0 && nMiss<ArraySize(azSuffix) );
450 zName = azSuffix[nMiss];
451 }else{
452 zName += i;
453 }
454 while( zName[0]=='/' ){ zName++; }
455 g.zPath = mprintf("%s/%s/%s", g.zPath, zCheckin, zName);
456 if( nMiss==0 ) zOrigName = zName;
457 if( !file_is_simple_pathname(zName, 1) ){
458 if( sqlite3_strglob("*/", zName)==0 ){
459 assert( nMiss>=0 && nMiss<ArraySize(azSuffix) );
460 zName = mprintf("%s%s", zName, azSuffix[nMiss]);
461 if( !file_is_simple_pathname(zName, 1) ){
462 goto doc_not_found;
463 }
464 }else{
465 goto doc_not_found;
466 }
467 }
468 if( fossil_strcmp(zCheckin,"ckout")==0 ){
469 /* Read from the local checkout */
470 char *zFullpath;
471 db_must_be_within_tree();
472 zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
473 if( file_isfile(zFullpath)
474 && blob_read_from_file(&filebody, zFullpath)>0 ){
475 rid = 1; /* Fake RID just to get the loop to end */
476 }
477 fossil_free(zFullpath);
478 }else{
479 vid = name_to_typed_rid(zCheckin, "ci");
480 rid = doc_load_content(vid, zName, &filebody);
481 }
482 }
483 if( rid==0 ) goto doc_not_found;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484 blob_to_utf8_no_bom(&filebody, 0);
485
486 /* The file is now contained in the filebody blob. Deliver the
487 ** file to the user
488 */
489 zMime = nMiss==0 ? P("mimetype") : 0;
490 if( zMime==0 ){
491 zMime = mimetype_from_name(zName);
492 }
493 Th_Store("doc_name", zName);
494 Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
@@ -500,10 +495,11 @@
495 " FROM blob WHERE rid=%d", vid));
496 Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
497 " WHERE objid=%d AND type='ci'", vid));
498 if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
499 Blob title, tail;
500 style_adunit_config(ADUNIT_RIGHT_OK);
501 if( wiki_find_title(&filebody, &title, &tail) ){
502 style_header("%s", blob_str(&title));
503 wiki_convert(&tail, 0, WIKI_BUTTONS);
504 }else{
505 style_header("Documentation");
@@ -515,11 +511,12 @@
511 Blob tail = BLOB_INITIALIZER;
512 markdown_to_html(&filebody, &title, &tail);
513 if( blob_size(&title)>0 ){
514 style_header("%s", blob_str(&title));
515 }else{
516 style_header("%s", nMiss>=ArraySize(azSuffix)?
517 "Not Found" : "Documentation");
518 }
519 blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail));
520 style_footer();
521 }else if( fossil_strcmp(zMime, "text/plain")==0 ){
522 style_header("Documentation");
@@ -536,18 +533,25 @@
533 #endif
534 }else{
535 cgi_set_content_type(zMime);
536 cgi_set_content(&filebody);
537 }
538 if( nMiss>=ArraySize(azSuffix) ) cgi_set_status(404, "Not Found");
539 db_end_transaction(0);
540 return;
541
 
542 /* Jump here when unable to locate the document */
543 doc_not_found:
544 db_end_transaction(0);
545 cgi_set_status(404, "Not Found");
546 style_header("Not Found");
547 @ <p>Document %h(zOrigName) not found
548 if( fossil_strcmp(zCheckin,"ckout")!=0 ){
549 @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a>
550 }
551 style_footer();
552 db_end_transaction(0);
553 return;
554 }
555
556 /*
557 ** The default logo.
558
+4 -4
--- src/export.c
+++ src/export.c
@@ -104,18 +104,18 @@
104104
**
105105
** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY?
106106
**
107107
** Write an export of all check-ins to standard output. The export is
108108
** written in the git-fast-export file format assuming the --git option is
109
-** provided. The git-fast-export format is currently the only VCS
109
+** provided. The git-fast-export format is currently the only VCS
110110
** interchange format supported, though other formats may be added in
111111
** the future.
112112
**
113113
** Run this command within a checkout. Or use the -R or --repository
114114
** option to specify a Fossil repository to be exported.
115115
**
116
-** Only check-ins are exported using --git. Git does not support tickets
116
+** Only check-ins are exported using --git. Git does not support tickets
117117
** or wiki or events or attachments, so none of those are exported.
118118
**
119119
** If the "--import-marks FILE" option is used, it contains a list of
120120
** rids to skip.
121121
**
@@ -124,11 +124,11 @@
124124
**
125125
** Options:
126126
** --export-marks FILE export rids of exported data to FILE
127127
** --import-marks FILE read rids of data to ignore from FILE
128128
** --repository|-R REPOSITORY export the given REPOSITORY
129
-**
129
+**
130130
** See also: import
131131
*/
132132
void export_cmd(void){
133133
Stmt q, q2, q3;
134134
int i;
@@ -179,11 +179,11 @@
179179
db_finalize(&qc);
180180
fclose(f);
181181
}
182182
183183
/* Step 1: Generate "blob" records for every artifact that is part
184
- ** of a check-in
184
+ ** of a check-in
185185
*/
186186
fossil_binary_mode(stdout);
187187
db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
188188
db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
189189
db_multi_exec(
190190
--- src/export.c
+++ src/export.c
@@ -104,18 +104,18 @@
104 **
105 ** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY?
106 **
107 ** Write an export of all check-ins to standard output. The export is
108 ** written in the git-fast-export file format assuming the --git option is
109 ** provided. The git-fast-export format is currently the only VCS
110 ** interchange format supported, though other formats may be added in
111 ** the future.
112 **
113 ** Run this command within a checkout. Or use the -R or --repository
114 ** option to specify a Fossil repository to be exported.
115 **
116 ** Only check-ins are exported using --git. Git does not support tickets
117 ** or wiki or events or attachments, so none of those are exported.
118 **
119 ** If the "--import-marks FILE" option is used, it contains a list of
120 ** rids to skip.
121 **
@@ -124,11 +124,11 @@
124 **
125 ** Options:
126 ** --export-marks FILE export rids of exported data to FILE
127 ** --import-marks FILE read rids of data to ignore from FILE
128 ** --repository|-R REPOSITORY export the given REPOSITORY
129 **
130 ** See also: import
131 */
132 void export_cmd(void){
133 Stmt q, q2, q3;
134 int i;
@@ -179,11 +179,11 @@
179 db_finalize(&qc);
180 fclose(f);
181 }
182
183 /* Step 1: Generate "blob" records for every artifact that is part
184 ** of a check-in
185 */
186 fossil_binary_mode(stdout);
187 db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
188 db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
189 db_multi_exec(
190
--- src/export.c
+++ src/export.c
@@ -104,18 +104,18 @@
104 **
105 ** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY?
106 **
107 ** Write an export of all check-ins to standard output. The export is
108 ** written in the git-fast-export file format assuming the --git option is
109 ** provided. The git-fast-export format is currently the only VCS
110 ** interchange format supported, though other formats may be added in
111 ** the future.
112 **
113 ** Run this command within a checkout. Or use the -R or --repository
114 ** option to specify a Fossil repository to be exported.
115 **
116 ** Only check-ins are exported using --git. Git does not support tickets
117 ** or wiki or events or attachments, so none of those are exported.
118 **
119 ** If the "--import-marks FILE" option is used, it contains a list of
120 ** rids to skip.
121 **
@@ -124,11 +124,11 @@
124 **
125 ** Options:
126 ** --export-marks FILE export rids of exported data to FILE
127 ** --import-marks FILE read rids of data to ignore from FILE
128 ** --repository|-R REPOSITORY export the given REPOSITORY
129 **
130 ** See also: import
131 */
132 void export_cmd(void){
133 Stmt q, q2, q3;
134 int i;
@@ -179,11 +179,11 @@
179 db_finalize(&qc);
180 fclose(f);
181 }
182
183 /* Step 1: Generate "blob" records for every artifact that is part
184 ** of a check-in
185 */
186 fossil_binary_mode(stdout);
187 db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
188 db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
189 db_multi_exec(
190
+19
--- src/file.c
+++ src/file.c
@@ -1262,10 +1262,29 @@
12621262
char *zValue = getenv(zName);
12631263
#endif
12641264
if( zValue ) zValue = fossil_filename_to_utf8(zValue);
12651265
return zValue;
12661266
}
1267
+
1268
+/*
1269
+** Sets the value of an environment variable as UTF8.
1270
+*/
1271
+int fossil_setenv(const char *zName, const char *zValue){
1272
+ int rc;
1273
+ char *zString = mprintf("%s=%s", zName, zValue);
1274
+#ifdef _WIN32
1275
+ wchar_t *uString = fossil_utf8_to_unicode(zString);
1276
+ rc = _wputenv(uString);
1277
+ fossil_unicode_free(uString);
1278
+ fossil_free(zString);
1279
+#else
1280
+ rc = putenv(zString);
1281
+ /* NOTE: Cannot free the string on POSIX. */
1282
+ /* fossil_free(zString); */
1283
+#endif
1284
+ return rc;
1285
+}
12671286
12681287
/*
12691288
** Like fopen() but always takes a UTF8 argument.
12701289
*/
12711290
FILE *fossil_fopen(const char *zName, const char *zMode){
12721291
--- src/file.c
+++ src/file.c
@@ -1262,10 +1262,29 @@
1262 char *zValue = getenv(zName);
1263 #endif
1264 if( zValue ) zValue = fossil_filename_to_utf8(zValue);
1265 return zValue;
1266 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1267
1268 /*
1269 ** Like fopen() but always takes a UTF8 argument.
1270 */
1271 FILE *fossil_fopen(const char *zName, const char *zMode){
1272
--- src/file.c
+++ src/file.c
@@ -1262,10 +1262,29 @@
1262 char *zValue = getenv(zName);
1263 #endif
1264 if( zValue ) zValue = fossil_filename_to_utf8(zValue);
1265 return zValue;
1266 }
1267
1268 /*
1269 ** Sets the value of an environment variable as UTF8.
1270 */
1271 int fossil_setenv(const char *zName, const char *zValue){
1272 int rc;
1273 char *zString = mprintf("%s=%s", zName, zValue);
1274 #ifdef _WIN32
1275 wchar_t *uString = fossil_utf8_to_unicode(zString);
1276 rc = _wputenv(uString);
1277 fossil_unicode_free(uString);
1278 fossil_free(zString);
1279 #else
1280 rc = putenv(zString);
1281 /* NOTE: Cannot free the string on POSIX. */
1282 /* fossil_free(zString); */
1283 #endif
1284 return rc;
1285 }
1286
1287 /*
1288 ** Like fopen() but always takes a UTF8 argument.
1289 */
1290 FILE *fossil_fopen(const char *zName, const char *zMode){
1291
+69 -55
--- src/finfo.c
+++ src/finfo.c
@@ -250,11 +250,11 @@
250250
int rc;
251251
Blob content, fname;
252252
const char *zRev;
253253
db_find_and_open_repository(0, 0);
254254
zRev = find_option("r","r",1);
255
-
255
+
256256
/* We should be done with options.. */
257257
verify_all_options();
258258
259259
for(i=2; i<g.argc; i++){
260260
file_tree_name(g.argv[i], &fname, 1);
@@ -284,110 +284,92 @@
284284
** b=DATE Only show changes before DATE
285285
** n=NUM Show the first NUM changes only
286286
** brbg Background color by branch name
287287
** ubg Background color by user name
288288
** ci=UUID Ancestors of a particular check-in
289
-** fco=BOOL Show only first occurrence of each version if true (default)
290289
*/
291290
void finfo_page(void){
292291
Stmt q;
293292
const char *zFilename;
294293
char zPrevDate[20];
295294
const char *zA;
296295
const char *zB;
297296
int n;
298297
int baseCheckin;
299
-
298
+ int fnid;
299
+ Bag ancestor;
300300
Blob title;
301301
Blob sql;
302302
HQuery url;
303303
GraphContext *pGraph;
304304
int brBg = P("brbg")!=0;
305305
int uBg = P("ubg")!=0;
306
- int firstChngOnly = atoi(PD("fco","1"))!=0;
307306
int fDebug = atoi(PD("debug","0"));
307
+ int fShowId = P("showid")!=0;
308308
309309
login_check_credentials();
310310
if( !g.perm.Read ){ login_needed(); return; }
311311
style_header("File History");
312312
login_anonymous_available();
313313
url_initialize(&url, "finfo");
314314
if( brBg ) url_add_parameter(&url, "brbg", 0);
315315
if( uBg ) url_add_parameter(&url, "ubg", 0);
316316
baseCheckin = name_to_rid_www("ci");
317
- if( baseCheckin ) firstChngOnly = 1;
318
- if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
319
-
320317
zPrevDate[0] = 0;
321318
zFilename = PD("name","");
319
+ fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
320
+ if( fnid==0 ){
321
+ @ No such file: %h(zFilename)
322
+ style_footer();
323
+ return;
324
+ }
325
+ if( baseCheckin ){
326
+ int baseFid = db_int(0,
327
+ "SELECT fid FROM mlink WHERE fnid=%d AND mid=%d",
328
+ fnid, baseCheckin
329
+ );
330
+ bag_init(&ancestor);
331
+ if( baseFid ) bag_insert(&ancestor, baseFid);
332
+ }
322333
url_add_parameter(&url, "name", zFilename);
323334
blob_zero(&sql);
324335
blob_append_sql(&sql,
325336
"SELECT"
326
- " datetime(event.mtime%s)," /* Date of change */
337
+ " datetime(min(event.mtime)%s)," /* Date of change */
327338
" coalesce(event.ecomment, event.comment)," /* Check-in comment */
328339
" coalesce(event.euser, event.user)," /* User who made chng */
329340
" mlink.pid," /* Parent file rid */
330341
" mlink.fid," /* File rid */
331342
" (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
332343
" (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
333344
" (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */
334345
" event.bgcolor," /* Background color */
335346
" (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
336
- " AND tagxref.rid=mlink.mid)," /* Tags */
347
+ " AND tagxref.rid=mlink.mid)," /* Branchname */
337348
" mlink.mid," /* check-in ID */
338
- " mlink.pfnid", /* Previous filename */
339
- timeline_utc(), TAG_BRANCH
340
- );
341
- if( firstChngOnly ){
342
-#if 0
343
- blob_append_sql(&sql, ", min(event.mtime)");
344
-#else
345
- blob_append_sql(&sql,
346
- ", min(CASE (SELECT value FROM tagxref"
347
- " WHERE tagtype>0 AND tagid=%d"
348
- " AND tagxref.rid=mlink.mid)"
349
- " WHEN 'trunk' THEN event.mtime-10000 ELSE event.mtime END)",
350
- TAG_BRANCH);
351
-#endif
352
- }
353
- blob_append_sql(&sql,
349
+ " mlink.pfnid" /* Previous filename */
354350
" FROM mlink, event"
355
- " WHERE mlink.fnid IN (SELECT fnid FROM filename WHERE name=%Q)"
351
+ " WHERE mlink.fnid=%d"
356352
" AND event.objid=mlink.mid",
357
- zFilename
353
+ timeline_utc(), TAG_BRANCH, fnid
358354
);
359
- if( baseCheckin ){
360
- compute_direct_ancestors(baseCheckin, 10000000);
361
- blob_append_sql(&sql," AND mlink.mid IN (SELECT rid FROM ancestor)");
362
- }
363355
if( (zA = P("a"))!=0 ){
364356
blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zA);
365357
url_add_parameter(&url, "a", zA);
366358
}
367359
if( (zB = P("b"))!=0 ){
368360
blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zB);
369361
url_add_parameter(&url, "b", zB);
370362
}
371
- if( firstChngOnly ){
372
- blob_append_sql(&sql, " GROUP BY mlink.fid");
373
- }
374
- blob_append_sql(&sql," ORDER BY event.mtime DESC /*sort*/");
363
+ blob_append_sql(&sql,
364
+ " GROUP BY mlink.fid"
365
+ " ORDER BY event.mtime DESC /*sort*/"
366
+ );
375367
if( (n = atoi(PD("n","0")))>0 ){
376368
blob_append_sql(&sql, " LIMIT %d", n);
377369
url_add_parameter(&url, "n", P("n"));
378370
}
379
- if( baseCheckin==0 ){
380
- if( firstChngOnly ){
381
- style_submenu_element("Full", "Show all changes","%s",
382
- url_render(&url, "fco", "0", 0, 0));
383
- }else{
384
- style_submenu_element("Simplified",
385
- "Show only first use of a change","%s",
386
- url_render(&url, "fco", 0, 0, 0));
387
- }
388
- }
389371
db_prepare(&q, "%s", blob_sql_text(&sql));
390372
if( P("showsql")!=0 ){
391373
@ <p>SQL: %h(blob_str(&sql))</p>
392374
}
393375
blob_reset(&sql);
@@ -395,15 +377,18 @@
395377
if( baseCheckin ){
396378
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
397379
char *zLink = href("%R/info/%s", zUuid);
398380
blob_appendf(&title, "Ancestors of file ");
399381
hyperlinked_path(zFilename, &title, zUuid, "tree", "");
382
+ if( fShowId ) blob_appendf(&title, " (%d)", fnid);
400383
blob_appendf(&title, " from check-in %z%S</a>", zLink, zUuid);
384
+ if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
401385
fossil_free(zUuid);
402386
}else{
403387
blob_appendf(&title, "History of files named ");
404388
hyperlinked_path(zFilename, &title, 0, "tree", "");
389
+ if( fShowId ) blob_appendf(&title, " (%d)", fnid);
405390
}
406391
@ <h2>%b(&title)</h2>
407392
blob_reset(&title);
408393
pGraph = graph_init();
409394
@ <div id="canvas" style="position:relative;width:1px;height:1px;"
@@ -422,17 +407,36 @@
422407
const char *zBr = db_column_text(&q, 9);
423408
int fmid = db_column_int(&q, 10);
424409
int pfnid = db_column_int(&q, 11);
425410
int gidx;
426411
char zTime[10];
412
+ int nParent = 0;
413
+ int aParent[GR_MAX_RAIL];
414
+ static Stmt qparent;
415
+
416
+ if( baseCheckin && frid && !bag_find(&ancestor, frid) ) continue;
417
+ db_static_prepare(&qparent,
418
+ "SELECT DISTINCT pid FROM mlink"
419
+ " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid"
420
+ " ORDER BY isaux /*sort*/"
421
+ );
422
+ db_bind_int(&qparent, ":fid", frid);
423
+ db_bind_int(&qparent, ":mid", fmid);
424
+ db_bind_int(&qparent, ":fnid", fnid);
425
+ while( db_step(&qparent)==SQLITE_ROW && nParent<ArraySize(aParent) ){
426
+ aParent[nParent] = db_column_int(&qparent, 0);
427
+ if( baseCheckin ) bag_insert(&ancestor, aParent[nParent]);
428
+ nParent++;
429
+ }
430
+ db_reset(&qparent);
427431
if( zBr==0 ) zBr = "trunk";
428432
if( uBg ){
429433
zBgClr = hash_color(zUser);
430434
}else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
431435
zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
432436
}
433
- gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr,
437
+ gidx = graph_add_row(pGraph, frid, nParent, aParent, zBr, zBgClr,
434438
zUuid, 0);
435439
if( strncmp(zDate, zPrevDate, 10) ){
436440
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
437441
@ <tr><td>
438442
@ <div class="divider">%s(zPrevDate)</div>
@@ -447,19 +451,23 @@
447451
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
448452
}else{
449453
@ <td class="timelineTableCell">
450454
}
451455
if( zUuid ){
452
- if( fpid==0 ){
456
+ if( nParent==0 ){
453457
@ <b>Added</b>
454458
}else if( pfnid ){
455459
char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
456460
pfnid);
457461
@ <b>Renamed</b> from
458462
@ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
459463
}
460
- @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
464
+ @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a>
465
+ if( fShowId ){
466
+ @ (%d(frid))
467
+ }
468
+ @ part of check-in
461469
}else{
462470
char *zNewName;
463471
zNewName = db_text(0,
464472
"SELECT name FROM filename WHERE fnid = "
465473
" (SELECT fnid FROM mlink"
@@ -473,13 +481,16 @@
473481
}else{
474482
@ <b>Deleted</b> by check-in
475483
}
476484
}
477485
hyperlink_to_uuid(zCkin);
486
+ if( fShowId ){
487
+ @ (%d(fmid))
488
+ }
478489
@ %W(zCom) (user:
479490
hyperlink_to_user(zUser, zDate, "");
480
- @ branch: %h(zBr))
491
+ @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>
481492
if( g.perm.Hyperlink && zUuid ){
482493
const char *z = zFilename;
483494
@ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
484495
@ [annotate]</a>
485496
@ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
@@ -488,23 +499,26 @@
488499
if( fpid ){
489500
@ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
490501
}
491502
}
492503
if( fDebug & FINFO_DEBUG_MLINK ){
493
- int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
494
- int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
495
- @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid) sz=%d(sz)
496
- if( srcid ){
497
- @ srcid=%d(srcid)
504
+ int ii;
505
+ @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid)
506
+ if( nParent>0 ){
507
+ @ parents=%d(aParent[0])
508
+ for(ii=1; ii<nParent; ii++){
509
+ @ %d(aParent[ii])
510
+ }
498511
}
512
+ @ %z(href("%R/finfo?name=%T&ci=%s&debug=1",zFilename,zCkin))[ancestry]</a>
499513
}
500514
tag_private_status(frid);
501515
@ </td></tr>
502516
}
503517
db_finalize(&q);
504518
if( pGraph ){
505
- graph_finish(pGraph, 0);
519
+ graph_finish(pGraph, 1);
506520
if( pGraph->nErr ){
507521
graph_free(pGraph);
508522
pGraph = 0;
509523
}else{
510524
int w = (pGraph->mxRail+1)*pGraph->iRailPitch + 10;
511525
--- src/finfo.c
+++ src/finfo.c
@@ -250,11 +250,11 @@
250 int rc;
251 Blob content, fname;
252 const char *zRev;
253 db_find_and_open_repository(0, 0);
254 zRev = find_option("r","r",1);
255
256 /* We should be done with options.. */
257 verify_all_options();
258
259 for(i=2; i<g.argc; i++){
260 file_tree_name(g.argv[i], &fname, 1);
@@ -284,110 +284,92 @@
284 ** b=DATE Only show changes before DATE
285 ** n=NUM Show the first NUM changes only
286 ** brbg Background color by branch name
287 ** ubg Background color by user name
288 ** ci=UUID Ancestors of a particular check-in
289 ** fco=BOOL Show only first occurrence of each version if true (default)
290 */
291 void finfo_page(void){
292 Stmt q;
293 const char *zFilename;
294 char zPrevDate[20];
295 const char *zA;
296 const char *zB;
297 int n;
298 int baseCheckin;
299
 
300 Blob title;
301 Blob sql;
302 HQuery url;
303 GraphContext *pGraph;
304 int brBg = P("brbg")!=0;
305 int uBg = P("ubg")!=0;
306 int firstChngOnly = atoi(PD("fco","1"))!=0;
307 int fDebug = atoi(PD("debug","0"));
 
308
309 login_check_credentials();
310 if( !g.perm.Read ){ login_needed(); return; }
311 style_header("File History");
312 login_anonymous_available();
313 url_initialize(&url, "finfo");
314 if( brBg ) url_add_parameter(&url, "brbg", 0);
315 if( uBg ) url_add_parameter(&url, "ubg", 0);
316 baseCheckin = name_to_rid_www("ci");
317 if( baseCheckin ) firstChngOnly = 1;
318 if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
319
320 zPrevDate[0] = 0;
321 zFilename = PD("name","");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322 url_add_parameter(&url, "name", zFilename);
323 blob_zero(&sql);
324 blob_append_sql(&sql,
325 "SELECT"
326 " datetime(event.mtime%s)," /* Date of change */
327 " coalesce(event.ecomment, event.comment)," /* Check-in comment */
328 " coalesce(event.euser, event.user)," /* User who made chng */
329 " mlink.pid," /* Parent file rid */
330 " mlink.fid," /* File rid */
331 " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
332 " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
333 " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */
334 " event.bgcolor," /* Background color */
335 " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
336 " AND tagxref.rid=mlink.mid)," /* Tags */
337 " mlink.mid," /* check-in ID */
338 " mlink.pfnid", /* Previous filename */
339 timeline_utc(), TAG_BRANCH
340 );
341 if( firstChngOnly ){
342 #if 0
343 blob_append_sql(&sql, ", min(event.mtime)");
344 #else
345 blob_append_sql(&sql,
346 ", min(CASE (SELECT value FROM tagxref"
347 " WHERE tagtype>0 AND tagid=%d"
348 " AND tagxref.rid=mlink.mid)"
349 " WHEN 'trunk' THEN event.mtime-10000 ELSE event.mtime END)",
350 TAG_BRANCH);
351 #endif
352 }
353 blob_append_sql(&sql,
354 " FROM mlink, event"
355 " WHERE mlink.fnid IN (SELECT fnid FROM filename WHERE name=%Q)"
356 " AND event.objid=mlink.mid",
357 zFilename
358 );
359 if( baseCheckin ){
360 compute_direct_ancestors(baseCheckin, 10000000);
361 blob_append_sql(&sql," AND mlink.mid IN (SELECT rid FROM ancestor)");
362 }
363 if( (zA = P("a"))!=0 ){
364 blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zA);
365 url_add_parameter(&url, "a", zA);
366 }
367 if( (zB = P("b"))!=0 ){
368 blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zB);
369 url_add_parameter(&url, "b", zB);
370 }
371 if( firstChngOnly ){
372 blob_append_sql(&sql, " GROUP BY mlink.fid");
373 }
374 blob_append_sql(&sql," ORDER BY event.mtime DESC /*sort*/");
375 if( (n = atoi(PD("n","0")))>0 ){
376 blob_append_sql(&sql, " LIMIT %d", n);
377 url_add_parameter(&url, "n", P("n"));
378 }
379 if( baseCheckin==0 ){
380 if( firstChngOnly ){
381 style_submenu_element("Full", "Show all changes","%s",
382 url_render(&url, "fco", "0", 0, 0));
383 }else{
384 style_submenu_element("Simplified",
385 "Show only first use of a change","%s",
386 url_render(&url, "fco", 0, 0, 0));
387 }
388 }
389 db_prepare(&q, "%s", blob_sql_text(&sql));
390 if( P("showsql")!=0 ){
391 @ <p>SQL: %h(blob_str(&sql))</p>
392 }
393 blob_reset(&sql);
@@ -395,15 +377,18 @@
395 if( baseCheckin ){
396 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
397 char *zLink = href("%R/info/%s", zUuid);
398 blob_appendf(&title, "Ancestors of file ");
399 hyperlinked_path(zFilename, &title, zUuid, "tree", "");
 
400 blob_appendf(&title, " from check-in %z%S</a>", zLink, zUuid);
 
401 fossil_free(zUuid);
402 }else{
403 blob_appendf(&title, "History of files named ");
404 hyperlinked_path(zFilename, &title, 0, "tree", "");
 
405 }
406 @ <h2>%b(&title)</h2>
407 blob_reset(&title);
408 pGraph = graph_init();
409 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
@@ -422,17 +407,36 @@
422 const char *zBr = db_column_text(&q, 9);
423 int fmid = db_column_int(&q, 10);
424 int pfnid = db_column_int(&q, 11);
425 int gidx;
426 char zTime[10];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427 if( zBr==0 ) zBr = "trunk";
428 if( uBg ){
429 zBgClr = hash_color(zUser);
430 }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
431 zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
432 }
433 gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr,
434 zUuid, 0);
435 if( strncmp(zDate, zPrevDate, 10) ){
436 sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
437 @ <tr><td>
438 @ <div class="divider">%s(zPrevDate)</div>
@@ -447,19 +451,23 @@
447 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
448 }else{
449 @ <td class="timelineTableCell">
450 }
451 if( zUuid ){
452 if( fpid==0 ){
453 @ <b>Added</b>
454 }else if( pfnid ){
455 char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
456 pfnid);
457 @ <b>Renamed</b> from
458 @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
459 }
460 @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
 
 
 
 
461 }else{
462 char *zNewName;
463 zNewName = db_text(0,
464 "SELECT name FROM filename WHERE fnid = "
465 " (SELECT fnid FROM mlink"
@@ -473,13 +481,16 @@
473 }else{
474 @ <b>Deleted</b> by check-in
475 }
476 }
477 hyperlink_to_uuid(zCkin);
 
 
 
478 @ %W(zCom) (user:
479 hyperlink_to_user(zUser, zDate, "");
480 @ branch: %h(zBr))
481 if( g.perm.Hyperlink && zUuid ){
482 const char *z = zFilename;
483 @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
484 @ [annotate]</a>
485 @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
@@ -488,23 +499,26 @@
488 if( fpid ){
489 @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
490 }
491 }
492 if( fDebug & FINFO_DEBUG_MLINK ){
493 int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
494 int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
495 @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid) sz=%d(sz)
496 if( srcid ){
497 @ srcid=%d(srcid)
 
 
498 }
 
499 }
500 tag_private_status(frid);
501 @ </td></tr>
502 }
503 db_finalize(&q);
504 if( pGraph ){
505 graph_finish(pGraph, 0);
506 if( pGraph->nErr ){
507 graph_free(pGraph);
508 pGraph = 0;
509 }else{
510 int w = (pGraph->mxRail+1)*pGraph->iRailPitch + 10;
511
--- src/finfo.c
+++ src/finfo.c
@@ -250,11 +250,11 @@
250 int rc;
251 Blob content, fname;
252 const char *zRev;
253 db_find_and_open_repository(0, 0);
254 zRev = find_option("r","r",1);
255
256 /* We should be done with options.. */
257 verify_all_options();
258
259 for(i=2; i<g.argc; i++){
260 file_tree_name(g.argv[i], &fname, 1);
@@ -284,110 +284,92 @@
284 ** b=DATE Only show changes before DATE
285 ** n=NUM Show the first NUM changes only
286 ** brbg Background color by branch name
287 ** ubg Background color by user name
288 ** ci=UUID Ancestors of a particular check-in
 
289 */
290 void finfo_page(void){
291 Stmt q;
292 const char *zFilename;
293 char zPrevDate[20];
294 const char *zA;
295 const char *zB;
296 int n;
297 int baseCheckin;
298 int fnid;
299 Bag ancestor;
300 Blob title;
301 Blob sql;
302 HQuery url;
303 GraphContext *pGraph;
304 int brBg = P("brbg")!=0;
305 int uBg = P("ubg")!=0;
 
306 int fDebug = atoi(PD("debug","0"));
307 int fShowId = P("showid")!=0;
308
309 login_check_credentials();
310 if( !g.perm.Read ){ login_needed(); return; }
311 style_header("File History");
312 login_anonymous_available();
313 url_initialize(&url, "finfo");
314 if( brBg ) url_add_parameter(&url, "brbg", 0);
315 if( uBg ) url_add_parameter(&url, "ubg", 0);
316 baseCheckin = name_to_rid_www("ci");
 
 
 
317 zPrevDate[0] = 0;
318 zFilename = PD("name","");
319 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
320 if( fnid==0 ){
321 @ No such file: %h(zFilename)
322 style_footer();
323 return;
324 }
325 if( baseCheckin ){
326 int baseFid = db_int(0,
327 "SELECT fid FROM mlink WHERE fnid=%d AND mid=%d",
328 fnid, baseCheckin
329 );
330 bag_init(&ancestor);
331 if( baseFid ) bag_insert(&ancestor, baseFid);
332 }
333 url_add_parameter(&url, "name", zFilename);
334 blob_zero(&sql);
335 blob_append_sql(&sql,
336 "SELECT"
337 " datetime(min(event.mtime)%s)," /* Date of change */
338 " coalesce(event.ecomment, event.comment)," /* Check-in comment */
339 " coalesce(event.euser, event.user)," /* User who made chng */
340 " mlink.pid," /* Parent file rid */
341 " mlink.fid," /* File rid */
342 " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
343 " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
344 " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */
345 " event.bgcolor," /* Background color */
346 " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
347 " AND tagxref.rid=mlink.mid)," /* Branchname */
348 " mlink.mid," /* check-in ID */
349 " mlink.pfnid" /* Previous filename */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350 " FROM mlink, event"
351 " WHERE mlink.fnid=%d"
352 " AND event.objid=mlink.mid",
353 timeline_utc(), TAG_BRANCH, fnid
354 );
 
 
 
 
355 if( (zA = P("a"))!=0 ){
356 blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zA);
357 url_add_parameter(&url, "a", zA);
358 }
359 if( (zB = P("b"))!=0 ){
360 blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zB);
361 url_add_parameter(&url, "b", zB);
362 }
363 blob_append_sql(&sql,
364 " GROUP BY mlink.fid"
365 " ORDER BY event.mtime DESC /*sort*/"
366 );
367 if( (n = atoi(PD("n","0")))>0 ){
368 blob_append_sql(&sql, " LIMIT %d", n);
369 url_add_parameter(&url, "n", P("n"));
370 }
 
 
 
 
 
 
 
 
 
 
371 db_prepare(&q, "%s", blob_sql_text(&sql));
372 if( P("showsql")!=0 ){
373 @ <p>SQL: %h(blob_str(&sql))</p>
374 }
375 blob_reset(&sql);
@@ -395,15 +377,18 @@
377 if( baseCheckin ){
378 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
379 char *zLink = href("%R/info/%s", zUuid);
380 blob_appendf(&title, "Ancestors of file ");
381 hyperlinked_path(zFilename, &title, zUuid, "tree", "");
382 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
383 blob_appendf(&title, " from check-in %z%S</a>", zLink, zUuid);
384 if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
385 fossil_free(zUuid);
386 }else{
387 blob_appendf(&title, "History of files named ");
388 hyperlinked_path(zFilename, &title, 0, "tree", "");
389 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
390 }
391 @ <h2>%b(&title)</h2>
392 blob_reset(&title);
393 pGraph = graph_init();
394 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
@@ -422,17 +407,36 @@
407 const char *zBr = db_column_text(&q, 9);
408 int fmid = db_column_int(&q, 10);
409 int pfnid = db_column_int(&q, 11);
410 int gidx;
411 char zTime[10];
412 int nParent = 0;
413 int aParent[GR_MAX_RAIL];
414 static Stmt qparent;
415
416 if( baseCheckin && frid && !bag_find(&ancestor, frid) ) continue;
417 db_static_prepare(&qparent,
418 "SELECT DISTINCT pid FROM mlink"
419 " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid"
420 " ORDER BY isaux /*sort*/"
421 );
422 db_bind_int(&qparent, ":fid", frid);
423 db_bind_int(&qparent, ":mid", fmid);
424 db_bind_int(&qparent, ":fnid", fnid);
425 while( db_step(&qparent)==SQLITE_ROW && nParent<ArraySize(aParent) ){
426 aParent[nParent] = db_column_int(&qparent, 0);
427 if( baseCheckin ) bag_insert(&ancestor, aParent[nParent]);
428 nParent++;
429 }
430 db_reset(&qparent);
431 if( zBr==0 ) zBr = "trunk";
432 if( uBg ){
433 zBgClr = hash_color(zUser);
434 }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
435 zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
436 }
437 gidx = graph_add_row(pGraph, frid, nParent, aParent, zBr, zBgClr,
438 zUuid, 0);
439 if( strncmp(zDate, zPrevDate, 10) ){
440 sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
441 @ <tr><td>
442 @ <div class="divider">%s(zPrevDate)</div>
@@ -447,19 +451,23 @@
451 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
452 }else{
453 @ <td class="timelineTableCell">
454 }
455 if( zUuid ){
456 if( nParent==0 ){
457 @ <b>Added</b>
458 }else if( pfnid ){
459 char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
460 pfnid);
461 @ <b>Renamed</b> from
462 @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
463 }
464 @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a>
465 if( fShowId ){
466 @ (%d(frid))
467 }
468 @ part of check-in
469 }else{
470 char *zNewName;
471 zNewName = db_text(0,
472 "SELECT name FROM filename WHERE fnid = "
473 " (SELECT fnid FROM mlink"
@@ -473,13 +481,16 @@
481 }else{
482 @ <b>Deleted</b> by check-in
483 }
484 }
485 hyperlink_to_uuid(zCkin);
486 if( fShowId ){
487 @ (%d(fmid))
488 }
489 @ %W(zCom) (user:
490 hyperlink_to_user(zUser, zDate, "");
491 @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>
492 if( g.perm.Hyperlink && zUuid ){
493 const char *z = zFilename;
494 @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
495 @ [annotate]</a>
496 @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
@@ -488,23 +499,26 @@
499 if( fpid ){
500 @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
501 }
502 }
503 if( fDebug & FINFO_DEBUG_MLINK ){
504 int ii;
505 @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid)
506 if( nParent>0 ){
507 @ parents=%d(aParent[0])
508 for(ii=1; ii<nParent; ii++){
509 @ %d(aParent[ii])
510 }
511 }
512 @ %z(href("%R/finfo?name=%T&ci=%s&debug=1",zFilename,zCkin))[ancestry]</a>
513 }
514 tag_private_status(frid);
515 @ </td></tr>
516 }
517 db_finalize(&q);
518 if( pGraph ){
519 graph_finish(pGraph, 1);
520 if( pGraph->nErr ){
521 graph_free(pGraph);
522 pGraph = 0;
523 }else{
524 int w = (pGraph->mxRail+1)*pGraph->iRailPitch + 10;
525
+25 -5
--- src/foci.c
+++ src/foci.c
@@ -17,25 +17,45 @@
1717
**
1818
** This routine implements an SQLite virtual table that gives all of the
1919
** files associated with a single checkin.
2020
**
2121
** The filename "foci" is short for "Files Of CheckIn".
22
+**
23
+** Usage example:
24
+**
25
+** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
26
+** -- ^^^^--- important!
27
+** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
28
+**
29
+** The symbolic_name_to_rid('trunk') function finds the BLOB.RID value
30
+** corresponding to the 'trunk' tag. Then the files_of_checkin virtual table
31
+** decodes the manifest defined by that BLOB and returns all files described
32
+** by that manifest. The "schema" for the temp.foci table is:
33
+**
34
+** CREATE TABLE files_of_checkin(
35
+** checkinID INTEGER, -- RID for the checkin manifest
36
+** filename TEXT, -- Name of a file
37
+** uuid TEXT, -- SHA1 hash of the file
38
+** previousName TEXT, -- Name of the file in previous checkin
39
+** perm TEXT -- Permissions on the file
40
+** );
41
+**
2242
*/
2343
#include "config.h"
2444
#include "foci.h"
2545
#include <assert.h>
2646
2747
/*
2848
** The schema for the virtual table:
2949
*/
30
-static const char zFociSchema[] =
50
+static const char zFociSchema[] =
3151
@ CREATE TABLE files_of_checkin(
3252
@ checkinID INTEGER, -- RID for the checkin manifest
3353
@ filename TEXT, -- Name of a file
3454
@ uuid TEXT, -- SHA1 hash of the file
3555
@ previousName TEXT, -- Name of the file in previous checkin
36
-@ prem TEXT -- Permissions on the file
56
+@ perm TEXT -- Permissions on the file
3757
@ );
3858
;
3959
4060
#if INTERFACE
4161
/*
@@ -139,11 +159,11 @@
139159
FociCursor *pCsr = (FociCursor *)pCursor;
140160
return pCsr->pFile==0;
141161
}
142162
143163
static int fociFilter(
144
- sqlite3_vtab_cursor *pCursor,
164
+ sqlite3_vtab_cursor *pCursor,
145165
int idxNum, const char *idxStr,
146166
int argc, sqlite3_value **argv
147167
){
148168
FociCursor *pCur = (FociCursor *)pCursor;
149169
manifest_destroy(pCur->pMan);
@@ -158,12 +178,12 @@
158178
}
159179
return SQLITE_OK;
160180
}
161181
162182
static int fociColumn(
163
- sqlite3_vtab_cursor *pCursor,
164
- sqlite3_context *ctx,
183
+ sqlite3_vtab_cursor *pCursor,
184
+ sqlite3_context *ctx,
165185
int i
166186
){
167187
FociCursor *pCsr = (FociCursor *)pCursor;
168188
switch( i ){
169189
case 0: /* checkinID */
170190
--- src/foci.c
+++ src/foci.c
@@ -17,25 +17,45 @@
17 **
18 ** This routine implements an SQLite virtual table that gives all of the
19 ** files associated with a single checkin.
20 **
21 ** The filename "foci" is short for "Files Of CheckIn".
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22 */
23 #include "config.h"
24 #include "foci.h"
25 #include <assert.h>
26
27 /*
28 ** The schema for the virtual table:
29 */
30 static const char zFociSchema[] =
31 @ CREATE TABLE files_of_checkin(
32 @ checkinID INTEGER, -- RID for the checkin manifest
33 @ filename TEXT, -- Name of a file
34 @ uuid TEXT, -- SHA1 hash of the file
35 @ previousName TEXT, -- Name of the file in previous checkin
36 @ prem TEXT -- Permissions on the file
37 @ );
38 ;
39
40 #if INTERFACE
41 /*
@@ -139,11 +159,11 @@
139 FociCursor *pCsr = (FociCursor *)pCursor;
140 return pCsr->pFile==0;
141 }
142
143 static int fociFilter(
144 sqlite3_vtab_cursor *pCursor,
145 int idxNum, const char *idxStr,
146 int argc, sqlite3_value **argv
147 ){
148 FociCursor *pCur = (FociCursor *)pCursor;
149 manifest_destroy(pCur->pMan);
@@ -158,12 +178,12 @@
158 }
159 return SQLITE_OK;
160 }
161
162 static int fociColumn(
163 sqlite3_vtab_cursor *pCursor,
164 sqlite3_context *ctx,
165 int i
166 ){
167 FociCursor *pCsr = (FociCursor *)pCursor;
168 switch( i ){
169 case 0: /* checkinID */
170
--- src/foci.c
+++ src/foci.c
@@ -17,25 +17,45 @@
17 **
18 ** This routine implements an SQLite virtual table that gives all of the
19 ** files associated with a single checkin.
20 **
21 ** The filename "foci" is short for "Files Of CheckIn".
22 **
23 ** Usage example:
24 **
25 ** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
26 ** -- ^^^^--- important!
27 ** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
28 **
29 ** The symbolic_name_to_rid('trunk') function finds the BLOB.RID value
30 ** corresponding to the 'trunk' tag. Then the files_of_checkin virtual table
31 ** decodes the manifest defined by that BLOB and returns all files described
32 ** by that manifest. The "schema" for the temp.foci table is:
33 **
34 ** CREATE TABLE files_of_checkin(
35 ** checkinID INTEGER, -- RID for the checkin manifest
36 ** filename TEXT, -- Name of a file
37 ** uuid TEXT, -- SHA1 hash of the file
38 ** previousName TEXT, -- Name of the file in previous checkin
39 ** perm TEXT -- Permissions on the file
40 ** );
41 **
42 */
43 #include "config.h"
44 #include "foci.h"
45 #include <assert.h>
46
47 /*
48 ** The schema for the virtual table:
49 */
50 static const char zFociSchema[] =
51 @ CREATE TABLE files_of_checkin(
52 @ checkinID INTEGER, -- RID for the checkin manifest
53 @ filename TEXT, -- Name of a file
54 @ uuid TEXT, -- SHA1 hash of the file
55 @ previousName TEXT, -- Name of the file in previous checkin
56 @ perm TEXT -- Permissions on the file
57 @ );
58 ;
59
60 #if INTERFACE
61 /*
@@ -139,11 +159,11 @@
159 FociCursor *pCsr = (FociCursor *)pCursor;
160 return pCsr->pFile==0;
161 }
162
163 static int fociFilter(
164 sqlite3_vtab_cursor *pCursor,
165 int idxNum, const char *idxStr,
166 int argc, sqlite3_value **argv
167 ){
168 FociCursor *pCur = (FociCursor *)pCursor;
169 manifest_destroy(pCur->pMan);
@@ -158,12 +178,12 @@
178 }
179 return SQLITE_OK;
180 }
181
182 static int fociColumn(
183 sqlite3_vtab_cursor *pCursor,
184 sqlite3_context *ctx,
185 int i
186 ){
187 FociCursor *pCsr = (FociCursor *)pCursor;
188 switch( i ){
189 case 0: /* checkinID */
190
+4 -4
--- src/fusefs.c
+++ src/fusefs.c
@@ -14,11 +14,11 @@
1414
** http://www.hwaci.com/drh/
1515
**
1616
*******************************************************************************
1717
**
1818
** This module implements the userspace side of a Fuse Filesystem that
19
-** contains all check-ins for a fossil repository.
19
+** contains all check-ins for a fossil repository.
2020
**
2121
** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS.
2222
** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for
2323
** the Fuse Filesystem, of course.
2424
*/
@@ -193,11 +193,11 @@
193193
int cnt = 0;
194194
n = fusefs_parse_path(zPath);
195195
if( n==0 ){
196196
filler(buf, ".", NULL, 0);
197197
filler(buf, "..", NULL, 0);
198
- filler(buf, "checkins", NULL, 0);
198
+ filler(buf, "checkins", NULL, 0);
199199
return 0;
200200
}
201201
if( strcmp(fusefs.az[0],"checkins")!=0 ) return -ENOENT;
202202
if( n==1 ) return -ENOENT;
203203
rid = fusefs_name_to_rid(fusefs.az[1]);
@@ -275,11 +275,11 @@
275275
if( offset+size>blob_size(&fusefs.content) ){
276276
size = blob_size(&fusefs.content) - offset;
277277
}
278278
memcpy(buf, blob_buffer(&fusefs.content)+offset, size);
279279
return size;
280
-}
280
+}
281281
282282
static struct fuse_operations fusefs_methods = {
283283
.getattr = fusefs_getattr,
284284
.readdir = fusefs_readdir,
285285
.read = fusefs_read,
@@ -293,11 +293,11 @@
293293
**
294294
** This command uses the Fuse Filesystem to mount a directory at
295295
** DIRECTORY that contains the content of all check-ins in the
296296
** repository. The names of files are DIRECTORY/checkins/VERSION/PATH
297297
** where DIRECTORY is the root of the mount, VERSION is any valid
298
-** check-in name (examples: "trunk" or "tip" or a tag or any unique
298
+** check-in name (examples: "trunk" or "tip" or a tag or any unique
299299
** prefix of a SHA1 hash, etc) and PATH is the pathname of the file
300300
** in the checkin. If DIRECTORY does not exist, then an attempt is
301301
** made to create it.
302302
**
303303
** The DIRECTORY/checkins directory is not searchable so one cannot
304304
--- src/fusefs.c
+++ src/fusefs.c
@@ -14,11 +14,11 @@
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This module implements the userspace side of a Fuse Filesystem that
19 ** contains all check-ins for a fossil repository.
20 **
21 ** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS.
22 ** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for
23 ** the Fuse Filesystem, of course.
24 */
@@ -193,11 +193,11 @@
193 int cnt = 0;
194 n = fusefs_parse_path(zPath);
195 if( n==0 ){
196 filler(buf, ".", NULL, 0);
197 filler(buf, "..", NULL, 0);
198 filler(buf, "checkins", NULL, 0);
199 return 0;
200 }
201 if( strcmp(fusefs.az[0],"checkins")!=0 ) return -ENOENT;
202 if( n==1 ) return -ENOENT;
203 rid = fusefs_name_to_rid(fusefs.az[1]);
@@ -275,11 +275,11 @@
275 if( offset+size>blob_size(&fusefs.content) ){
276 size = blob_size(&fusefs.content) - offset;
277 }
278 memcpy(buf, blob_buffer(&fusefs.content)+offset, size);
279 return size;
280 }
281
282 static struct fuse_operations fusefs_methods = {
283 .getattr = fusefs_getattr,
284 .readdir = fusefs_readdir,
285 .read = fusefs_read,
@@ -293,11 +293,11 @@
293 **
294 ** This command uses the Fuse Filesystem to mount a directory at
295 ** DIRECTORY that contains the content of all check-ins in the
296 ** repository. The names of files are DIRECTORY/checkins/VERSION/PATH
297 ** where DIRECTORY is the root of the mount, VERSION is any valid
298 ** check-in name (examples: "trunk" or "tip" or a tag or any unique
299 ** prefix of a SHA1 hash, etc) and PATH is the pathname of the file
300 ** in the checkin. If DIRECTORY does not exist, then an attempt is
301 ** made to create it.
302 **
303 ** The DIRECTORY/checkins directory is not searchable so one cannot
304
--- src/fusefs.c
+++ src/fusefs.c
@@ -14,11 +14,11 @@
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This module implements the userspace side of a Fuse Filesystem that
19 ** contains all check-ins for a fossil repository.
20 **
21 ** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS.
22 ** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for
23 ** the Fuse Filesystem, of course.
24 */
@@ -193,11 +193,11 @@
193 int cnt = 0;
194 n = fusefs_parse_path(zPath);
195 if( n==0 ){
196 filler(buf, ".", NULL, 0);
197 filler(buf, "..", NULL, 0);
198 filler(buf, "checkins", NULL, 0);
199 return 0;
200 }
201 if( strcmp(fusefs.az[0],"checkins")!=0 ) return -ENOENT;
202 if( n==1 ) return -ENOENT;
203 rid = fusefs_name_to_rid(fusefs.az[1]);
@@ -275,11 +275,11 @@
275 if( offset+size>blob_size(&fusefs.content) ){
276 size = blob_size(&fusefs.content) - offset;
277 }
278 memcpy(buf, blob_buffer(&fusefs.content)+offset, size);
279 return size;
280 }
281
282 static struct fuse_operations fusefs_methods = {
283 .getattr = fusefs_getattr,
284 .readdir = fusefs_readdir,
285 .read = fusefs_read,
@@ -293,11 +293,11 @@
293 **
294 ** This command uses the Fuse Filesystem to mount a directory at
295 ** DIRECTORY that contains the content of all check-ins in the
296 ** repository. The names of files are DIRECTORY/checkins/VERSION/PATH
297 ** where DIRECTORY is the root of the mount, VERSION is any valid
298 ** check-in name (examples: "trunk" or "tip" or a tag or any unique
299 ** prefix of a SHA1 hash, etc) and PATH is the pathname of the file
300 ** in the checkin. If DIRECTORY does not exist, then an attempt is
301 ** made to create it.
302 **
303 ** The DIRECTORY/checkins directory is not searchable so one cannot
304
-19
--- src/glob.c
+++ src/glob.c
@@ -138,29 +138,10 @@
138138
z += i+1;
139139
}
140140
return p;
141141
}
142142
143
-/*
144
-** Return non-zero if string z matches glob pattern zGlob and zero if the
145
-** pattern does not match.
146
-**
147
-** Globbing rules:
148
-**
149
-** '*' Matches any sequence of zero or more characters.
150
-**
151
-** '?' Matches exactly one character.
152
-**
153
-** [...] Matches one character from the enclosed list of
154
-** characters.
155
-**
156
-** [^...] Matches one character not in the enclosed list.
157
-*/
158
-int strglob(const char *zGlob, const char *z){
159
- return sqlite3_strglob(zGlob, z)==0;
160
-}
161
-
162143
/*
163144
** Return true (non-zero) if zString matches any of the patterns in
164145
** the Glob. The value returned is actually a 1-based index of the pattern
165146
** that matched. Return 0 if none of the patterns match zString.
166147
**
167148
--- src/glob.c
+++ src/glob.c
@@ -138,29 +138,10 @@
138 z += i+1;
139 }
140 return p;
141 }
142
143 /*
144 ** Return non-zero if string z matches glob pattern zGlob and zero if the
145 ** pattern does not match.
146 **
147 ** Globbing rules:
148 **
149 ** '*' Matches any sequence of zero or more characters.
150 **
151 ** '?' Matches exactly one character.
152 **
153 ** [...] Matches one character from the enclosed list of
154 ** characters.
155 **
156 ** [^...] Matches one character not in the enclosed list.
157 */
158 int strglob(const char *zGlob, const char *z){
159 return sqlite3_strglob(zGlob, z)==0;
160 }
161
162 /*
163 ** Return true (non-zero) if zString matches any of the patterns in
164 ** the Glob. The value returned is actually a 1-based index of the pattern
165 ** that matched. Return 0 if none of the patterns match zString.
166 **
167
--- src/glob.c
+++ src/glob.c
@@ -138,29 +138,10 @@
138 z += i+1;
139 }
140 return p;
141 }
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143 /*
144 ** Return true (non-zero) if zString matches any of the patterns in
145 ** the Glob. The value returned is actually a 1-based index of the pattern
146 ** that matched. Return 0 if none of the patterns match zString.
147 **
148
+26 -5
--- src/graph.c
+++ src/graph.c
@@ -38,11 +38,11 @@
3838
char *zBgClr; /* Background Color */
3939
char zUuid[41]; /* Check-in for file ID */
4040
4141
GraphRow *pNext; /* Next row down in the list of all rows */
4242
GraphRow *pPrev; /* Previous row */
43
-
43
+
4444
int idx; /* Row index. First is 1. 0 used for "none" */
4545
int idxTop; /* Direct descendent highest up on the graph */
4646
GraphRow *pChild; /* Child immediately above this node */
4747
u8 isDup; /* True if this is duplicate of a prior entry */
4848
u8 isLeaf; /* True if this is a leaf node */
@@ -154,11 +154,11 @@
154154
** Return the canonical pointer for a given branch name.
155155
** Multiple calls to this routine with equivalent strings
156156
** will return the same pointer.
157157
**
158158
** The returned value is a pointer to a (readonly) string that
159
-** has the useful property that strings can be checked for
159
+** has the useful property that strings can be checked for
160160
** equality by comparing pointers.
161161
**
162162
** Note: also used for background color names.
163163
*/
164164
static char *persistBranchName(GraphContext *p, const char *zBranch){
@@ -214,11 +214,11 @@
214214
return pRow->idx;
215215
}
216216
217217
/*
218218
** Return the index of a rail currently not in use for any row between
219
-** top and bottom, inclusive.
219
+** top and bottom, inclusive.
220220
*/
221221
static int findFreeRail(
222222
GraphContext *p, /* The graph context */
223223
int top, int btm, /* Span of rows for which the rail is needed */
224224
u64 inUseMask, /* Mask or rails already in use */
@@ -379,12 +379,33 @@
379379
}
380380
}
381381
}
382382
}
383383
384
+ /* If the primary parent is in a different branch, but there are
385
+ ** other parents in the same branch, reorder the parents to make
386
+ ** the parent from the same branch the primary parent.
387
+ */
388
+ for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
389
+ if( pRow->isDup ) continue;
390
+ if( pRow->nParent<2 ) continue; /* Not a fork */
391
+ pParent = hashFind(p, pRow->aParent[0]);
392
+ if( pParent==0 ) continue; /* Parent off-screen */
393
+ if( pParent->zBranch==pRow->zBranch ) continue; /* Same branch */
394
+ for(i=1; i<pRow->nParent; i++){
395
+ pParent = hashFind(p, pRow->aParent[i]);
396
+ if( pParent && pParent->zBranch==pRow->zBranch ){
397
+ int t = pRow->aParent[0];
398
+ pRow->aParent[0] = pRow->aParent[i];
399
+ pRow->aParent[i] = t;
400
+ break;
401
+ }
402
+ }
403
+ }
404
+
384405
385
- /* Find the pChild pointer for each node.
406
+ /* Find the pChild pointer for each node.
386407
**
387408
** The pChild points to the node directly above on the same rail.
388409
** The pChild must be in the same branch. Leaf nodes have a NULL
389410
** pChild.
390411
**
@@ -533,11 +554,11 @@
533554
}
534555
}
535556
}
536557
537558
/*
538
- ** Insert merge rails from primaries to duplicates.
559
+ ** Insert merge rails from primaries to duplicates.
539560
*/
540561
if( hasDup ){
541562
int dupRail;
542563
int mxRail;
543564
find_max_rail(p);
544565
--- src/graph.c
+++ src/graph.c
@@ -38,11 +38,11 @@
38 char *zBgClr; /* Background Color */
39 char zUuid[41]; /* Check-in for file ID */
40
41 GraphRow *pNext; /* Next row down in the list of all rows */
42 GraphRow *pPrev; /* Previous row */
43
44 int idx; /* Row index. First is 1. 0 used for "none" */
45 int idxTop; /* Direct descendent highest up on the graph */
46 GraphRow *pChild; /* Child immediately above this node */
47 u8 isDup; /* True if this is duplicate of a prior entry */
48 u8 isLeaf; /* True if this is a leaf node */
@@ -154,11 +154,11 @@
154 ** Return the canonical pointer for a given branch name.
155 ** Multiple calls to this routine with equivalent strings
156 ** will return the same pointer.
157 **
158 ** The returned value is a pointer to a (readonly) string that
159 ** has the useful property that strings can be checked for
160 ** equality by comparing pointers.
161 **
162 ** Note: also used for background color names.
163 */
164 static char *persistBranchName(GraphContext *p, const char *zBranch){
@@ -214,11 +214,11 @@
214 return pRow->idx;
215 }
216
217 /*
218 ** Return the index of a rail currently not in use for any row between
219 ** top and bottom, inclusive.
220 */
221 static int findFreeRail(
222 GraphContext *p, /* The graph context */
223 int top, int btm, /* Span of rows for which the rail is needed */
224 u64 inUseMask, /* Mask or rails already in use */
@@ -379,12 +379,33 @@
379 }
380 }
381 }
382 }
383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
385 /* Find the pChild pointer for each node.
386 **
387 ** The pChild points to the node directly above on the same rail.
388 ** The pChild must be in the same branch. Leaf nodes have a NULL
389 ** pChild.
390 **
@@ -533,11 +554,11 @@
533 }
534 }
535 }
536
537 /*
538 ** Insert merge rails from primaries to duplicates.
539 */
540 if( hasDup ){
541 int dupRail;
542 int mxRail;
543 find_max_rail(p);
544
--- src/graph.c
+++ src/graph.c
@@ -38,11 +38,11 @@
38 char *zBgClr; /* Background Color */
39 char zUuid[41]; /* Check-in for file ID */
40
41 GraphRow *pNext; /* Next row down in the list of all rows */
42 GraphRow *pPrev; /* Previous row */
43
44 int idx; /* Row index. First is 1. 0 used for "none" */
45 int idxTop; /* Direct descendent highest up on the graph */
46 GraphRow *pChild; /* Child immediately above this node */
47 u8 isDup; /* True if this is duplicate of a prior entry */
48 u8 isLeaf; /* True if this is a leaf node */
@@ -154,11 +154,11 @@
154 ** Return the canonical pointer for a given branch name.
155 ** Multiple calls to this routine with equivalent strings
156 ** will return the same pointer.
157 **
158 ** The returned value is a pointer to a (readonly) string that
159 ** has the useful property that strings can be checked for
160 ** equality by comparing pointers.
161 **
162 ** Note: also used for background color names.
163 */
164 static char *persistBranchName(GraphContext *p, const char *zBranch){
@@ -214,11 +214,11 @@
214 return pRow->idx;
215 }
216
217 /*
218 ** Return the index of a rail currently not in use for any row between
219 ** top and bottom, inclusive.
220 */
221 static int findFreeRail(
222 GraphContext *p, /* The graph context */
223 int top, int btm, /* Span of rows for which the rail is needed */
224 u64 inUseMask, /* Mask or rails already in use */
@@ -379,12 +379,33 @@
379 }
380 }
381 }
382 }
383
384 /* If the primary parent is in a different branch, but there are
385 ** other parents in the same branch, reorder the parents to make
386 ** the parent from the same branch the primary parent.
387 */
388 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
389 if( pRow->isDup ) continue;
390 if( pRow->nParent<2 ) continue; /* Not a fork */
391 pParent = hashFind(p, pRow->aParent[0]);
392 if( pParent==0 ) continue; /* Parent off-screen */
393 if( pParent->zBranch==pRow->zBranch ) continue; /* Same branch */
394 for(i=1; i<pRow->nParent; i++){
395 pParent = hashFind(p, pRow->aParent[i]);
396 if( pParent && pParent->zBranch==pRow->zBranch ){
397 int t = pRow->aParent[0];
398 pRow->aParent[0] = pRow->aParent[i];
399 pRow->aParent[i] = t;
400 break;
401 }
402 }
403 }
404
405
406 /* Find the pChild pointer for each node.
407 **
408 ** The pChild points to the node directly above on the same rail.
409 ** The pChild must be in the same branch. Leaf nodes have a NULL
410 ** pChild.
411 **
@@ -533,11 +554,11 @@
554 }
555 }
556 }
557
558 /*
559 ** Insert merge rails from primaries to duplicates.
560 */
561 if( hasDup ){
562 int dupRail;
563 int mxRail;
564 find_max_rail(p);
565
+13 -8
--- src/http.c
+++ src/http.c
@@ -155,11 +155,11 @@
155155
blob_reset(&x);
156156
return ( c!='n' && c!='N' );
157157
}
158158
159159
/*
160
-** Get the HTTP Basic Authorization credentials from the user
160
+** Get the HTTP Basic Authorization credentials from the user
161161
** when 401 is received.
162162
*/
163163
char *prompt_for_httpauth_creds(void){
164164
Blob x;
165165
char *zUser;
@@ -205,11 +205,12 @@
205205
int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
206206
Blob login; /* The login card */
207207
Blob payload; /* The complete payload including login card */
208208
Blob hdr; /* The HTTP request header */
209209
int closeConnection; /* True to close the connection when done */
210
- int iLength; /* Length of the reply payload */
210
+ int iLength; /* Expected length of the reply payload */
211
+ int iRecvLen; /* Received length of the reply payload */
211212
int rc = 0; /* Result code */
212213
int iHttpVersion; /* Which version of HTTP protocol server uses */
213214
char *zLine; /* A single line of the reply header */
214215
int i; /* Loop counter */
215216
int isError = 0; /* True if the reply is an error message */
@@ -265,11 +266,11 @@
265266
transport_send(&g.url, &hdr);
266267
transport_send(&g.url, &payload);
267268
blob_reset(&hdr);
268269
blob_reset(&payload);
269270
transport_flip(&g.url);
270
-
271
+
271272
/*
272273
** Read and interpret the server reply
273274
*/
274275
closeConnection = 1;
275276
iLength = -1;
@@ -332,11 +333,11 @@
332333
for(i=9; zLine[i] && zLine[i]==' '; i++){}
333334
if( zLine[i]==0 ){
334335
fossil_warning("malformed redirect: %s", zLine);
335336
goto write_err;
336337
}
337
- j = strlen(zLine) - 1;
338
+ j = strlen(zLine) - 1;
338339
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
339340
j -= 4;
340341
zLine[j] = 0;
341342
}
342343
transport_close(&g.url);
@@ -348,11 +349,11 @@
348349
g.zHttpAuth = get_httpauth();
349350
return http_exchange(pSend, pReply, useLogin, maxRedirect);
350351
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
351352
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
352353
isCompressed = 0;
353
- }else if( fossil_strnicmp(&zLine[14],
354
+ }else if( fossil_strnicmp(&zLine[14],
354355
"application/x-fossil-uncompressed", -1)==0 ){
355356
isCompressed = 0;
356357
}else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
357358
isError = 1;
358359
}
@@ -370,11 +371,15 @@
370371
/*
371372
** Extract the reply payload that follows the header
372373
*/
373374
blob_zero(pReply);
374375
blob_resize(pReply, iLength);
375
- iLength = transport_receive(&g.url, blob_buffer(pReply), iLength);
376
+ iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength);
377
+ if( iRecvLen != iLength ){
378
+ fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength);
379
+ goto write_err;
380
+ }
376381
blob_resize(pReply, iLength);
377382
if( isError ){
378383
char *z;
379384
int i, j;
380385
z = blob_str(pReply);
@@ -406,12 +411,12 @@
406411
}else{
407412
transport_rewind(&g.url);
408413
}
409414
return 0;
410415
411
- /*
416
+ /*
412417
** Jump to here if an error is seen.
413418
*/
414419
write_err:
415420
transport_close(&g.url);
416
- return 1;
421
+ return 1;
417422
}
418423
--- src/http.c
+++ src/http.c
@@ -155,11 +155,11 @@
155 blob_reset(&x);
156 return ( c!='n' && c!='N' );
157 }
158
159 /*
160 ** Get the HTTP Basic Authorization credentials from the user
161 ** when 401 is received.
162 */
163 char *prompt_for_httpauth_creds(void){
164 Blob x;
165 char *zUser;
@@ -205,11 +205,12 @@
205 int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
206 Blob login; /* The login card */
207 Blob payload; /* The complete payload including login card */
208 Blob hdr; /* The HTTP request header */
209 int closeConnection; /* True to close the connection when done */
210 int iLength; /* Length of the reply payload */
 
211 int rc = 0; /* Result code */
212 int iHttpVersion; /* Which version of HTTP protocol server uses */
213 char *zLine; /* A single line of the reply header */
214 int i; /* Loop counter */
215 int isError = 0; /* True if the reply is an error message */
@@ -265,11 +266,11 @@
265 transport_send(&g.url, &hdr);
266 transport_send(&g.url, &payload);
267 blob_reset(&hdr);
268 blob_reset(&payload);
269 transport_flip(&g.url);
270
271 /*
272 ** Read and interpret the server reply
273 */
274 closeConnection = 1;
275 iLength = -1;
@@ -332,11 +333,11 @@
332 for(i=9; zLine[i] && zLine[i]==' '; i++){}
333 if( zLine[i]==0 ){
334 fossil_warning("malformed redirect: %s", zLine);
335 goto write_err;
336 }
337 j = strlen(zLine) - 1;
338 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
339 j -= 4;
340 zLine[j] = 0;
341 }
342 transport_close(&g.url);
@@ -348,11 +349,11 @@
348 g.zHttpAuth = get_httpauth();
349 return http_exchange(pSend, pReply, useLogin, maxRedirect);
350 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
351 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
352 isCompressed = 0;
353 }else if( fossil_strnicmp(&zLine[14],
354 "application/x-fossil-uncompressed", -1)==0 ){
355 isCompressed = 0;
356 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
357 isError = 1;
358 }
@@ -370,11 +371,15 @@
370 /*
371 ** Extract the reply payload that follows the header
372 */
373 blob_zero(pReply);
374 blob_resize(pReply, iLength);
375 iLength = transport_receive(&g.url, blob_buffer(pReply), iLength);
 
 
 
 
376 blob_resize(pReply, iLength);
377 if( isError ){
378 char *z;
379 int i, j;
380 z = blob_str(pReply);
@@ -406,12 +411,12 @@
406 }else{
407 transport_rewind(&g.url);
408 }
409 return 0;
410
411 /*
412 ** Jump to here if an error is seen.
413 */
414 write_err:
415 transport_close(&g.url);
416 return 1;
417 }
418
--- src/http.c
+++ src/http.c
@@ -155,11 +155,11 @@
155 blob_reset(&x);
156 return ( c!='n' && c!='N' );
157 }
158
159 /*
160 ** Get the HTTP Basic Authorization credentials from the user
161 ** when 401 is received.
162 */
163 char *prompt_for_httpauth_creds(void){
164 Blob x;
165 char *zUser;
@@ -205,11 +205,12 @@
205 int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
206 Blob login; /* The login card */
207 Blob payload; /* The complete payload including login card */
208 Blob hdr; /* The HTTP request header */
209 int closeConnection; /* True to close the connection when done */
210 int iLength; /* Expected length of the reply payload */
211 int iRecvLen; /* Received length of the reply payload */
212 int rc = 0; /* Result code */
213 int iHttpVersion; /* Which version of HTTP protocol server uses */
214 char *zLine; /* A single line of the reply header */
215 int i; /* Loop counter */
216 int isError = 0; /* True if the reply is an error message */
@@ -265,11 +266,11 @@
266 transport_send(&g.url, &hdr);
267 transport_send(&g.url, &payload);
268 blob_reset(&hdr);
269 blob_reset(&payload);
270 transport_flip(&g.url);
271
272 /*
273 ** Read and interpret the server reply
274 */
275 closeConnection = 1;
276 iLength = -1;
@@ -332,11 +333,11 @@
333 for(i=9; zLine[i] && zLine[i]==' '; i++){}
334 if( zLine[i]==0 ){
335 fossil_warning("malformed redirect: %s", zLine);
336 goto write_err;
337 }
338 j = strlen(zLine) - 1;
339 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
340 j -= 4;
341 zLine[j] = 0;
342 }
343 transport_close(&g.url);
@@ -348,11 +349,11 @@
349 g.zHttpAuth = get_httpauth();
350 return http_exchange(pSend, pReply, useLogin, maxRedirect);
351 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
352 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
353 isCompressed = 0;
354 }else if( fossil_strnicmp(&zLine[14],
355 "application/x-fossil-uncompressed", -1)==0 ){
356 isCompressed = 0;
357 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
358 isError = 1;
359 }
@@ -370,11 +371,15 @@
371 /*
372 ** Extract the reply payload that follows the header
373 */
374 blob_zero(pReply);
375 blob_resize(pReply, iLength);
376 iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength);
377 if( iRecvLen != iLength ){
378 fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength);
379 goto write_err;
380 }
381 blob_resize(pReply, iLength);
382 if( isError ){
383 char *z;
384 int i, j;
385 z = blob_str(pReply);
@@ -406,12 +411,12 @@
411 }else{
412 transport_rewind(&g.url);
413 }
414 return 0;
415
416 /*
417 ** Jump to here if an error is seen.
418 */
419 write_err:
420 transport_close(&g.url);
421 return 1;
422 }
423
+56 -46
--- src/http_socket.c
+++ src/http_socket.c
@@ -27,10 +27,13 @@
2727
*/
2828
2929
#include "config.h"
3030
#include "http_socket.h"
3131
#if defined(_WIN32)
32
+# if !defined(_WIN32_WINNT)
33
+# define _WIN32_WINNT 0x0501
34
+# endif
3235
# include <winsock2.h>
3336
# include <ws2tcpip.h>
3437
#else
3538
# include <netinet/in.h>
3639
# include <arpa/inet.h>
@@ -45,11 +48,10 @@
4548
** There can only be a single socket connection open at a time.
4649
** State information about that socket is stored in the following
4750
** local variables:
4851
*/
4952
static int socketIsInit = 0; /* True after global initialization */
50
-static int addrIsInit = 0; /* True once addr is initialized */
5153
#if defined(_WIN32)
5254
static WSADATA socketInfo; /* Windows socket initialize data */
5355
#endif
5456
static int iSocket = -1; /* The socket on which we talk to the server */
5557
static char *socketErrMsg = 0; /* Text of most recent socket error */
@@ -106,11 +108,10 @@
106108
WSACleanup();
107109
#endif
108110
socket_clear_errmsg();
109111
socketIsInit = 0;
110112
}
111
- addrIsInit = 0;
112113
}
113114
114115
/*
115116
** Close the currently open socket. If no socket is open, this routine
116117
** is a no-op.
@@ -134,54 +135,56 @@
134135
** pUrlDAta->port TCP/IP port to use. Ex: 80
135136
**
136137
** Return the number of errors.
137138
*/
138139
int socket_open(UrlData *pUrlData){
139
- static struct sockaddr_in addr; /* The server address */
140
+ int rc = 0;
141
+ struct addrinfo *ai = 0;
142
+ struct addrinfo *p;
143
+ struct addrinfo hints;
144
+ char zPort[30];
145
+ char zRemote[NI_MAXHOST];
140146
141147
socket_global_init();
142
- if( !addrIsInit ){
143
- memset(&addr, 0, sizeof(addr));
144
- addr.sin_family = AF_INET;
145
- addr.sin_port = htons(pUrlData->port);
146
- *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
147
- if( -1 == *(int*)&addr.sin_addr ){
148
-#ifndef FOSSIL_STATIC_LINK
149
- struct hostent *pHost;
150
- pHost = gethostbyname(pUrlData->name);
151
- if( pHost!=0 ){
152
- memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
153
- }else
154
-#endif
155
- {
156
- socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
157
- return 1;
158
- }
159
- }
160
- addrIsInit = 1;
161
-
162
- /* Set the Global.zIpAddr variable to the server we are talking to.
163
- ** This is used to populate the ipaddr column of the rcvfrom table,
164
- ** if any files are received from the server.
165
- */
166
- g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
167
- }
168
- iSocket = socket(AF_INET,SOCK_STREAM,0);
169
- if( iSocket<0 ){
170
- socket_set_errmsg("cannot create a socket");
171
- return 1;
172
- }
173
- if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
148
+ memset(&hints, 0, sizeof(struct addrinfo));
149
+ assert( iSocket<0 );
150
+ hints.ai_family = g.fIPv4 ? AF_INET : AF_UNSPEC;
151
+ hints.ai_socktype = SOCK_STREAM;
152
+ hints.ai_protocol = IPPROTO_TCP;
153
+ sqlite3_snprintf(sizeof(zPort),zPort,"%d", pUrlData->port);
154
+ rc = getaddrinfo(pUrlData->name, zPort, &hints, &ai);
155
+ if( rc ){
156
+ socket_set_errmsg("getaddrinfo() fails: %s", gai_strerror(rc));
157
+ goto end_socket_open;
158
+ }
159
+ for(p=ai; p; p=p->ai_next){
160
+ iSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
161
+ if( iSocket<0 ) continue;
162
+ if( connect(iSocket,p->ai_addr,p->ai_addrlen)<0 ){
163
+ socket_close();
164
+ continue;
165
+ }
166
+ rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
167
+ 0, 0, NI_NUMERICHOST);
168
+ if( rc ){
169
+ socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
170
+ goto end_socket_open;
171
+ }
172
+ g.zIpAddr = mprintf("%s", zRemote);
173
+ break;
174
+ }
175
+ if( p==0 ){
174176
socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
175177
pUrlData->port);
176
- socket_close();
177
- return 1;
178178
}
179179
#if !defined(_WIN32)
180180
signal(SIGPIPE, SIG_IGN);
181181
#endif
182
- return 0;
182
+end_socket_open:
183
+ if( rc && iSocket>=0 ) socket_close();
184
+ if( ai ) freeaddrinfo(ai);
185
+ return rc;
183186
}
184187
185188
/*
186189
** Send content out over the open socket connection.
187190
*/
@@ -220,15 +223,22 @@
220223
** so rcvfrom gets populated. For hostnames with more than one IP (or
221224
** if overridden in ~/.ssh/config) the rcvfrom may not match the host
222225
** to which we connect.
223226
*/
224227
void socket_ssh_resolve_addr(UrlData *pUrlData){
225
- struct hostent *pHost; /* Used to make best effort for rcvfrom */
226
- struct sockaddr_in addr;
227
-
228
- memset(&addr, 0, sizeof(addr));
229
- pHost = gethostbyname(pUrlData->name);
230
- if( pHost!=0 ){
231
- memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
232
- g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
228
+ struct addrinfo *ai = 0;
229
+ struct addrinfo hints;
230
+ char zRemote[NI_MAXHOST];
231
+ hints.ai_family = AF_UNSPEC;
232
+ hints.ai_socktype = SOCK_STREAM;
233
+ hints.ai_protocol = IPPROTO_TCP;
234
+ if( getaddrinfo(pUrlData->name, NULL, &hints, &ai)==0
235
+ && ai!=0
236
+ && getnameinfo(ai->ai_addr, ai->ai_addrlen, zRemote,
237
+ sizeof(zRemote), 0, 0, NI_NUMERICHOST)==0 ){
238
+ g.zIpAddr = mprintf("%s (%s)", zRemote, pUrlData->name);
239
+ }
240
+ if( ai ) freeaddrinfo(ai);
241
+ if( g.zIpAddr==0 ){
242
+ g.zIpAddr = mprintf("%s", pUrlData->name);
233243
}
234244
}
235245
--- src/http_socket.c
+++ src/http_socket.c
@@ -27,10 +27,13 @@
27 */
28
29 #include "config.h"
30 #include "http_socket.h"
31 #if defined(_WIN32)
 
 
 
32 # include <winsock2.h>
33 # include <ws2tcpip.h>
34 #else
35 # include <netinet/in.h>
36 # include <arpa/inet.h>
@@ -45,11 +48,10 @@
45 ** There can only be a single socket connection open at a time.
46 ** State information about that socket is stored in the following
47 ** local variables:
48 */
49 static int socketIsInit = 0; /* True after global initialization */
50 static int addrIsInit = 0; /* True once addr is initialized */
51 #if defined(_WIN32)
52 static WSADATA socketInfo; /* Windows socket initialize data */
53 #endif
54 static int iSocket = -1; /* The socket on which we talk to the server */
55 static char *socketErrMsg = 0; /* Text of most recent socket error */
@@ -106,11 +108,10 @@
106 WSACleanup();
107 #endif
108 socket_clear_errmsg();
109 socketIsInit = 0;
110 }
111 addrIsInit = 0;
112 }
113
114 /*
115 ** Close the currently open socket. If no socket is open, this routine
116 ** is a no-op.
@@ -134,54 +135,56 @@
134 ** pUrlDAta->port TCP/IP port to use. Ex: 80
135 **
136 ** Return the number of errors.
137 */
138 int socket_open(UrlData *pUrlData){
139 static struct sockaddr_in addr; /* The server address */
 
 
 
 
 
140
141 socket_global_init();
142 if( !addrIsInit ){
143 memset(&addr, 0, sizeof(addr));
144 addr.sin_family = AF_INET;
145 addr.sin_port = htons(pUrlData->port);
146 *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
147 if( -1 == *(int*)&addr.sin_addr ){
148 #ifndef FOSSIL_STATIC_LINK
149 struct hostent *pHost;
150 pHost = gethostbyname(pUrlData->name);
151 if( pHost!=0 ){
152 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
153 }else
154 #endif
155 {
156 socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
157 return 1;
158 }
159 }
160 addrIsInit = 1;
161
162 /* Set the Global.zIpAddr variable to the server we are talking to.
163 ** This is used to populate the ipaddr column of the rcvfrom table,
164 ** if any files are received from the server.
165 */
166 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
167 }
168 iSocket = socket(AF_INET,SOCK_STREAM,0);
169 if( iSocket<0 ){
170 socket_set_errmsg("cannot create a socket");
171 return 1;
172 }
173 if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
174 socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
175 pUrlData->port);
176 socket_close();
177 return 1;
178 }
179 #if !defined(_WIN32)
180 signal(SIGPIPE, SIG_IGN);
181 #endif
182 return 0;
 
 
 
183 }
184
185 /*
186 ** Send content out over the open socket connection.
187 */
@@ -220,15 +223,22 @@
220 ** so rcvfrom gets populated. For hostnames with more than one IP (or
221 ** if overridden in ~/.ssh/config) the rcvfrom may not match the host
222 ** to which we connect.
223 */
224 void socket_ssh_resolve_addr(UrlData *pUrlData){
225 struct hostent *pHost; /* Used to make best effort for rcvfrom */
226 struct sockaddr_in addr;
227
228 memset(&addr, 0, sizeof(addr));
229 pHost = gethostbyname(pUrlData->name);
230 if( pHost!=0 ){
231 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
232 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
 
 
 
 
 
 
 
233 }
234 }
235
--- src/http_socket.c
+++ src/http_socket.c
@@ -27,10 +27,13 @@
27 */
28
29 #include "config.h"
30 #include "http_socket.h"
31 #if defined(_WIN32)
32 # if !defined(_WIN32_WINNT)
33 # define _WIN32_WINNT 0x0501
34 # endif
35 # include <winsock2.h>
36 # include <ws2tcpip.h>
37 #else
38 # include <netinet/in.h>
39 # include <arpa/inet.h>
@@ -45,11 +48,10 @@
48 ** There can only be a single socket connection open at a time.
49 ** State information about that socket is stored in the following
50 ** local variables:
51 */
52 static int socketIsInit = 0; /* True after global initialization */
 
53 #if defined(_WIN32)
54 static WSADATA socketInfo; /* Windows socket initialize data */
55 #endif
56 static int iSocket = -1; /* The socket on which we talk to the server */
57 static char *socketErrMsg = 0; /* Text of most recent socket error */
@@ -106,11 +108,10 @@
108 WSACleanup();
109 #endif
110 socket_clear_errmsg();
111 socketIsInit = 0;
112 }
 
113 }
114
115 /*
116 ** Close the currently open socket. If no socket is open, this routine
117 ** is a no-op.
@@ -134,54 +135,56 @@
135 ** pUrlDAta->port TCP/IP port to use. Ex: 80
136 **
137 ** Return the number of errors.
138 */
139 int socket_open(UrlData *pUrlData){
140 int rc = 0;
141 struct addrinfo *ai = 0;
142 struct addrinfo *p;
143 struct addrinfo hints;
144 char zPort[30];
145 char zRemote[NI_MAXHOST];
146
147 socket_global_init();
148 memset(&hints, 0, sizeof(struct addrinfo));
149 assert( iSocket<0 );
150 hints.ai_family = g.fIPv4 ? AF_INET : AF_UNSPEC;
151 hints.ai_socktype = SOCK_STREAM;
152 hints.ai_protocol = IPPROTO_TCP;
153 sqlite3_snprintf(sizeof(zPort),zPort,"%d", pUrlData->port);
154 rc = getaddrinfo(pUrlData->name, zPort, &hints, &ai);
155 if( rc ){
156 socket_set_errmsg("getaddrinfo() fails: %s", gai_strerror(rc));
157 goto end_socket_open;
158 }
159 for(p=ai; p; p=p->ai_next){
160 iSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
161 if( iSocket<0 ) continue;
162 if( connect(iSocket,p->ai_addr,p->ai_addrlen)<0 ){
163 socket_close();
164 continue;
165 }
166 rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
167 0, 0, NI_NUMERICHOST);
168 if( rc ){
169 socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
170 goto end_socket_open;
171 }
172 g.zIpAddr = mprintf("%s", zRemote);
173 break;
174 }
175 if( p==0 ){
 
 
 
 
176 socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
177 pUrlData->port);
 
 
178 }
179 #if !defined(_WIN32)
180 signal(SIGPIPE, SIG_IGN);
181 #endif
182 end_socket_open:
183 if( rc && iSocket>=0 ) socket_close();
184 if( ai ) freeaddrinfo(ai);
185 return rc;
186 }
187
188 /*
189 ** Send content out over the open socket connection.
190 */
@@ -220,15 +223,22 @@
223 ** so rcvfrom gets populated. For hostnames with more than one IP (or
224 ** if overridden in ~/.ssh/config) the rcvfrom may not match the host
225 ** to which we connect.
226 */
227 void socket_ssh_resolve_addr(UrlData *pUrlData){
228 struct addrinfo *ai = 0;
229 struct addrinfo hints;
230 char zRemote[NI_MAXHOST];
231 hints.ai_family = AF_UNSPEC;
232 hints.ai_socktype = SOCK_STREAM;
233 hints.ai_protocol = IPPROTO_TCP;
234 if( getaddrinfo(pUrlData->name, NULL, &hints, &ai)==0
235 && ai!=0
236 && getnameinfo(ai->ai_addr, ai->ai_addrlen, zRemote,
237 sizeof(zRemote), 0, 0, NI_NUMERICHOST)==0 ){
238 g.zIpAddr = mprintf("%s (%s)", zRemote, pUrlData->name);
239 }
240 if( ai ) freeaddrinfo(ai);
241 if( g.zIpAddr==0 ){
242 g.zIpAddr = mprintf("%s", pUrlData->name);
243 }
244 }
245
--- src/http_transport.c
+++ src/http_transport.c
@@ -87,11 +87,11 @@
8787
8888
/*
8989
** SSH initialization of the transport layer
9090
*/
9191
int transport_ssh_open(UrlData *pUrlData){
92
- /* For SSH we need to create and run SSH fossil http
92
+ /* For SSH we need to create and run SSH fossil http
9393
** to talk to the remote machine.
9494
*/
9595
const char *zSsh; /* The base SSH command */
9696
Blob zCmd; /* The SSH command */
9797
char *zHost; /* The host name to contact */
9898
--- src/http_transport.c
+++ src/http_transport.c
@@ -87,11 +87,11 @@
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(UrlData *pUrlData){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98
--- src/http_transport.c
+++ src/http_transport.c
@@ -87,11 +87,11 @@
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(UrlData *pUrlData){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98
+2 -4
--- src/info.c
+++ src/info.c
@@ -198,13 +198,10 @@
198198
int verboseFlag = find_option("verbose","v",0)!=0;
199199
if( !verboseFlag ){
200200
verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
201201
}
202202
203
- /* We should be done with options.. */
204
- verify_all_options();
205
-
206203
if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
207204
db_open_config(0);
208205
db_open_repository(g.argv[2]);
209206
db_record_repository_filename(g.argv[2]);
210207
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
@@ -211,10 +208,11 @@
211208
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
212209
extraRepoInfo();
213210
return;
214211
}
215212
db_find_and_open_repository(0,0);
213
+ verify_all_options();
216214
if( g.argc==2 ){
217215
int vid;
218216
/* 012345678901234 */
219217
db_record_repository_filename(0);
220218
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
@@ -716,11 +714,11 @@
716714
" mperm,"
717715
" (SELECT uuid FROM blob WHERE rid=mlink.pid),"
718716
" (SELECT uuid FROM blob WHERE rid=mlink.fid),"
719717
" (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
720718
" FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
721
- " WHERE mlink.mid=%d"
719
+ " WHERE mlink.mid=%d AND NOT mlink.isaux"
722720
" AND (mlink.fid>0"
723721
" OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))"
724722
" ORDER BY name /*sort*/",
725723
rid, rid
726724
);
727725
--- src/info.c
+++ src/info.c
@@ -198,13 +198,10 @@
198 int verboseFlag = find_option("verbose","v",0)!=0;
199 if( !verboseFlag ){
200 verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
201 }
202
203 /* We should be done with options.. */
204 verify_all_options();
205
206 if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
207 db_open_config(0);
208 db_open_repository(g.argv[2]);
209 db_record_repository_filename(g.argv[2]);
210 fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
@@ -211,10 +208,11 @@
211 fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
212 extraRepoInfo();
213 return;
214 }
215 db_find_and_open_repository(0,0);
 
216 if( g.argc==2 ){
217 int vid;
218 /* 012345678901234 */
219 db_record_repository_filename(0);
220 fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
@@ -716,11 +714,11 @@
716 " mperm,"
717 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
718 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
719 " (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
720 " FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
721 " WHERE mlink.mid=%d"
722 " AND (mlink.fid>0"
723 " OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))"
724 " ORDER BY name /*sort*/",
725 rid, rid
726 );
727
--- src/info.c
+++ src/info.c
@@ -198,13 +198,10 @@
198 int verboseFlag = find_option("verbose","v",0)!=0;
199 if( !verboseFlag ){
200 verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
201 }
202
 
 
 
203 if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
204 db_open_config(0);
205 db_open_repository(g.argv[2]);
206 db_record_repository_filename(g.argv[2]);
207 fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
@@ -211,10 +208,11 @@
208 fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
209 extraRepoInfo();
210 return;
211 }
212 db_find_and_open_repository(0,0);
213 verify_all_options();
214 if( g.argc==2 ){
215 int vid;
216 /* 012345678901234 */
217 db_record_repository_filename(0);
218 fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
@@ -716,11 +714,11 @@
714 " mperm,"
715 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
716 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
717 " (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
718 " FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
719 " WHERE mlink.mid=%d AND NOT mlink.isaux"
720 " AND (mlink.fid>0"
721 " OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))"
722 " ORDER BY name /*sort*/",
723 rid, rid
724 );
725
--- src/json_branch.c
+++ src/json_branch.c
@@ -66,11 +66,11 @@
6666
cson_value * payV;
6767
cson_object * pay;
6868
cson_value * listV;
6969
cson_array * list;
7070
char const * range = NULL;
71
- int which = 0;
71
+ int branchListFlags = BRL_OPEN_ONLY;
7272
char * sawConversionError = NULL;
7373
Stmt q;
7474
if( !g.perm.Read ){
7575
json_set_err(FSL_JSON_E_DENIED,
7676
"Requires 'o' permissions.");
@@ -102,19 +102,19 @@
102102
}
103103
/* Normalize range values... */
104104
switch(*range){
105105
case 'c':
106106
range = "closed";
107
- which = -1;
107
+ branchListFlags = BRL_CLOSED_ONLY;
108108
break;
109109
case 'a':
110110
range = "all";
111
- which = 1;
111
+ branchListFlags = BRL_BOTH;
112112
break;
113113
default:
114114
range = "open";
115
- which = 0;
115
+ branchListFlags = BRL_OPEN_ONLY;
116116
break;
117117
};
118118
cson_object_set(pay,"range",json_new_string(range));
119119
120120
if( g.localOpen ){ /* add "current" property (branch name). */
@@ -128,11 +128,11 @@
128128
cson_object_set(pay,"current",json_new_string(zCurrent));
129129
}
130130
}
131131
132132
133
- branch_prepare_list_query(&q, which);
133
+ branch_prepare_list_query(&q, branchListFlags);
134134
cson_object_set(pay,"branches",listV);
135135
while((SQLITE_ROW==db_step(&q))){
136136
cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
137137
if(v){
138138
cson_array_append(list,v);
139139
--- src/json_branch.c
+++ src/json_branch.c
@@ -66,11 +66,11 @@
66 cson_value * payV;
67 cson_object * pay;
68 cson_value * listV;
69 cson_array * list;
70 char const * range = NULL;
71 int which = 0;
72 char * sawConversionError = NULL;
73 Stmt q;
74 if( !g.perm.Read ){
75 json_set_err(FSL_JSON_E_DENIED,
76 "Requires 'o' permissions.");
@@ -102,19 +102,19 @@
102 }
103 /* Normalize range values... */
104 switch(*range){
105 case 'c':
106 range = "closed";
107 which = -1;
108 break;
109 case 'a':
110 range = "all";
111 which = 1;
112 break;
113 default:
114 range = "open";
115 which = 0;
116 break;
117 };
118 cson_object_set(pay,"range",json_new_string(range));
119
120 if( g.localOpen ){ /* add "current" property (branch name). */
@@ -128,11 +128,11 @@
128 cson_object_set(pay,"current",json_new_string(zCurrent));
129 }
130 }
131
132
133 branch_prepare_list_query(&q, which);
134 cson_object_set(pay,"branches",listV);
135 while((SQLITE_ROW==db_step(&q))){
136 cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
137 if(v){
138 cson_array_append(list,v);
139
--- src/json_branch.c
+++ src/json_branch.c
@@ -66,11 +66,11 @@
66 cson_value * payV;
67 cson_object * pay;
68 cson_value * listV;
69 cson_array * list;
70 char const * range = NULL;
71 int branchListFlags = BRL_OPEN_ONLY;
72 char * sawConversionError = NULL;
73 Stmt q;
74 if( !g.perm.Read ){
75 json_set_err(FSL_JSON_E_DENIED,
76 "Requires 'o' permissions.");
@@ -102,19 +102,19 @@
102 }
103 /* Normalize range values... */
104 switch(*range){
105 case 'c':
106 range = "closed";
107 branchListFlags = BRL_CLOSED_ONLY;
108 break;
109 case 'a':
110 range = "all";
111 branchListFlags = BRL_BOTH;
112 break;
113 default:
114 range = "open";
115 branchListFlags = BRL_OPEN_ONLY;
116 break;
117 };
118 cson_object_set(pay,"range",json_new_string(range));
119
120 if( g.localOpen ){ /* add "current" property (branch name). */
@@ -128,11 +128,11 @@
128 cson_object_set(pay,"current",json_new_string(zCurrent));
129 }
130 }
131
132
133 branch_prepare_list_query(&q, branchListFlags);
134 cson_object_set(pay,"branches",listV);
135 while((SQLITE_ROW==db_step(&q))){
136 cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
137 if(v){
138 cson_array_append(list,v);
139
+5 -5
--- src/leaf.c
+++ src/leaf.c
@@ -27,15 +27,15 @@
2727
2828
2929
/*
3030
** Return true if the check-in with RID=rid is a leaf.
3131
**
32
-** A leaf has no children in the same branch.
32
+** A leaf has no children in the same branch.
3333
*/
3434
int is_a_leaf(int rid){
3535
int rc;
36
- static const char zSql[] =
36
+ static const char zSql[] =
3737
@ SELECT 1 FROM plink
3838
@ WHERE pid=%d
3939
@ AND coalesce((SELECT value FROM tagxref
4040
@ WHERE tagid=%d AND rid=plink.pid), 'trunk')
4141
@ =coalesce((SELECT value FROM tagxref
@@ -56,11 +56,11 @@
5656
** A non-branch child is one which is on the same branch as the parent.
5757
*/
5858
int count_nonbranch_children(int pid){
5959
int nNonBranch = 0;
6060
static Stmt q;
61
- static const char zSql[] =
61
+ static const char zSql[] =
6262
@ SELECT count(*) FROM plink
6363
@ WHERE pid=:pid AND isprim
6464
@ AND coalesce((SELECT value FROM tagxref
6565
@ WHERE tagid=%d AND rid=plink.pid), 'trunk')
6666
@ =coalesce((SELECT value FROM tagxref
@@ -75,11 +75,11 @@
7575
return nNonBranch;
7676
}
7777
7878
7979
/*
80
-** Recompute the entire LEAF table.
80
+** Recompute the entire LEAF table.
8181
**
8282
** This can be expensive (5 seconds or so) for a really large repository.
8383
** So it is only done for things like a rebuild.
8484
*/
8585
void leaf_rebuild(void){
@@ -159,11 +159,11 @@
159159
** Schedule a leaf check for "rid" and its parents.
160160
*/
161161
void leaf_eventually_check(int rid){
162162
static Stmt parentsOf;
163163
164
- db_static_prepare(&parentsOf,
164
+ db_static_prepare(&parentsOf,
165165
"SELECT pid FROM plink WHERE cid=:rid AND pid>0"
166166
);
167167
db_bind_int(&parentsOf, ":rid", rid);
168168
bag_insert(&needToCheck, rid);
169169
while( db_step(&parentsOf)==SQLITE_ROW ){
170170
--- src/leaf.c
+++ src/leaf.c
@@ -27,15 +27,15 @@
27
28
29 /*
30 ** Return true if the check-in with RID=rid is a leaf.
31 **
32 ** A leaf has no children in the same branch.
33 */
34 int is_a_leaf(int rid){
35 int rc;
36 static const char zSql[] =
37 @ SELECT 1 FROM plink
38 @ WHERE pid=%d
39 @ AND coalesce((SELECT value FROM tagxref
40 @ WHERE tagid=%d AND rid=plink.pid), 'trunk')
41 @ =coalesce((SELECT value FROM tagxref
@@ -56,11 +56,11 @@
56 ** A non-branch child is one which is on the same branch as the parent.
57 */
58 int count_nonbranch_children(int pid){
59 int nNonBranch = 0;
60 static Stmt q;
61 static const char zSql[] =
62 @ SELECT count(*) FROM plink
63 @ WHERE pid=:pid AND isprim
64 @ AND coalesce((SELECT value FROM tagxref
65 @ WHERE tagid=%d AND rid=plink.pid), 'trunk')
66 @ =coalesce((SELECT value FROM tagxref
@@ -75,11 +75,11 @@
75 return nNonBranch;
76 }
77
78
79 /*
80 ** Recompute the entire LEAF table.
81 **
82 ** This can be expensive (5 seconds or so) for a really large repository.
83 ** So it is only done for things like a rebuild.
84 */
85 void leaf_rebuild(void){
@@ -159,11 +159,11 @@
159 ** Schedule a leaf check for "rid" and its parents.
160 */
161 void leaf_eventually_check(int rid){
162 static Stmt parentsOf;
163
164 db_static_prepare(&parentsOf,
165 "SELECT pid FROM plink WHERE cid=:rid AND pid>0"
166 );
167 db_bind_int(&parentsOf, ":rid", rid);
168 bag_insert(&needToCheck, rid);
169 while( db_step(&parentsOf)==SQLITE_ROW ){
170
--- src/leaf.c
+++ src/leaf.c
@@ -27,15 +27,15 @@
27
28
29 /*
30 ** Return true if the check-in with RID=rid is a leaf.
31 **
32 ** A leaf has no children in the same branch.
33 */
34 int is_a_leaf(int rid){
35 int rc;
36 static const char zSql[] =
37 @ SELECT 1 FROM plink
38 @ WHERE pid=%d
39 @ AND coalesce((SELECT value FROM tagxref
40 @ WHERE tagid=%d AND rid=plink.pid), 'trunk')
41 @ =coalesce((SELECT value FROM tagxref
@@ -56,11 +56,11 @@
56 ** A non-branch child is one which is on the same branch as the parent.
57 */
58 int count_nonbranch_children(int pid){
59 int nNonBranch = 0;
60 static Stmt q;
61 static const char zSql[] =
62 @ SELECT count(*) FROM plink
63 @ WHERE pid=:pid AND isprim
64 @ AND coalesce((SELECT value FROM tagxref
65 @ WHERE tagid=%d AND rid=plink.pid), 'trunk')
66 @ =coalesce((SELECT value FROM tagxref
@@ -75,11 +75,11 @@
75 return nNonBranch;
76 }
77
78
79 /*
80 ** Recompute the entire LEAF table.
81 **
82 ** This can be expensive (5 seconds or so) for a really large repository.
83 ** So it is only done for things like a rebuild.
84 */
85 void leaf_rebuild(void){
@@ -159,11 +159,11 @@
159 ** Schedule a leaf check for "rid" and its parents.
160 */
161 void leaf_eventually_check(int rid){
162 static Stmt parentsOf;
163
164 db_static_prepare(&parentsOf,
165 "SELECT pid FROM plink WHERE cid=:rid AND pid>0"
166 );
167 db_bind_int(&parentsOf, ":rid", rid);
168 bag_insert(&needToCheck, rid);
169 while( db_step(&parentsOf)==SQLITE_ROW ){
170
+2 -1
--- src/login.c
+++ src/login.c
@@ -483,11 +483,11 @@
483483
zQS = "";
484484
}else if( zQS[0]!=0 ){
485485
zQS = mprintf("?%s", zQS);
486486
}
487487
cgi_redirectf("%s%s%s", g.zHttpsURL, P("PATH_INFO"), zQS);
488
- return;
488
+ return;
489489
}
490490
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
491491
constant_time_cmp_function, 0, 0);
492492
zUsername = P("u");
493493
zPasswd = P("p");
@@ -575,10 +575,11 @@
575575
login_set_user_cookie(zUsername, uid, NULL);
576576
redirect_to_g();
577577
}
578578
}
579579
style_header("Login/Logout");
580
+ style_adunit_config(ADUNIT_OFF);
580581
@ %s(zErrMsg)
581582
if( zGoto && P("anon")==0 ){
582583
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
583584
}
584585
form_begin(0, "%R/login");
585586
--- src/login.c
+++ src/login.c
@@ -483,11 +483,11 @@
483 zQS = "";
484 }else if( zQS[0]!=0 ){
485 zQS = mprintf("?%s", zQS);
486 }
487 cgi_redirectf("%s%s%s", g.zHttpsURL, P("PATH_INFO"), zQS);
488 return;
489 }
490 sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
491 constant_time_cmp_function, 0, 0);
492 zUsername = P("u");
493 zPasswd = P("p");
@@ -575,10 +575,11 @@
575 login_set_user_cookie(zUsername, uid, NULL);
576 redirect_to_g();
577 }
578 }
579 style_header("Login/Logout");
 
580 @ %s(zErrMsg)
581 if( zGoto && P("anon")==0 ){
582 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
583 }
584 form_begin(0, "%R/login");
585
--- src/login.c
+++ src/login.c
@@ -483,11 +483,11 @@
483 zQS = "";
484 }else if( zQS[0]!=0 ){
485 zQS = mprintf("?%s", zQS);
486 }
487 cgi_redirectf("%s%s%s", g.zHttpsURL, P("PATH_INFO"), zQS);
488 return;
489 }
490 sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
491 constant_time_cmp_function, 0, 0);
492 zUsername = P("u");
493 zPasswd = P("p");
@@ -575,10 +575,11 @@
575 login_set_user_cookie(zUsername, uid, NULL);
576 redirect_to_g();
577 }
578 }
579 style_header("Login/Logout");
580 style_adunit_config(ADUNIT_OFF);
581 @ %s(zErrMsg)
582 if( zGoto && P("anon")==0 ){
583 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
584 }
585 form_begin(0, "%R/login");
586
+79 -15
--- src/main.c
+++ src/main.c
@@ -143,16 +143,18 @@
143143
int fSqlTrace; /* True if --sqltrace flag is present */
144144
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
145145
int fSqlPrint; /* True if -sqlprint flag is present */
146146
int fQuiet; /* True if -quiet flag is present */
147147
int fHttpTrace; /* Trace outbound HTTP requests */
148
+ int fAnyTrace; /* Any kind of tracing */
148149
char *zHttpAuth; /* HTTP Authorization user:pass information */
149150
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
150151
int fSshTrace; /* Trace the SSH setup traffic */
151152
int fSshClient; /* HTTP client flags for SSH client */
152153
char *zSshCmd; /* SSH command string */
153154
int fNoSync; /* Do not do an autosync ever. --nosync */
155
+ int fIPv4; /* Use only IPv4, not IPv6. --ipv4 */
154156
char *zPath; /* Name of webpage being served */
155157
char *zExtra; /* Extra path information past the webpage name */
156158
char *zBaseURL; /* Full text of the URL being served */
157159
char *zHttpsURL; /* zBaseURL translated to https: */
158160
char *zTop; /* Parent directory of zPath */
@@ -657,15 +659,15 @@
657659
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
658660
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
659661
g.fSshClient = 0;
660662
g.zSshCmd = 0;
661663
if( g.fSqlTrace ) g.fSqlStats = 1;
662
- g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
663664
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
664665
#ifdef FOSSIL_ENABLE_TH1_HOOKS
665666
g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
666667
#endif
668
+ g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|g.fHttpTrace;
667669
g.zHttpAuth = 0;
668670
g.zLogin = find_option("user", "U", 1);
669671
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
670672
g.zErrlog = find_option("errorlog", 0, 1);
671673
fossil_init_flags_from_options();
@@ -1787,57 +1789,119 @@
17871789
g.cgiOutput = 1;
17881790
blob_read_from_file(&config, zFile);
17891791
while( blob_line(&config, &line) ){
17901792
if( !blob_token(&line, &key) ) continue;
17911793
if( blob_buffer(&key)[0]=='#' ) continue;
1792
- if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
1793
- g.fDebug = fossil_fopen(blob_str(&value), "ab");
1794
- blob_reset(&value);
1795
- continue;
1796
- }
1797
- if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
1798
- g.zErrlog = mprintf("%s", blob_str(&value));
1799
- continue;
1800
- }
1801
- if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
1802
- cgi_setenv("HOME", blob_str(&value));
1803
- blob_reset(&value);
1804
- continue;
1805
- }
18061794
if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
1795
+ /* repository: FILENAME
1796
+ **
1797
+ ** The name of the Fossil repository to be served via CGI. Most
1798
+ ** fossil CGI scripts have a single non-comment line that contains
1799
+ ** this one entry.
1800
+ */
18071801
blob_trim(&value);
18081802
db_open_repository(blob_str(&value));
18091803
blob_reset(&value);
18101804
continue;
18111805
}
18121806
if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){
1807
+ /* directory: DIRECTORY
1808
+ **
1809
+ ** If repository: is omitted, then terms of the PATH_INFO cgi parameter
1810
+ ** are appended to DIRECTORY looking for a repository (whose name ends
1811
+ ** in ".fossil") or a file in "files:".
1812
+ */
18131813
db_close(1);
18141814
g.zRepositoryName = mprintf("%s", blob_str(&value));
18151815
blob_reset(&value);
18161816
continue;
18171817
}
18181818
if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
1819
+ /* notfound: URL
1820
+ **
1821
+ ** If using directory: and no suitable repository or file is found,
1822
+ ** then redirect to URL.
1823
+ */
18191824
zNotFound = mprintf("%s", blob_str(&value));
18201825
blob_reset(&value);
18211826
continue;
18221827
}
18231828
if( blob_eq(&key, "localauth") ){
1829
+ /* localauth
1830
+ **
1831
+ ** Grant "administrator" privileges to users connecting with HTTP
1832
+ ** from IP address 127.0.0.1. Do not bother checking credentials.
1833
+ */
18241834
g.useLocalauth = 1;
18251835
continue;
18261836
}
18271837
if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
18281838
&& blob_token(&line, &value2) ){
1839
+ /* See the header comment on the redirect_web_page() function
1840
+ ** above for details. */
18291841
nRedirect++;
18301842
azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
18311843
azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
18321844
azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
18331845
blob_reset(&value);
18341846
blob_reset(&value2);
18351847
continue;
18361848
}
18371849
if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
1850
+ /* files: GLOBLIST
1851
+ **
1852
+ ** GLOBLIST is a comma-separated list of filename globs. For
1853
+ ** example: *.html,*.css,*.js
1854
+ **
1855
+ ** If the repository: line is omitted and then PATH_INFO is searched
1856
+ ** for files that match any of these GLOBs and if any such file is
1857
+ ** found it is returned verbatim. This feature allows "fossil server"
1858
+ ** to function as a primitive web-server delivering arbitrary content.
1859
+ */
18381860
pFileGlob = glob_create(blob_str(&value));
1861
+ blob_reset(&value);
1862
+ continue;
1863
+ }
1864
+ if( blob_eq(&key, "setenv:") && blob_token(&line, &value)
1865
+ && blob_token(&line, &value2) ){
1866
+ /* setenv: NAME VALUE
1867
+ **
1868
+ ** Sets environment variable NAME to VALUE
1869
+ */
1870
+ fossil_setenv(blob_str(&value), blob_str(&value2));
1871
+ blob_reset(&value);
1872
+ blob_reset(&value2);
1873
+ continue;
1874
+ }
1875
+ if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
1876
+ /* debug: FILENAME
1877
+ **
1878
+ ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
1879
+ ** into FILENAME.
1880
+ */
1881
+ g.fDebug = fossil_fopen(blob_str(&value), "ab");
1882
+ blob_reset(&value);
1883
+ continue;
1884
+ }
1885
+ if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
1886
+ /* errorlog: FILENAME
1887
+ **
1888
+ ** Causes messages from warnings, errors, and panics to be appended
1889
+ ** to FILENAME.
1890
+ */
1891
+ g.zErrlog = mprintf("%s", blob_str(&value));
1892
+ blob_reset(&value);
1893
+ continue;
1894
+ }
1895
+ if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
1896
+ /* HOME: VALUE
1897
+ **
1898
+ ** Set CGI parameter "HOME" to VALUE. This is legacy. Use
1899
+ ** setenv: instead.
1900
+ */
1901
+ cgi_setenv("HOME", blob_str(&value));
1902
+ blob_reset(&value);
18391903
continue;
18401904
}
18411905
}
18421906
blob_reset(&config);
18431907
if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
18441908
--- src/main.c
+++ src/main.c
@@ -143,16 +143,18 @@
143 int fSqlTrace; /* True if --sqltrace flag is present */
144 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
145 int fSqlPrint; /* True if -sqlprint flag is present */
146 int fQuiet; /* True if -quiet flag is present */
147 int fHttpTrace; /* Trace outbound HTTP requests */
 
148 char *zHttpAuth; /* HTTP Authorization user:pass information */
149 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
150 int fSshTrace; /* Trace the SSH setup traffic */
151 int fSshClient; /* HTTP client flags for SSH client */
152 char *zSshCmd; /* SSH command string */
153 int fNoSync; /* Do not do an autosync ever. --nosync */
 
154 char *zPath; /* Name of webpage being served */
155 char *zExtra; /* Extra path information past the webpage name */
156 char *zBaseURL; /* Full text of the URL being served */
157 char *zHttpsURL; /* zBaseURL translated to https: */
158 char *zTop; /* Parent directory of zPath */
@@ -657,15 +659,15 @@
657 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
658 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
659 g.fSshClient = 0;
660 g.zSshCmd = 0;
661 if( g.fSqlTrace ) g.fSqlStats = 1;
662 g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
663 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
664 #ifdef FOSSIL_ENABLE_TH1_HOOKS
665 g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
666 #endif
 
667 g.zHttpAuth = 0;
668 g.zLogin = find_option("user", "U", 1);
669 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
670 g.zErrlog = find_option("errorlog", 0, 1);
671 fossil_init_flags_from_options();
@@ -1787,57 +1789,119 @@
1787 g.cgiOutput = 1;
1788 blob_read_from_file(&config, zFile);
1789 while( blob_line(&config, &line) ){
1790 if( !blob_token(&line, &key) ) continue;
1791 if( blob_buffer(&key)[0]=='#' ) continue;
1792 if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
1793 g.fDebug = fossil_fopen(blob_str(&value), "ab");
1794 blob_reset(&value);
1795 continue;
1796 }
1797 if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
1798 g.zErrlog = mprintf("%s", blob_str(&value));
1799 continue;
1800 }
1801 if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
1802 cgi_setenv("HOME", blob_str(&value));
1803 blob_reset(&value);
1804 continue;
1805 }
1806 if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
 
 
 
 
 
 
1807 blob_trim(&value);
1808 db_open_repository(blob_str(&value));
1809 blob_reset(&value);
1810 continue;
1811 }
1812 if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){
 
 
 
 
 
 
1813 db_close(1);
1814 g.zRepositoryName = mprintf("%s", blob_str(&value));
1815 blob_reset(&value);
1816 continue;
1817 }
1818 if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
 
 
 
 
 
1819 zNotFound = mprintf("%s", blob_str(&value));
1820 blob_reset(&value);
1821 continue;
1822 }
1823 if( blob_eq(&key, "localauth") ){
 
 
 
 
 
1824 g.useLocalauth = 1;
1825 continue;
1826 }
1827 if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
1828 && blob_token(&line, &value2) ){
 
 
1829 nRedirect++;
1830 azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
1831 azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
1832 azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
1833 blob_reset(&value);
1834 blob_reset(&value2);
1835 continue;
1836 }
1837 if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
 
 
 
 
 
 
 
 
 
 
1838 pFileGlob = glob_create(blob_str(&value));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1839 continue;
1840 }
1841 }
1842 blob_reset(&config);
1843 if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
1844
--- src/main.c
+++ src/main.c
@@ -143,16 +143,18 @@
143 int fSqlTrace; /* True if --sqltrace flag is present */
144 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
145 int fSqlPrint; /* True if -sqlprint flag is present */
146 int fQuiet; /* True if -quiet flag is present */
147 int fHttpTrace; /* Trace outbound HTTP requests */
148 int fAnyTrace; /* Any kind of tracing */
149 char *zHttpAuth; /* HTTP Authorization user:pass information */
150 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
151 int fSshTrace; /* Trace the SSH setup traffic */
152 int fSshClient; /* HTTP client flags for SSH client */
153 char *zSshCmd; /* SSH command string */
154 int fNoSync; /* Do not do an autosync ever. --nosync */
155 int fIPv4; /* Use only IPv4, not IPv6. --ipv4 */
156 char *zPath; /* Name of webpage being served */
157 char *zExtra; /* Extra path information past the webpage name */
158 char *zBaseURL; /* Full text of the URL being served */
159 char *zHttpsURL; /* zBaseURL translated to https: */
160 char *zTop; /* Parent directory of zPath */
@@ -657,15 +659,15 @@
659 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
660 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
661 g.fSshClient = 0;
662 g.zSshCmd = 0;
663 if( g.fSqlTrace ) g.fSqlStats = 1;
 
664 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
665 #ifdef FOSSIL_ENABLE_TH1_HOOKS
666 g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
667 #endif
668 g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|g.fHttpTrace;
669 g.zHttpAuth = 0;
670 g.zLogin = find_option("user", "U", 1);
671 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
672 g.zErrlog = find_option("errorlog", 0, 1);
673 fossil_init_flags_from_options();
@@ -1787,57 +1789,119 @@
1789 g.cgiOutput = 1;
1790 blob_read_from_file(&config, zFile);
1791 while( blob_line(&config, &line) ){
1792 if( !blob_token(&line, &key) ) continue;
1793 if( blob_buffer(&key)[0]=='#' ) continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1794 if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
1795 /* repository: FILENAME
1796 **
1797 ** The name of the Fossil repository to be served via CGI. Most
1798 ** fossil CGI scripts have a single non-comment line that contains
1799 ** this one entry.
1800 */
1801 blob_trim(&value);
1802 db_open_repository(blob_str(&value));
1803 blob_reset(&value);
1804 continue;
1805 }
1806 if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){
1807 /* directory: DIRECTORY
1808 **
1809 ** If repository: is omitted, then terms of the PATH_INFO cgi parameter
1810 ** are appended to DIRECTORY looking for a repository (whose name ends
1811 ** in ".fossil") or a file in "files:".
1812 */
1813 db_close(1);
1814 g.zRepositoryName = mprintf("%s", blob_str(&value));
1815 blob_reset(&value);
1816 continue;
1817 }
1818 if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
1819 /* notfound: URL
1820 **
1821 ** If using directory: and no suitable repository or file is found,
1822 ** then redirect to URL.
1823 */
1824 zNotFound = mprintf("%s", blob_str(&value));
1825 blob_reset(&value);
1826 continue;
1827 }
1828 if( blob_eq(&key, "localauth") ){
1829 /* localauth
1830 **
1831 ** Grant "administrator" privileges to users connecting with HTTP
1832 ** from IP address 127.0.0.1. Do not bother checking credentials.
1833 */
1834 g.useLocalauth = 1;
1835 continue;
1836 }
1837 if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
1838 && blob_token(&line, &value2) ){
1839 /* See the header comment on the redirect_web_page() function
1840 ** above for details. */
1841 nRedirect++;
1842 azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
1843 azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
1844 azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
1845 blob_reset(&value);
1846 blob_reset(&value2);
1847 continue;
1848 }
1849 if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
1850 /* files: GLOBLIST
1851 **
1852 ** GLOBLIST is a comma-separated list of filename globs. For
1853 ** example: *.html,*.css,*.js
1854 **
1855 ** If the repository: line is omitted and then PATH_INFO is searched
1856 ** for files that match any of these GLOBs and if any such file is
1857 ** found it is returned verbatim. This feature allows "fossil server"
1858 ** to function as a primitive web-server delivering arbitrary content.
1859 */
1860 pFileGlob = glob_create(blob_str(&value));
1861 blob_reset(&value);
1862 continue;
1863 }
1864 if( blob_eq(&key, "setenv:") && blob_token(&line, &value)
1865 && blob_token(&line, &value2) ){
1866 /* setenv: NAME VALUE
1867 **
1868 ** Sets environment variable NAME to VALUE
1869 */
1870 fossil_setenv(blob_str(&value), blob_str(&value2));
1871 blob_reset(&value);
1872 blob_reset(&value2);
1873 continue;
1874 }
1875 if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
1876 /* debug: FILENAME
1877 **
1878 ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
1879 ** into FILENAME.
1880 */
1881 g.fDebug = fossil_fopen(blob_str(&value), "ab");
1882 blob_reset(&value);
1883 continue;
1884 }
1885 if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
1886 /* errorlog: FILENAME
1887 **
1888 ** Causes messages from warnings, errors, and panics to be appended
1889 ** to FILENAME.
1890 */
1891 g.zErrlog = mprintf("%s", blob_str(&value));
1892 blob_reset(&value);
1893 continue;
1894 }
1895 if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
1896 /* HOME: VALUE
1897 **
1898 ** Set CGI parameter "HOME" to VALUE. This is legacy. Use
1899 ** setenv: instead.
1900 */
1901 cgi_setenv("HOME", blob_str(&value));
1902 blob_reset(&value);
1903 continue;
1904 }
1905 }
1906 blob_reset(&config);
1907 if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
1908
+39 -2
--- src/main.mk
+++ src/main.mk
@@ -104,10 +104,11 @@
104104
$(SRCDIR)/sitemap.c \
105105
$(SRCDIR)/skins.c \
106106
$(SRCDIR)/sqlcmd.c \
107107
$(SRCDIR)/stash.c \
108108
$(SRCDIR)/stat.c \
109
+ $(SRCDIR)/statrep.c \
109110
$(SRCDIR)/style.c \
110111
$(SRCDIR)/sync.c \
111112
$(SRCDIR)/tag.c \
112113
$(SRCDIR)/tar.c \
113114
$(SRCDIR)/th_main.c \
@@ -131,11 +132,36 @@
131132
$(SRCDIR)/xfer.c \
132133
$(SRCDIR)/xfersetup.c \
133134
$(SRCDIR)/zip.c
134135
135136
EXTRA_FILES = \
136
- $(SRCDIR)/diff.tcl
137
+ $(SRCDIR)/../skins/black_and_white/css.txt \
138
+ $(SRCDIR)/../skins/black_and_white/footer.txt \
139
+ $(SRCDIR)/../skins/black_and_white/header.txt \
140
+ $(SRCDIR)/../skins/default/css.txt \
141
+ $(SRCDIR)/../skins/default/footer.txt \
142
+ $(SRCDIR)/../skins/default/header.txt \
143
+ $(SRCDIR)/../skins/eagle/css.txt \
144
+ $(SRCDIR)/../skins/eagle/footer.txt \
145
+ $(SRCDIR)/../skins/eagle/header.txt \
146
+ $(SRCDIR)/../skins/enhanced1/css.txt \
147
+ $(SRCDIR)/../skins/enhanced1/footer.txt \
148
+ $(SRCDIR)/../skins/enhanced1/header.txt \
149
+ $(SRCDIR)/../skins/etienne1/css.txt \
150
+ $(SRCDIR)/../skins/etienne1/footer.txt \
151
+ $(SRCDIR)/../skins/etienne1/header.txt \
152
+ $(SRCDIR)/../skins/khaki/css.txt \
153
+ $(SRCDIR)/../skins/khaki/footer.txt \
154
+ $(SRCDIR)/../skins/khaki/header.txt \
155
+ $(SRCDIR)/../skins/plain_gray/css.txt \
156
+ $(SRCDIR)/../skins/plain_gray/footer.txt \
157
+ $(SRCDIR)/../skins/plain_gray/header.txt \
158
+ $(SRCDIR)/../skins/rounded1/css.txt \
159
+ $(SRCDIR)/../skins/rounded1/footer.txt \
160
+ $(SRCDIR)/../skins/rounded1/header.txt \
161
+ $(SRCDIR)/diff.tcl \
162
+ $(SRCDIR)/markdown.md
137163
138164
TRANS_SRC = \
139165
$(OBJDIR)/add_.c \
140166
$(OBJDIR)/allrepo_.c \
141167
$(OBJDIR)/attach_.c \
@@ -226,10 +252,11 @@
226252
$(OBJDIR)/sitemap_.c \
227253
$(OBJDIR)/skins_.c \
228254
$(OBJDIR)/sqlcmd_.c \
229255
$(OBJDIR)/stash_.c \
230256
$(OBJDIR)/stat_.c \
257
+ $(OBJDIR)/statrep_.c \
231258
$(OBJDIR)/style_.c \
232259
$(OBJDIR)/sync_.c \
233260
$(OBJDIR)/tag_.c \
234261
$(OBJDIR)/tar_.c \
235262
$(OBJDIR)/th_main_.c \
@@ -345,10 +372,11 @@
345372
$(OBJDIR)/sitemap.o \
346373
$(OBJDIR)/skins.o \
347374
$(OBJDIR)/sqlcmd.o \
348375
$(OBJDIR)/stash.o \
349376
$(OBJDIR)/stat.o \
377
+ $(OBJDIR)/statrep.o \
350378
$(OBJDIR)/style.o \
351379
$(OBJDIR)/sync.o \
352380
$(OBJDIR)/tag.o \
353381
$(OBJDIR)/tar.o \
354382
$(OBJDIR)/th_main.o \
@@ -478,11 +506,11 @@
478506
479507
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
480508
$(OBJDIR)/mkindex $(TRANS_SRC) >$@
481509
482510
$(OBJDIR)/builtin_data.h: $(OBJDIR)/mkbuiltin $(EXTRA_FILES)
483
- $(OBJDIR)/mkbuiltin $(EXTRA_FILES) >$@
511
+ $(OBJDIR)/mkbuiltin --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
484512
485513
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
486514
$(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
487515
$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
488516
$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -573,10 +601,11 @@
573601
$(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
574602
$(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
575603
$(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
576604
$(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
577605
$(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
606
+ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
578607
$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
579608
$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
580609
$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
581610
$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
582611
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1340,10 +1369,18 @@
13401369
13411370
$(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
13421371
$(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
13431372
13441373
$(OBJDIR)/stat.h: $(OBJDIR)/headers
1374
+
1375
+$(OBJDIR)/statrep_.c: $(SRCDIR)/statrep.c $(OBJDIR)/translate
1376
+ $(OBJDIR)/translate $(SRCDIR)/statrep.c >$@
1377
+
1378
+$(OBJDIR)/statrep.o: $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
1379
+ $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c
1380
+
1381
+$(OBJDIR)/statrep.h: $(OBJDIR)/headers
13451382
13461383
$(OBJDIR)/style_.c: $(SRCDIR)/style.c $(OBJDIR)/translate
13471384
$(OBJDIR)/translate $(SRCDIR)/style.c >$@
13481385
13491386
$(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
13501387
--- src/main.mk
+++ src/main.mk
@@ -104,10 +104,11 @@
104 $(SRCDIR)/sitemap.c \
105 $(SRCDIR)/skins.c \
106 $(SRCDIR)/sqlcmd.c \
107 $(SRCDIR)/stash.c \
108 $(SRCDIR)/stat.c \
 
109 $(SRCDIR)/style.c \
110 $(SRCDIR)/sync.c \
111 $(SRCDIR)/tag.c \
112 $(SRCDIR)/tar.c \
113 $(SRCDIR)/th_main.c \
@@ -131,11 +132,36 @@
131 $(SRCDIR)/xfer.c \
132 $(SRCDIR)/xfersetup.c \
133 $(SRCDIR)/zip.c
134
135 EXTRA_FILES = \
136 $(SRCDIR)/diff.tcl
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
138 TRANS_SRC = \
139 $(OBJDIR)/add_.c \
140 $(OBJDIR)/allrepo_.c \
141 $(OBJDIR)/attach_.c \
@@ -226,10 +252,11 @@
226 $(OBJDIR)/sitemap_.c \
227 $(OBJDIR)/skins_.c \
228 $(OBJDIR)/sqlcmd_.c \
229 $(OBJDIR)/stash_.c \
230 $(OBJDIR)/stat_.c \
 
231 $(OBJDIR)/style_.c \
232 $(OBJDIR)/sync_.c \
233 $(OBJDIR)/tag_.c \
234 $(OBJDIR)/tar_.c \
235 $(OBJDIR)/th_main_.c \
@@ -345,10 +372,11 @@
345 $(OBJDIR)/sitemap.o \
346 $(OBJDIR)/skins.o \
347 $(OBJDIR)/sqlcmd.o \
348 $(OBJDIR)/stash.o \
349 $(OBJDIR)/stat.o \
 
350 $(OBJDIR)/style.o \
351 $(OBJDIR)/sync.o \
352 $(OBJDIR)/tag.o \
353 $(OBJDIR)/tar.o \
354 $(OBJDIR)/th_main.o \
@@ -478,11 +506,11 @@
478
479 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
480 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
481
482 $(OBJDIR)/builtin_data.h: $(OBJDIR)/mkbuiltin $(EXTRA_FILES)
483 $(OBJDIR)/mkbuiltin $(EXTRA_FILES) >$@
484
485 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
486 $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
487 $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
488 $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -573,10 +601,11 @@
573 $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
574 $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
575 $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
576 $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
577 $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
 
578 $(OBJDIR)/style_.c:$(OBJDIR)/style.h \
579 $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
580 $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
581 $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
582 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1340,10 +1369,18 @@
1340
1341 $(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
1342 $(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
1343
1344 $(OBJDIR)/stat.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1345
1346 $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(OBJDIR)/translate
1347 $(OBJDIR)/translate $(SRCDIR)/style.c >$@
1348
1349 $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
1350
--- src/main.mk
+++ src/main.mk
@@ -104,10 +104,11 @@
104 $(SRCDIR)/sitemap.c \
105 $(SRCDIR)/skins.c \
106 $(SRCDIR)/sqlcmd.c \
107 $(SRCDIR)/stash.c \
108 $(SRCDIR)/stat.c \
109 $(SRCDIR)/statrep.c \
110 $(SRCDIR)/style.c \
111 $(SRCDIR)/sync.c \
112 $(SRCDIR)/tag.c \
113 $(SRCDIR)/tar.c \
114 $(SRCDIR)/th_main.c \
@@ -131,11 +132,36 @@
132 $(SRCDIR)/xfer.c \
133 $(SRCDIR)/xfersetup.c \
134 $(SRCDIR)/zip.c
135
136 EXTRA_FILES = \
137 $(SRCDIR)/../skins/black_and_white/css.txt \
138 $(SRCDIR)/../skins/black_and_white/footer.txt \
139 $(SRCDIR)/../skins/black_and_white/header.txt \
140 $(SRCDIR)/../skins/default/css.txt \
141 $(SRCDIR)/../skins/default/footer.txt \
142 $(SRCDIR)/../skins/default/header.txt \
143 $(SRCDIR)/../skins/eagle/css.txt \
144 $(SRCDIR)/../skins/eagle/footer.txt \
145 $(SRCDIR)/../skins/eagle/header.txt \
146 $(SRCDIR)/../skins/enhanced1/css.txt \
147 $(SRCDIR)/../skins/enhanced1/footer.txt \
148 $(SRCDIR)/../skins/enhanced1/header.txt \
149 $(SRCDIR)/../skins/etienne1/css.txt \
150 $(SRCDIR)/../skins/etienne1/footer.txt \
151 $(SRCDIR)/../skins/etienne1/header.txt \
152 $(SRCDIR)/../skins/khaki/css.txt \
153 $(SRCDIR)/../skins/khaki/footer.txt \
154 $(SRCDIR)/../skins/khaki/header.txt \
155 $(SRCDIR)/../skins/plain_gray/css.txt \
156 $(SRCDIR)/../skins/plain_gray/footer.txt \
157 $(SRCDIR)/../skins/plain_gray/header.txt \
158 $(SRCDIR)/../skins/rounded1/css.txt \
159 $(SRCDIR)/../skins/rounded1/footer.txt \
160 $(SRCDIR)/../skins/rounded1/header.txt \
161 $(SRCDIR)/diff.tcl \
162 $(SRCDIR)/markdown.md
163
164 TRANS_SRC = \
165 $(OBJDIR)/add_.c \
166 $(OBJDIR)/allrepo_.c \
167 $(OBJDIR)/attach_.c \
@@ -226,10 +252,11 @@
252 $(OBJDIR)/sitemap_.c \
253 $(OBJDIR)/skins_.c \
254 $(OBJDIR)/sqlcmd_.c \
255 $(OBJDIR)/stash_.c \
256 $(OBJDIR)/stat_.c \
257 $(OBJDIR)/statrep_.c \
258 $(OBJDIR)/style_.c \
259 $(OBJDIR)/sync_.c \
260 $(OBJDIR)/tag_.c \
261 $(OBJDIR)/tar_.c \
262 $(OBJDIR)/th_main_.c \
@@ -345,10 +372,11 @@
372 $(OBJDIR)/sitemap.o \
373 $(OBJDIR)/skins.o \
374 $(OBJDIR)/sqlcmd.o \
375 $(OBJDIR)/stash.o \
376 $(OBJDIR)/stat.o \
377 $(OBJDIR)/statrep.o \
378 $(OBJDIR)/style.o \
379 $(OBJDIR)/sync.o \
380 $(OBJDIR)/tag.o \
381 $(OBJDIR)/tar.o \
382 $(OBJDIR)/th_main.o \
@@ -478,11 +506,11 @@
506
507 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
508 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
509
510 $(OBJDIR)/builtin_data.h: $(OBJDIR)/mkbuiltin $(EXTRA_FILES)
511 $(OBJDIR)/mkbuiltin --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
512
513 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
514 $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
515 $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
516 $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -573,10 +601,11 @@
601 $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
602 $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
603 $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
604 $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
605 $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
606 $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
607 $(OBJDIR)/style_.c:$(OBJDIR)/style.h \
608 $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
609 $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
610 $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
611 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1340,10 +1369,18 @@
1369
1370 $(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
1371 $(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
1372
1373 $(OBJDIR)/stat.h: $(OBJDIR)/headers
1374
1375 $(OBJDIR)/statrep_.c: $(SRCDIR)/statrep.c $(OBJDIR)/translate
1376 $(OBJDIR)/translate $(SRCDIR)/statrep.c >$@
1377
1378 $(OBJDIR)/statrep.o: $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
1379 $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c
1380
1381 $(OBJDIR)/statrep.h: $(OBJDIR)/headers
1382
1383 $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(OBJDIR)/translate
1384 $(OBJDIR)/translate $(SRCDIR)/style.c >$@
1385
1386 $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
1387
+59 -59
--- src/makeheaders.c
+++ src/makeheaders.c
@@ -112,19 +112,19 @@
112112
**
113113
** struct Xyzzy;
114114
**
115115
** Not every object has a forward declaration. If it does, thought, the
116116
** forward declaration will be contained in the zFwd field for C and
117
-** the zFwdCpp for C++. The zDecl field contains the complete
118
-** declaration text.
117
+** the zFwdCpp for C++. The zDecl field contains the complete
118
+** declaration text.
119119
*/
120120
typedef struct Decl Decl;
121121
struct Decl {
122122
char *zName; /* Name of the object being declared. The appearance
123123
** of this name is a source file triggers the declaration
124124
** to be added to the header for that file. */
125
- char *zFile; /* File from which extracted. */
125
+ const char *zFile; /* File from which extracted. */
126126
char *zIf; /* Surround the declaration with this #if */
127127
char *zFwd; /* A forward declaration. NULL if there is none. */
128128
char *zFwdCpp; /* Use this forward declaration for C++. */
129129
char *zDecl; /* A full declaration of this object */
130130
char *zExtra; /* Extra declaration text inserted into class objects */
@@ -163,11 +163,11 @@
163163
** in the output when using the -H option.)
164164
**
165165
** EXPORT scope The object is visible and usable everywhere.
166166
**
167167
** The DP_Flag is a temporary use flag that is used during processing to
168
-** prevent an infinite loop. It's use is localized.
168
+** prevent an infinite loop. It's use is localized.
169169
**
170170
** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
171171
** and are used to specify what type of declaration the object requires.
172172
*/
173173
#define DP_Forward 0x001 /* Has a forward declaration in this file */
@@ -201,11 +201,11 @@
201201
** Be careful not to confuse PS_Export with DP_Export or
202202
** PS_Local with DP_Local. Their names are similar, but the meanings
203203
** of these flags are very different.
204204
*/
205205
#define PS_Extern 0x000800 /* "extern" has been seen */
206
-#define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE"
206
+#define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE"
207207
** and "#endif" */
208208
#define PS_Export2 0x002000 /* If "EXPORT" seen */
209209
#define PS_Typedef 0x004000 /* If "typedef" has been seen */
210210
#define PS_Static 0x008000 /* If "static" has been seen */
211211
#define PS_Interface 0x010000 /* If within #if INTERFACE..#endif */
@@ -231,11 +231,11 @@
231231
#define TY_Union 0x04000000
232232
#define TY_Enumeration 0x08000000
233233
#define TY_Defunct 0x10000000 /* Used to erase a declaration */
234234
235235
/*
236
-** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
236
+** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
237237
** instances of the following structure.
238238
*/
239239
typedef struct Ifmacro Ifmacro;
240240
struct Ifmacro {
241241
int nLine; /* Line number where this macro occurs */
@@ -293,11 +293,11 @@
293293
int flags; /* One or more DP_, PS_ and/or TY_ flags */
294294
InFile *pNext; /* Next input file in the list of them all */
295295
IdentTable idTable; /* All identifiers in this input file */
296296
};
297297
298
-/*
298
+/*
299299
** An unbounded string is able to grow without limit. We use these
300300
** to construct large in-memory strings from lots of smaller components.
301301
*/
302302
typedef struct String String;
303303
struct String {
@@ -332,19 +332,19 @@
332332
** never to read a file that it generated itself.
333333
**
334334
** The "#undef INTERFACE" part is a hack to work around a name collision
335335
** in MSVC 2008.
336336
*/
337
-const char zTopLine[] =
337
+const char zTopLine[] =
338338
"/* \aThis file was automatically generated. Do not edit! */\n"
339339
"#undef INTERFACE\n";
340340
#define nTopLine (sizeof(zTopLine)-1)
341341
342342
/*
343343
** The name of the file currently being parsed.
344344
*/
345
-static char *zFilename;
345
+static const char *zFilename;
346346
347347
/*
348348
** The stack of #if macros for the file currently being parsed.
349349
*/
350350
static Ifmacro *ifStack = 0;
@@ -702,11 +702,11 @@
702702
struct stat sStat;
703703
FILE *pIn;
704704
char *zBuf;
705705
int n;
706706
707
- if( stat(zFilename,&sStat)!=0
707
+ if( stat(zFilename,&sStat)!=0
708708
#ifndef WIN32
709709
|| !S_ISREG(sStat.st_mode)
710710
#endif
711711
){
712712
return 0;
@@ -889,12 +889,12 @@
889889
}
890890
}
891891
}
892892
i++;
893893
}
894
- if( z[i] ){
895
- i += 2;
894
+ if( z[i] ){
895
+ i += 2;
896896
}else{
897897
isBlockComment = 0;
898898
fprintf(stderr,"%s:%d: Unterminated comment\n",
899899
zFilename, startLine);
900900
nErr++;
@@ -906,11 +906,11 @@
906906
pToken->eType = TT_Other;
907907
pToken->nText = 1 + (z[i+1]=='+');
908908
}
909909
break;
910910
911
- case '0':
911
+ case '0':
912912
if( z[i+1]=='x' || z[i+1]=='X' ){
913913
/* A hex constant */
914914
i += 2;
915915
while( isxdigit(z[i]) ){ i++; }
916916
}else{
@@ -963,11 +963,11 @@
963963
while( isalnum(z[i]) || z[i]=='_' ){ i++; };
964964
pToken->eType = TT_Id;
965965
pToken->nText = i - pIn->i;
966966
break;
967967
968
- case ':':
968
+ case ':':
969969
pToken->eType = TT_Other;
970970
pToken->nText = 1 + (z[i+1]==':');
971971
break;
972972
973973
case '=':
@@ -977,11 +977,11 @@
977977
case '-':
978978
case '*':
979979
case '%':
980980
case '^':
981981
case '&':
982
- case '|':
982
+ case '|':
983983
pToken->eType = TT_Other;
984984
pToken->nText = 1 + (z[i+1]=='=');
985985
break;
986986
987987
default:
@@ -1064,11 +1064,11 @@
10641064
}
10651065
}
10661066
/* NOT REACHED */
10671067
}
10681068
1069
-/*
1069
+/*
10701070
** This routine looks for identifiers (strings of contiguous alphanumeric
10711071
** characters) within a preprocessor directive and adds every such string
10721072
** found to the given identifier table
10731073
*/
10741074
static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
@@ -1157,11 +1157,11 @@
11571157
case TT_Id:
11581158
if( pTable ){
11591159
IdentTableInsert(pTable,pToken->zText,pToken->nText);
11601160
}
11611161
break;
1162
-
1162
+
11631163
case TT_Preprocessor:
11641164
if( pTable!=0 ){
11651165
FindIdentifiersInMacro(pToken,pTable);
11661166
}
11671167
break;
@@ -1263,11 +1263,11 @@
12631263
exit(1);
12641264
}
12651265
pList = TokenizeFile(zFile,&sTable);
12661266
for(p=pList; p; p=p->pNext){
12671267
int j;
1268
- switch( p->eType ){
1268
+ switch( p->eType ){
12691269
case TT_Space:
12701270
printf("%4d: Space\n",p->nLine);
12711271
break;
12721272
case TT_Id:
12731273
printf("%4d: Id %.*s\n",p->nLine,p->nText,p->zText);
@@ -1330,11 +1330,11 @@
13301330
needSpace = 1;
13311331
break;
13321332
13331333
default:
13341334
c = pFirst->zText[0];
1335
- printf("%s%.*s",
1335
+ printf("%s%.*s",
13361336
(needSpace && (c=='*' || c=='{')) ? " " : "",
13371337
pFirst->nText, pFirst->zText);
13381338
needSpace = pFirst->zText[0]==',';
13391339
break;
13401340
}
@@ -1371,13 +1371,13 @@
13711371
13721372
StringInit(&str);
13731373
pLast = pLast->pNext;
13741374
while( pFirst!=pLast ){
13751375
if( pFirst==pSkip ){ iSkip = nSkip; }
1376
- if( iSkip>0 ){
1376
+ if( iSkip>0 ){
13771377
iSkip--;
1378
- pFirst=pFirst->pNext;
1378
+ pFirst=pFirst->pNext;
13791379
continue;
13801380
}
13811381
switch( pFirst->eType ){
13821382
case TT_Preprocessor:
13831383
StringAppend(&str,"\n",1);
@@ -1384,13 +1384,13 @@
13841384
StringAppend(&str,pFirst->zText,pFirst->nText);
13851385
StringAppend(&str,"\n",1);
13861386
needSpace = 0;
13871387
break;
13881388
1389
- case TT_Id:
1389
+ case TT_Id:
13901390
switch( pFirst->zText[0] ){
1391
- case 'E':
1391
+ case 'E':
13921392
if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
13931393
skipOne = 1;
13941394
}
13951395
break;
13961396
case 'P':
@@ -1645,17 +1645,17 @@
16451645
pLast = pLast->pNext;
16461646
for(p=pFirst; p && p!=pLast; p=p->pNext){
16471647
if( p->eType==TT_Id ){
16481648
static IdentTable sReserved;
16491649
static int isInit = 0;
1650
- static char *aWords[] = { "char", "class",
1651
- "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
1650
+ static const char *aWords[] = { "char", "class",
1651
+ "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
16521652
"float", "int", "long",
16531653
"PRIVATE", "PROTECTED", "PUBLIC",
1654
- "register", "static", "struct", "sizeof", "signed", "typedef",
1654
+ "register", "static", "struct", "sizeof", "signed", "typedef",
16551655
"union", "volatile", "virtual", "void", };
1656
-
1656
+
16571657
if( !isInit ){
16581658
int i;
16591659
for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
16601660
IdentTableInsert(&sReserved,aWords[i],0);
16611661
}
@@ -1768,11 +1768,11 @@
17681768
pCode = pLast;
17691769
while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
17701770
pLast = pLast->pPrev;
17711771
}
17721772
if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
1773
- fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
1773
+ fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
17741774
zFilename, pFirst->nLine);
17751775
return 1;
17761776
}
17771777
if( flags & (PS_Interface|PS_Export|PS_Local) ){
17781778
fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
@@ -1849,11 +1849,11 @@
18491849
return 1;
18501850
}
18511851
18521852
#ifdef DEBUG
18531853
if( debugMask & PARSER ){
1854
- printf("**** Found inline routine: %.*s on line %d...\n",
1854
+ printf("**** Found inline routine: %.*s on line %d...\n",
18551855
pName->nText, pName->zText, pFirst->nLine);
18561856
PrintTokens(pFirst,pEnd);
18571857
printf("\n");
18581858
}
18591859
#endif
@@ -1888,11 +1888,11 @@
18881888
** to search for an occurrence of an ID followed immediately by '('.
18891889
** If found, we have a prototype. Otherwise we are dealing with a
18901890
** variable definition.
18911891
*/
18921892
static int isVariableDef(Token *pFirst, Token *pEnd){
1893
- if( pEnd && pEnd->zText[0]=='=' &&
1893
+ if( pEnd && pEnd->zText[0]=='=' &&
18941894
(pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
18951895
){
18961896
return 1;
18971897
}
18981898
while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
@@ -1949,11 +1949,11 @@
19491949
}
19501950
while( pFirst!=0 && pFirst->pNext!=pEnd &&
19511951
((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
19521952
|| (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
19531953
){
1954
- /* Lose the initial "static" or local from local variables.
1954
+ /* Lose the initial "static" or local from local variables.
19551955
** We'll prepend "extern" later. */
19561956
pFirst = pFirst->pNext;
19571957
isLocal = 1;
19581958
}
19591959
if( pFirst==0 || !isLocal ){
@@ -1962,11 +1962,11 @@
19621962
}else if( flags & PS_Method ){
19631963
/* Methods are declared by their class. Don't declare separately. */
19641964
return nErr;
19651965
}
19661966
isVar = (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
1967
- if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
1967
+ if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
19681968
&& (flags & PS_Extern)==0 ){
19691969
fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
19701970
zFilename, pFirst->nLine);
19711971
nErr++;
19721972
}
@@ -2095,11 +2095,11 @@
20952095
nCmd++;
20962096
}
20972097
20982098
if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
20992099
/*
2100
- ** Pop the if stack
2100
+ ** Pop the if stack
21012101
*/
21022102
pIf = ifStack;
21032103
if( pIf==0 ){
21042104
fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
21052105
return 1;
@@ -2106,11 +2106,11 @@
21062106
}
21072107
ifStack = pIf->pNext;
21082108
SafeFree(pIf);
21092109
}else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
21102110
/*
2111
- ** Record a #define if we are in PS_Interface or PS_Export
2111
+ ** Record a #define if we are in PS_Interface or PS_Export
21122112
*/
21132113
Decl *pDecl;
21142114
if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
21152115
zArg = &zCmd[6];
21162116
while( *zArg && isspace(*zArg) && *zArg!='\n' ){
@@ -2129,11 +2129,11 @@
21292129
}else if( flags & PS_Local ){
21302130
DeclSetProperty(pDecl,DP_Local);
21312131
}
21322132
}else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
21332133
/*
2134
- ** Record an #include if we are in PS_Interface or PS_Export
2134
+ ** Record an #include if we are in PS_Interface or PS_Export
21352135
*/
21362136
Include *pInclude;
21372137
char *zIf;
21382138
21392139
if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
@@ -2184,11 +2184,11 @@
21842184
PushIfMacro(0,0,0,pToken->nLine,PS_Local);
21852185
}else{
21862186
PushIfMacro(0,zArg,nArg,pToken->nLine,0);
21872187
}
21882188
}else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
2189
- /*
2189
+ /*
21902190
** Push an #ifdef.
21912191
*/
21922192
zArg = &zCmd[5];
21932193
while( *zArg && isspace(*zArg) && *zArg!='\n' ){
21942194
zArg++;
@@ -2207,11 +2207,11 @@
22072207
if( *zArg==0 || *zArg=='\n' ){ return 0; }
22082208
nArg = pToken->nText + (int)(pToken->zText - zArg);
22092209
PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
22102210
}else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
22112211
/*
2212
- ** Invert the #if on the top of the stack
2212
+ ** Invert the #if on the top of the stack
22132213
*/
22142214
if( ifStack==0 ){
22152215
fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
22162216
pToken->nLine);
22172217
return 1;
@@ -2224,33 +2224,33 @@
22242224
}else{
22252225
pIf->flags = 0;
22262226
}
22272227
}else{
22282228
/*
2229
- ** This directive can be safely ignored
2229
+ ** This directive can be safely ignored
22302230
*/
22312231
return 0;
22322232
}
22332233
2234
- /*
2235
- ** Recompute the preset flags
2234
+ /*
2235
+ ** Recompute the preset flags
22362236
*/
22372237
*pPresetFlags = 0;
22382238
for(pIf = ifStack; pIf; pIf=pIf->pNext){
22392239
*pPresetFlags |= pIf->flags;
22402240
}
2241
-
2241
+
22422242
return nErr;
22432243
}
22442244
22452245
/*
22462246
** Parse an entire file. Return the number of errors.
22472247
**
22482248
** pList is a list of tokens in the file. Whitespace tokens have been
22492249
** eliminated, and text with {...} has been collapsed into a
22502250
** single TT_Brace token.
2251
-**
2251
+**
22522252
** initFlags are a set of parse flags that should always be set for this
22532253
** file. For .c files this is normally 0. For .h files it is PS_Interface.
22542254
*/
22552255
static int ParseFile(Token *pList, int initFlags){
22562256
int nErr = 0;
@@ -2279,11 +2279,11 @@
22792279
pStart = 0;
22802280
flags = presetFlags;
22812281
break;
22822282
22832283
case '=':
2284
- if( pList->pPrev->nText==8
2284
+ if( pList->pPrev->nText==8
22852285
&& strncmp(pList->pPrev->zText,"operator",8)==0 ){
22862286
break;
22872287
}
22882288
nErr += ProcessDecl(pStart,pList,flags);
22892289
pStart = 0;
@@ -2471,11 +2471,11 @@
24712471
pDecl->zExtra = 0;
24722472
}
24732473
24742474
/*
24752475
** Reset the DP_Forward and DP_Declared flags on all Decl structures.
2476
-** Set both flags for anything that is tagged as local and isn't
2476
+** Set both flags for anything that is tagged as local and isn't
24772477
** in the file zFilename so that it won't be printing in other files.
24782478
*/
24792479
static void ResetDeclFlags(char *zFilename){
24802480
Decl *pDecl;
24812481
@@ -2574,11 +2574,11 @@
25742574
int flag;
25752575
int isCpp; /* True if generating C++ */
25762576
int doneTypedef = 0; /* True if a typedef has been done for this object */
25772577
25782578
/* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
2579
- /*
2579
+ /*
25802580
** For any object that has a forward declaration, go ahead and do the
25812581
** forward declaration first.
25822582
*/
25832583
isCpp = (pState->flags & DP_Cplusplus) != 0;
25842584
for(p=pDecl; p; p=p->pSameName){
@@ -2626,12 +2626,12 @@
26262626
** function on a recursive call with the same pDecl. Hence, recursive
26272627
** calls to this function (through ScanText()) can never change the
26282628
** value of DP_Flag out from under us.
26292629
*/
26302630
for(p=pDecl; p; p=p->pSameName){
2631
- if( !DeclHasProperty(p,DP_Declared)
2632
- && (p->zFwd==0 || needFullDecl)
2631
+ if( !DeclHasProperty(p,DP_Declared)
2632
+ && (p->zFwd==0 || needFullDecl)
26332633
&& p->zDecl!=0
26342634
){
26352635
DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
26362636
}else{
26372637
DeclClearProperty(p,DP_Flag);
@@ -2735,12 +2735,12 @@
27352735
** by sToken.
27362736
*/
27372737
pDecl = FindDecl(sToken.zText,sToken.nText);
27382738
if( pDecl==0 ) continue;
27392739
2740
- /*
2741
- ** If we get this far, we've found an identifier that has a
2740
+ /*
2741
+ ** If we get this far, we've found an identifier that has a
27422742
** declaration in the database. Now see if we the full declaration
27432743
** or just a forward declaration.
27442744
*/
27452745
GetNonspaceToken(&sIn,&sNext);
27462746
if( sNext.zText[0]=='*' ){
@@ -2770,12 +2770,12 @@
27702770
int progress;
27712771
27722772
do{
27732773
progress = 0;
27742774
for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
2775
- if( DeclHasProperty(pDecl,DP_Forward)
2776
- && !DeclHasProperty(pDecl,DP_Declared)
2775
+ if( DeclHasProperty(pDecl,DP_Forward)
2776
+ && !DeclHasProperty(pDecl,DP_Declared)
27772777
){
27782778
DeclareObject(pDecl,pState,1);
27792779
progress = 1;
27802780
assert( DeclHasProperty(pDecl,DP_Declared) );
27812781
}
@@ -2842,11 +2842,11 @@
28422842
nErr++;
28432843
}
28442844
}else if( report ){
28452845
fprintf(report,"unchanged\n");
28462846
}
2847
- SafeFree(zOldVersion);
2847
+ SafeFree(zOldVersion);
28482848
IdentTableReset(&includeTable);
28492849
StringReset(&outStr);
28502850
return nErr;
28512851
}
28522852
@@ -2878,11 +2878,11 @@
28782878
}
28792879
ChangeIfContext(0,&sState);
28802880
printf("%s",StringGet(&outStr));
28812881
IdentTableReset(&includeTable);
28822882
StringReset(&outStr);
2883
- return 0;
2883
+ return 0;
28842884
}
28852885
28862886
#ifdef DEBUG
28872887
/*
28882888
** Return the number of characters in the given string prior to the
@@ -3040,11 +3040,11 @@
30403040
int nSrc;
30413041
char *zSrc;
30423042
InFile *pFile;
30433043
int i;
30443044
3045
- /*
3045
+ /*
30463046
** Get the name of the input file to be scanned. The input file is
30473047
** everything before the first ':' or the whole file if no ':' is seen.
30483048
**
30493049
** Except, on windows, ignore any ':' that occurs as the second character
30503050
** since it might be part of the drive specifier. So really, the ":' has
@@ -3099,11 +3099,11 @@
30993099
}
31003100
}
31013101
31023102
/*
31033103
** If pFile->zSrc contains no 'c' or 'C' in its extension, it
3104
- ** must be a header file. In that case, we need to set the
3104
+ ** must be a header file. In that case, we need to set the
31053105
** PS_Interface flag.
31063106
*/
31073107
pFile->flags |= PS_Interface;
31083108
for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
31093109
if( zSrc[i]=='c' || zSrc[i]=='C' ){
@@ -3110,11 +3110,11 @@
31103110
pFile->flags &= ~PS_Interface;
31113111
break;
31123112
}
31133113
}
31143114
3115
- /* Done!
3115
+ /* Done!
31163116
*/
31173117
return pFile;
31183118
}
31193119
31203120
/* MS-Windows and MS-DOS both have the following serious OS bug: the
@@ -3162,11 +3162,11 @@
31623162
while( c!=EOF ){
31633163
while( c!=EOF && isspace(c) ){
31643164
if( c=='\n' ){
31653165
startOfLine = 1;
31663166
}
3167
- c = getc(in);
3167
+ c = getc(in);
31683168
if( startOfLine && c=='#' ){
31693169
while( c!=EOF && c!='\n' ){
31703170
c = getc(in);
31713171
}
31723172
}
@@ -3184,11 +3184,11 @@
31843184
if( nAlloc==0 ){
31853185
nAlloc = 100 + argc;
31863186
zNew = malloc( sizeof(char*) * nAlloc );
31873187
}else{
31883188
nAlloc *= 2;
3189
- zNew = realloc( zNew, sizeof(char*) * nAlloc );
3189
+ zNew = realloc( zNew, sizeof(char*) * nAlloc );
31903190
}
31913191
}
31923192
if( zNew ){
31933193
int j = nNew + index;
31943194
zNew[j] = malloc( n + 1 );
@@ -3254,11 +3254,11 @@
32543254
32553255
/*
32563256
** The following text contains a few simple #defines that we want
32573257
** to be available to every file.
32583258
*/
3259
-static char zInit[] =
3259
+static const char zInit[] =
32603260
"#define INTERFACE 0\n"
32613261
"#define EXPORT_INTERFACE 0\n"
32623262
"#define LOCAL_INTERFACE 0\n"
32633263
"#define EXPORT\n"
32643264
"#define LOCAL static\n"
32653265
--- src/makeheaders.c
+++ src/makeheaders.c
@@ -112,19 +112,19 @@
112 **
113 ** struct Xyzzy;
114 **
115 ** Not every object has a forward declaration. If it does, thought, the
116 ** forward declaration will be contained in the zFwd field for C and
117 ** the zFwdCpp for C++. The zDecl field contains the complete
118 ** declaration text.
119 */
120 typedef struct Decl Decl;
121 struct Decl {
122 char *zName; /* Name of the object being declared. The appearance
123 ** of this name is a source file triggers the declaration
124 ** to be added to the header for that file. */
125 char *zFile; /* File from which extracted. */
126 char *zIf; /* Surround the declaration with this #if */
127 char *zFwd; /* A forward declaration. NULL if there is none. */
128 char *zFwdCpp; /* Use this forward declaration for C++. */
129 char *zDecl; /* A full declaration of this object */
130 char *zExtra; /* Extra declaration text inserted into class objects */
@@ -163,11 +163,11 @@
163 ** in the output when using the -H option.)
164 **
165 ** EXPORT scope The object is visible and usable everywhere.
166 **
167 ** The DP_Flag is a temporary use flag that is used during processing to
168 ** prevent an infinite loop. It's use is localized.
169 **
170 ** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
171 ** and are used to specify what type of declaration the object requires.
172 */
173 #define DP_Forward 0x001 /* Has a forward declaration in this file */
@@ -201,11 +201,11 @@
201 ** Be careful not to confuse PS_Export with DP_Export or
202 ** PS_Local with DP_Local. Their names are similar, but the meanings
203 ** of these flags are very different.
204 */
205 #define PS_Extern 0x000800 /* "extern" has been seen */
206 #define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE"
207 ** and "#endif" */
208 #define PS_Export2 0x002000 /* If "EXPORT" seen */
209 #define PS_Typedef 0x004000 /* If "typedef" has been seen */
210 #define PS_Static 0x008000 /* If "static" has been seen */
211 #define PS_Interface 0x010000 /* If within #if INTERFACE..#endif */
@@ -231,11 +231,11 @@
231 #define TY_Union 0x04000000
232 #define TY_Enumeration 0x08000000
233 #define TY_Defunct 0x10000000 /* Used to erase a declaration */
234
235 /*
236 ** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
237 ** instances of the following structure.
238 */
239 typedef struct Ifmacro Ifmacro;
240 struct Ifmacro {
241 int nLine; /* Line number where this macro occurs */
@@ -293,11 +293,11 @@
293 int flags; /* One or more DP_, PS_ and/or TY_ flags */
294 InFile *pNext; /* Next input file in the list of them all */
295 IdentTable idTable; /* All identifiers in this input file */
296 };
297
298 /*
299 ** An unbounded string is able to grow without limit. We use these
300 ** to construct large in-memory strings from lots of smaller components.
301 */
302 typedef struct String String;
303 struct String {
@@ -332,19 +332,19 @@
332 ** never to read a file that it generated itself.
333 **
334 ** The "#undef INTERFACE" part is a hack to work around a name collision
335 ** in MSVC 2008.
336 */
337 const char zTopLine[] =
338 "/* \aThis file was automatically generated. Do not edit! */\n"
339 "#undef INTERFACE\n";
340 #define nTopLine (sizeof(zTopLine)-1)
341
342 /*
343 ** The name of the file currently being parsed.
344 */
345 static char *zFilename;
346
347 /*
348 ** The stack of #if macros for the file currently being parsed.
349 */
350 static Ifmacro *ifStack = 0;
@@ -702,11 +702,11 @@
702 struct stat sStat;
703 FILE *pIn;
704 char *zBuf;
705 int n;
706
707 if( stat(zFilename,&sStat)!=0
708 #ifndef WIN32
709 || !S_ISREG(sStat.st_mode)
710 #endif
711 ){
712 return 0;
@@ -889,12 +889,12 @@
889 }
890 }
891 }
892 i++;
893 }
894 if( z[i] ){
895 i += 2;
896 }else{
897 isBlockComment = 0;
898 fprintf(stderr,"%s:%d: Unterminated comment\n",
899 zFilename, startLine);
900 nErr++;
@@ -906,11 +906,11 @@
906 pToken->eType = TT_Other;
907 pToken->nText = 1 + (z[i+1]=='+');
908 }
909 break;
910
911 case '0':
912 if( z[i+1]=='x' || z[i+1]=='X' ){
913 /* A hex constant */
914 i += 2;
915 while( isxdigit(z[i]) ){ i++; }
916 }else{
@@ -963,11 +963,11 @@
963 while( isalnum(z[i]) || z[i]=='_' ){ i++; };
964 pToken->eType = TT_Id;
965 pToken->nText = i - pIn->i;
966 break;
967
968 case ':':
969 pToken->eType = TT_Other;
970 pToken->nText = 1 + (z[i+1]==':');
971 break;
972
973 case '=':
@@ -977,11 +977,11 @@
977 case '-':
978 case '*':
979 case '%':
980 case '^':
981 case '&':
982 case '|':
983 pToken->eType = TT_Other;
984 pToken->nText = 1 + (z[i+1]=='=');
985 break;
986
987 default:
@@ -1064,11 +1064,11 @@
1064 }
1065 }
1066 /* NOT REACHED */
1067 }
1068
1069 /*
1070 ** This routine looks for identifiers (strings of contiguous alphanumeric
1071 ** characters) within a preprocessor directive and adds every such string
1072 ** found to the given identifier table
1073 */
1074 static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
@@ -1157,11 +1157,11 @@
1157 case TT_Id:
1158 if( pTable ){
1159 IdentTableInsert(pTable,pToken->zText,pToken->nText);
1160 }
1161 break;
1162
1163 case TT_Preprocessor:
1164 if( pTable!=0 ){
1165 FindIdentifiersInMacro(pToken,pTable);
1166 }
1167 break;
@@ -1263,11 +1263,11 @@
1263 exit(1);
1264 }
1265 pList = TokenizeFile(zFile,&sTable);
1266 for(p=pList; p; p=p->pNext){
1267 int j;
1268 switch( p->eType ){
1269 case TT_Space:
1270 printf("%4d: Space\n",p->nLine);
1271 break;
1272 case TT_Id:
1273 printf("%4d: Id %.*s\n",p->nLine,p->nText,p->zText);
@@ -1330,11 +1330,11 @@
1330 needSpace = 1;
1331 break;
1332
1333 default:
1334 c = pFirst->zText[0];
1335 printf("%s%.*s",
1336 (needSpace && (c=='*' || c=='{')) ? " " : "",
1337 pFirst->nText, pFirst->zText);
1338 needSpace = pFirst->zText[0]==',';
1339 break;
1340 }
@@ -1371,13 +1371,13 @@
1371
1372 StringInit(&str);
1373 pLast = pLast->pNext;
1374 while( pFirst!=pLast ){
1375 if( pFirst==pSkip ){ iSkip = nSkip; }
1376 if( iSkip>0 ){
1377 iSkip--;
1378 pFirst=pFirst->pNext;
1379 continue;
1380 }
1381 switch( pFirst->eType ){
1382 case TT_Preprocessor:
1383 StringAppend(&str,"\n",1);
@@ -1384,13 +1384,13 @@
1384 StringAppend(&str,pFirst->zText,pFirst->nText);
1385 StringAppend(&str,"\n",1);
1386 needSpace = 0;
1387 break;
1388
1389 case TT_Id:
1390 switch( pFirst->zText[0] ){
1391 case 'E':
1392 if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
1393 skipOne = 1;
1394 }
1395 break;
1396 case 'P':
@@ -1645,17 +1645,17 @@
1645 pLast = pLast->pNext;
1646 for(p=pFirst; p && p!=pLast; p=p->pNext){
1647 if( p->eType==TT_Id ){
1648 static IdentTable sReserved;
1649 static int isInit = 0;
1650 static char *aWords[] = { "char", "class",
1651 "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
1652 "float", "int", "long",
1653 "PRIVATE", "PROTECTED", "PUBLIC",
1654 "register", "static", "struct", "sizeof", "signed", "typedef",
1655 "union", "volatile", "virtual", "void", };
1656
1657 if( !isInit ){
1658 int i;
1659 for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
1660 IdentTableInsert(&sReserved,aWords[i],0);
1661 }
@@ -1768,11 +1768,11 @@
1768 pCode = pLast;
1769 while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
1770 pLast = pLast->pPrev;
1771 }
1772 if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
1773 fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
1774 zFilename, pFirst->nLine);
1775 return 1;
1776 }
1777 if( flags & (PS_Interface|PS_Export|PS_Local) ){
1778 fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
@@ -1849,11 +1849,11 @@
1849 return 1;
1850 }
1851
1852 #ifdef DEBUG
1853 if( debugMask & PARSER ){
1854 printf("**** Found inline routine: %.*s on line %d...\n",
1855 pName->nText, pName->zText, pFirst->nLine);
1856 PrintTokens(pFirst,pEnd);
1857 printf("\n");
1858 }
1859 #endif
@@ -1888,11 +1888,11 @@
1888 ** to search for an occurrence of an ID followed immediately by '('.
1889 ** If found, we have a prototype. Otherwise we are dealing with a
1890 ** variable definition.
1891 */
1892 static int isVariableDef(Token *pFirst, Token *pEnd){
1893 if( pEnd && pEnd->zText[0]=='=' &&
1894 (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
1895 ){
1896 return 1;
1897 }
1898 while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
@@ -1949,11 +1949,11 @@
1949 }
1950 while( pFirst!=0 && pFirst->pNext!=pEnd &&
1951 ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
1952 || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
1953 ){
1954 /* Lose the initial "static" or local from local variables.
1955 ** We'll prepend "extern" later. */
1956 pFirst = pFirst->pNext;
1957 isLocal = 1;
1958 }
1959 if( pFirst==0 || !isLocal ){
@@ -1962,11 +1962,11 @@
1962 }else if( flags & PS_Method ){
1963 /* Methods are declared by their class. Don't declare separately. */
1964 return nErr;
1965 }
1966 isVar = (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
1967 if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
1968 && (flags & PS_Extern)==0 ){
1969 fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
1970 zFilename, pFirst->nLine);
1971 nErr++;
1972 }
@@ -2095,11 +2095,11 @@
2095 nCmd++;
2096 }
2097
2098 if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
2099 /*
2100 ** Pop the if stack
2101 */
2102 pIf = ifStack;
2103 if( pIf==0 ){
2104 fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
2105 return 1;
@@ -2106,11 +2106,11 @@
2106 }
2107 ifStack = pIf->pNext;
2108 SafeFree(pIf);
2109 }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
2110 /*
2111 ** Record a #define if we are in PS_Interface or PS_Export
2112 */
2113 Decl *pDecl;
2114 if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
2115 zArg = &zCmd[6];
2116 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
@@ -2129,11 +2129,11 @@
2129 }else if( flags & PS_Local ){
2130 DeclSetProperty(pDecl,DP_Local);
2131 }
2132 }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
2133 /*
2134 ** Record an #include if we are in PS_Interface or PS_Export
2135 */
2136 Include *pInclude;
2137 char *zIf;
2138
2139 if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
@@ -2184,11 +2184,11 @@
2184 PushIfMacro(0,0,0,pToken->nLine,PS_Local);
2185 }else{
2186 PushIfMacro(0,zArg,nArg,pToken->nLine,0);
2187 }
2188 }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
2189 /*
2190 ** Push an #ifdef.
2191 */
2192 zArg = &zCmd[5];
2193 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
2194 zArg++;
@@ -2207,11 +2207,11 @@
2207 if( *zArg==0 || *zArg=='\n' ){ return 0; }
2208 nArg = pToken->nText + (int)(pToken->zText - zArg);
2209 PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
2210 }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
2211 /*
2212 ** Invert the #if on the top of the stack
2213 */
2214 if( ifStack==0 ){
2215 fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
2216 pToken->nLine);
2217 return 1;
@@ -2224,33 +2224,33 @@
2224 }else{
2225 pIf->flags = 0;
2226 }
2227 }else{
2228 /*
2229 ** This directive can be safely ignored
2230 */
2231 return 0;
2232 }
2233
2234 /*
2235 ** Recompute the preset flags
2236 */
2237 *pPresetFlags = 0;
2238 for(pIf = ifStack; pIf; pIf=pIf->pNext){
2239 *pPresetFlags |= pIf->flags;
2240 }
2241
2242 return nErr;
2243 }
2244
2245 /*
2246 ** Parse an entire file. Return the number of errors.
2247 **
2248 ** pList is a list of tokens in the file. Whitespace tokens have been
2249 ** eliminated, and text with {...} has been collapsed into a
2250 ** single TT_Brace token.
2251 **
2252 ** initFlags are a set of parse flags that should always be set for this
2253 ** file. For .c files this is normally 0. For .h files it is PS_Interface.
2254 */
2255 static int ParseFile(Token *pList, int initFlags){
2256 int nErr = 0;
@@ -2279,11 +2279,11 @@
2279 pStart = 0;
2280 flags = presetFlags;
2281 break;
2282
2283 case '=':
2284 if( pList->pPrev->nText==8
2285 && strncmp(pList->pPrev->zText,"operator",8)==0 ){
2286 break;
2287 }
2288 nErr += ProcessDecl(pStart,pList,flags);
2289 pStart = 0;
@@ -2471,11 +2471,11 @@
2471 pDecl->zExtra = 0;
2472 }
2473
2474 /*
2475 ** Reset the DP_Forward and DP_Declared flags on all Decl structures.
2476 ** Set both flags for anything that is tagged as local and isn't
2477 ** in the file zFilename so that it won't be printing in other files.
2478 */
2479 static void ResetDeclFlags(char *zFilename){
2480 Decl *pDecl;
2481
@@ -2574,11 +2574,11 @@
2574 int flag;
2575 int isCpp; /* True if generating C++ */
2576 int doneTypedef = 0; /* True if a typedef has been done for this object */
2577
2578 /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
2579 /*
2580 ** For any object that has a forward declaration, go ahead and do the
2581 ** forward declaration first.
2582 */
2583 isCpp = (pState->flags & DP_Cplusplus) != 0;
2584 for(p=pDecl; p; p=p->pSameName){
@@ -2626,12 +2626,12 @@
2626 ** function on a recursive call with the same pDecl. Hence, recursive
2627 ** calls to this function (through ScanText()) can never change the
2628 ** value of DP_Flag out from under us.
2629 */
2630 for(p=pDecl; p; p=p->pSameName){
2631 if( !DeclHasProperty(p,DP_Declared)
2632 && (p->zFwd==0 || needFullDecl)
2633 && p->zDecl!=0
2634 ){
2635 DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
2636 }else{
2637 DeclClearProperty(p,DP_Flag);
@@ -2735,12 +2735,12 @@
2735 ** by sToken.
2736 */
2737 pDecl = FindDecl(sToken.zText,sToken.nText);
2738 if( pDecl==0 ) continue;
2739
2740 /*
2741 ** If we get this far, we've found an identifier that has a
2742 ** declaration in the database. Now see if we the full declaration
2743 ** or just a forward declaration.
2744 */
2745 GetNonspaceToken(&sIn,&sNext);
2746 if( sNext.zText[0]=='*' ){
@@ -2770,12 +2770,12 @@
2770 int progress;
2771
2772 do{
2773 progress = 0;
2774 for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
2775 if( DeclHasProperty(pDecl,DP_Forward)
2776 && !DeclHasProperty(pDecl,DP_Declared)
2777 ){
2778 DeclareObject(pDecl,pState,1);
2779 progress = 1;
2780 assert( DeclHasProperty(pDecl,DP_Declared) );
2781 }
@@ -2842,11 +2842,11 @@
2842 nErr++;
2843 }
2844 }else if( report ){
2845 fprintf(report,"unchanged\n");
2846 }
2847 SafeFree(zOldVersion);
2848 IdentTableReset(&includeTable);
2849 StringReset(&outStr);
2850 return nErr;
2851 }
2852
@@ -2878,11 +2878,11 @@
2878 }
2879 ChangeIfContext(0,&sState);
2880 printf("%s",StringGet(&outStr));
2881 IdentTableReset(&includeTable);
2882 StringReset(&outStr);
2883 return 0;
2884 }
2885
2886 #ifdef DEBUG
2887 /*
2888 ** Return the number of characters in the given string prior to the
@@ -3040,11 +3040,11 @@
3040 int nSrc;
3041 char *zSrc;
3042 InFile *pFile;
3043 int i;
3044
3045 /*
3046 ** Get the name of the input file to be scanned. The input file is
3047 ** everything before the first ':' or the whole file if no ':' is seen.
3048 **
3049 ** Except, on windows, ignore any ':' that occurs as the second character
3050 ** since it might be part of the drive specifier. So really, the ":' has
@@ -3099,11 +3099,11 @@
3099 }
3100 }
3101
3102 /*
3103 ** If pFile->zSrc contains no 'c' or 'C' in its extension, it
3104 ** must be a header file. In that case, we need to set the
3105 ** PS_Interface flag.
3106 */
3107 pFile->flags |= PS_Interface;
3108 for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
3109 if( zSrc[i]=='c' || zSrc[i]=='C' ){
@@ -3110,11 +3110,11 @@
3110 pFile->flags &= ~PS_Interface;
3111 break;
3112 }
3113 }
3114
3115 /* Done!
3116 */
3117 return pFile;
3118 }
3119
3120 /* MS-Windows and MS-DOS both have the following serious OS bug: the
@@ -3162,11 +3162,11 @@
3162 while( c!=EOF ){
3163 while( c!=EOF && isspace(c) ){
3164 if( c=='\n' ){
3165 startOfLine = 1;
3166 }
3167 c = getc(in);
3168 if( startOfLine && c=='#' ){
3169 while( c!=EOF && c!='\n' ){
3170 c = getc(in);
3171 }
3172 }
@@ -3184,11 +3184,11 @@
3184 if( nAlloc==0 ){
3185 nAlloc = 100 + argc;
3186 zNew = malloc( sizeof(char*) * nAlloc );
3187 }else{
3188 nAlloc *= 2;
3189 zNew = realloc( zNew, sizeof(char*) * nAlloc );
3190 }
3191 }
3192 if( zNew ){
3193 int j = nNew + index;
3194 zNew[j] = malloc( n + 1 );
@@ -3254,11 +3254,11 @@
3254
3255 /*
3256 ** The following text contains a few simple #defines that we want
3257 ** to be available to every file.
3258 */
3259 static char zInit[] =
3260 "#define INTERFACE 0\n"
3261 "#define EXPORT_INTERFACE 0\n"
3262 "#define LOCAL_INTERFACE 0\n"
3263 "#define EXPORT\n"
3264 "#define LOCAL static\n"
3265
--- src/makeheaders.c
+++ src/makeheaders.c
@@ -112,19 +112,19 @@
112 **
113 ** struct Xyzzy;
114 **
115 ** Not every object has a forward declaration. If it does, thought, the
116 ** forward declaration will be contained in the zFwd field for C and
117 ** the zFwdCpp for C++. The zDecl field contains the complete
118 ** declaration text.
119 */
120 typedef struct Decl Decl;
121 struct Decl {
122 char *zName; /* Name of the object being declared. The appearance
123 ** of this name is a source file triggers the declaration
124 ** to be added to the header for that file. */
125 const char *zFile; /* File from which extracted. */
126 char *zIf; /* Surround the declaration with this #if */
127 char *zFwd; /* A forward declaration. NULL if there is none. */
128 char *zFwdCpp; /* Use this forward declaration for C++. */
129 char *zDecl; /* A full declaration of this object */
130 char *zExtra; /* Extra declaration text inserted into class objects */
@@ -163,11 +163,11 @@
163 ** in the output when using the -H option.)
164 **
165 ** EXPORT scope The object is visible and usable everywhere.
166 **
167 ** The DP_Flag is a temporary use flag that is used during processing to
168 ** prevent an infinite loop. It's use is localized.
169 **
170 ** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
171 ** and are used to specify what type of declaration the object requires.
172 */
173 #define DP_Forward 0x001 /* Has a forward declaration in this file */
@@ -201,11 +201,11 @@
201 ** Be careful not to confuse PS_Export with DP_Export or
202 ** PS_Local with DP_Local. Their names are similar, but the meanings
203 ** of these flags are very different.
204 */
205 #define PS_Extern 0x000800 /* "extern" has been seen */
206 #define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE"
207 ** and "#endif" */
208 #define PS_Export2 0x002000 /* If "EXPORT" seen */
209 #define PS_Typedef 0x004000 /* If "typedef" has been seen */
210 #define PS_Static 0x008000 /* If "static" has been seen */
211 #define PS_Interface 0x010000 /* If within #if INTERFACE..#endif */
@@ -231,11 +231,11 @@
231 #define TY_Union 0x04000000
232 #define TY_Enumeration 0x08000000
233 #define TY_Defunct 0x10000000 /* Used to erase a declaration */
234
235 /*
236 ** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
237 ** instances of the following structure.
238 */
239 typedef struct Ifmacro Ifmacro;
240 struct Ifmacro {
241 int nLine; /* Line number where this macro occurs */
@@ -293,11 +293,11 @@
293 int flags; /* One or more DP_, PS_ and/or TY_ flags */
294 InFile *pNext; /* Next input file in the list of them all */
295 IdentTable idTable; /* All identifiers in this input file */
296 };
297
298 /*
299 ** An unbounded string is able to grow without limit. We use these
300 ** to construct large in-memory strings from lots of smaller components.
301 */
302 typedef struct String String;
303 struct String {
@@ -332,19 +332,19 @@
332 ** never to read a file that it generated itself.
333 **
334 ** The "#undef INTERFACE" part is a hack to work around a name collision
335 ** in MSVC 2008.
336 */
337 const char zTopLine[] =
338 "/* \aThis file was automatically generated. Do not edit! */\n"
339 "#undef INTERFACE\n";
340 #define nTopLine (sizeof(zTopLine)-1)
341
342 /*
343 ** The name of the file currently being parsed.
344 */
345 static const char *zFilename;
346
347 /*
348 ** The stack of #if macros for the file currently being parsed.
349 */
350 static Ifmacro *ifStack = 0;
@@ -702,11 +702,11 @@
702 struct stat sStat;
703 FILE *pIn;
704 char *zBuf;
705 int n;
706
707 if( stat(zFilename,&sStat)!=0
708 #ifndef WIN32
709 || !S_ISREG(sStat.st_mode)
710 #endif
711 ){
712 return 0;
@@ -889,12 +889,12 @@
889 }
890 }
891 }
892 i++;
893 }
894 if( z[i] ){
895 i += 2;
896 }else{
897 isBlockComment = 0;
898 fprintf(stderr,"%s:%d: Unterminated comment\n",
899 zFilename, startLine);
900 nErr++;
@@ -906,11 +906,11 @@
906 pToken->eType = TT_Other;
907 pToken->nText = 1 + (z[i+1]=='+');
908 }
909 break;
910
911 case '0':
912 if( z[i+1]=='x' || z[i+1]=='X' ){
913 /* A hex constant */
914 i += 2;
915 while( isxdigit(z[i]) ){ i++; }
916 }else{
@@ -963,11 +963,11 @@
963 while( isalnum(z[i]) || z[i]=='_' ){ i++; };
964 pToken->eType = TT_Id;
965 pToken->nText = i - pIn->i;
966 break;
967
968 case ':':
969 pToken->eType = TT_Other;
970 pToken->nText = 1 + (z[i+1]==':');
971 break;
972
973 case '=':
@@ -977,11 +977,11 @@
977 case '-':
978 case '*':
979 case '%':
980 case '^':
981 case '&':
982 case '|':
983 pToken->eType = TT_Other;
984 pToken->nText = 1 + (z[i+1]=='=');
985 break;
986
987 default:
@@ -1064,11 +1064,11 @@
1064 }
1065 }
1066 /* NOT REACHED */
1067 }
1068
1069 /*
1070 ** This routine looks for identifiers (strings of contiguous alphanumeric
1071 ** characters) within a preprocessor directive and adds every such string
1072 ** found to the given identifier table
1073 */
1074 static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
@@ -1157,11 +1157,11 @@
1157 case TT_Id:
1158 if( pTable ){
1159 IdentTableInsert(pTable,pToken->zText,pToken->nText);
1160 }
1161 break;
1162
1163 case TT_Preprocessor:
1164 if( pTable!=0 ){
1165 FindIdentifiersInMacro(pToken,pTable);
1166 }
1167 break;
@@ -1263,11 +1263,11 @@
1263 exit(1);
1264 }
1265 pList = TokenizeFile(zFile,&sTable);
1266 for(p=pList; p; p=p->pNext){
1267 int j;
1268 switch( p->eType ){
1269 case TT_Space:
1270 printf("%4d: Space\n",p->nLine);
1271 break;
1272 case TT_Id:
1273 printf("%4d: Id %.*s\n",p->nLine,p->nText,p->zText);
@@ -1330,11 +1330,11 @@
1330 needSpace = 1;
1331 break;
1332
1333 default:
1334 c = pFirst->zText[0];
1335 printf("%s%.*s",
1336 (needSpace && (c=='*' || c=='{')) ? " " : "",
1337 pFirst->nText, pFirst->zText);
1338 needSpace = pFirst->zText[0]==',';
1339 break;
1340 }
@@ -1371,13 +1371,13 @@
1371
1372 StringInit(&str);
1373 pLast = pLast->pNext;
1374 while( pFirst!=pLast ){
1375 if( pFirst==pSkip ){ iSkip = nSkip; }
1376 if( iSkip>0 ){
1377 iSkip--;
1378 pFirst=pFirst->pNext;
1379 continue;
1380 }
1381 switch( pFirst->eType ){
1382 case TT_Preprocessor:
1383 StringAppend(&str,"\n",1);
@@ -1384,13 +1384,13 @@
1384 StringAppend(&str,pFirst->zText,pFirst->nText);
1385 StringAppend(&str,"\n",1);
1386 needSpace = 0;
1387 break;
1388
1389 case TT_Id:
1390 switch( pFirst->zText[0] ){
1391 case 'E':
1392 if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
1393 skipOne = 1;
1394 }
1395 break;
1396 case 'P':
@@ -1645,17 +1645,17 @@
1645 pLast = pLast->pNext;
1646 for(p=pFirst; p && p!=pLast; p=p->pNext){
1647 if( p->eType==TT_Id ){
1648 static IdentTable sReserved;
1649 static int isInit = 0;
1650 static const char *aWords[] = { "char", "class",
1651 "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
1652 "float", "int", "long",
1653 "PRIVATE", "PROTECTED", "PUBLIC",
1654 "register", "static", "struct", "sizeof", "signed", "typedef",
1655 "union", "volatile", "virtual", "void", };
1656
1657 if( !isInit ){
1658 int i;
1659 for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
1660 IdentTableInsert(&sReserved,aWords[i],0);
1661 }
@@ -1768,11 +1768,11 @@
1768 pCode = pLast;
1769 while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
1770 pLast = pLast->pPrev;
1771 }
1772 if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
1773 fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
1774 zFilename, pFirst->nLine);
1775 return 1;
1776 }
1777 if( flags & (PS_Interface|PS_Export|PS_Local) ){
1778 fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
@@ -1849,11 +1849,11 @@
1849 return 1;
1850 }
1851
1852 #ifdef DEBUG
1853 if( debugMask & PARSER ){
1854 printf("**** Found inline routine: %.*s on line %d...\n",
1855 pName->nText, pName->zText, pFirst->nLine);
1856 PrintTokens(pFirst,pEnd);
1857 printf("\n");
1858 }
1859 #endif
@@ -1888,11 +1888,11 @@
1888 ** to search for an occurrence of an ID followed immediately by '('.
1889 ** If found, we have a prototype. Otherwise we are dealing with a
1890 ** variable definition.
1891 */
1892 static int isVariableDef(Token *pFirst, Token *pEnd){
1893 if( pEnd && pEnd->zText[0]=='=' &&
1894 (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
1895 ){
1896 return 1;
1897 }
1898 while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
@@ -1949,11 +1949,11 @@
1949 }
1950 while( pFirst!=0 && pFirst->pNext!=pEnd &&
1951 ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
1952 || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
1953 ){
1954 /* Lose the initial "static" or local from local variables.
1955 ** We'll prepend "extern" later. */
1956 pFirst = pFirst->pNext;
1957 isLocal = 1;
1958 }
1959 if( pFirst==0 || !isLocal ){
@@ -1962,11 +1962,11 @@
1962 }else if( flags & PS_Method ){
1963 /* Methods are declared by their class. Don't declare separately. */
1964 return nErr;
1965 }
1966 isVar = (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
1967 if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
1968 && (flags & PS_Extern)==0 ){
1969 fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
1970 zFilename, pFirst->nLine);
1971 nErr++;
1972 }
@@ -2095,11 +2095,11 @@
2095 nCmd++;
2096 }
2097
2098 if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
2099 /*
2100 ** Pop the if stack
2101 */
2102 pIf = ifStack;
2103 if( pIf==0 ){
2104 fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
2105 return 1;
@@ -2106,11 +2106,11 @@
2106 }
2107 ifStack = pIf->pNext;
2108 SafeFree(pIf);
2109 }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
2110 /*
2111 ** Record a #define if we are in PS_Interface or PS_Export
2112 */
2113 Decl *pDecl;
2114 if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
2115 zArg = &zCmd[6];
2116 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
@@ -2129,11 +2129,11 @@
2129 }else if( flags & PS_Local ){
2130 DeclSetProperty(pDecl,DP_Local);
2131 }
2132 }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
2133 /*
2134 ** Record an #include if we are in PS_Interface or PS_Export
2135 */
2136 Include *pInclude;
2137 char *zIf;
2138
2139 if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
@@ -2184,11 +2184,11 @@
2184 PushIfMacro(0,0,0,pToken->nLine,PS_Local);
2185 }else{
2186 PushIfMacro(0,zArg,nArg,pToken->nLine,0);
2187 }
2188 }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
2189 /*
2190 ** Push an #ifdef.
2191 */
2192 zArg = &zCmd[5];
2193 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
2194 zArg++;
@@ -2207,11 +2207,11 @@
2207 if( *zArg==0 || *zArg=='\n' ){ return 0; }
2208 nArg = pToken->nText + (int)(pToken->zText - zArg);
2209 PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
2210 }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
2211 /*
2212 ** Invert the #if on the top of the stack
2213 */
2214 if( ifStack==0 ){
2215 fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
2216 pToken->nLine);
2217 return 1;
@@ -2224,33 +2224,33 @@
2224 }else{
2225 pIf->flags = 0;
2226 }
2227 }else{
2228 /*
2229 ** This directive can be safely ignored
2230 */
2231 return 0;
2232 }
2233
2234 /*
2235 ** Recompute the preset flags
2236 */
2237 *pPresetFlags = 0;
2238 for(pIf = ifStack; pIf; pIf=pIf->pNext){
2239 *pPresetFlags |= pIf->flags;
2240 }
2241
2242 return nErr;
2243 }
2244
2245 /*
2246 ** Parse an entire file. Return the number of errors.
2247 **
2248 ** pList is a list of tokens in the file. Whitespace tokens have been
2249 ** eliminated, and text with {...} has been collapsed into a
2250 ** single TT_Brace token.
2251 **
2252 ** initFlags are a set of parse flags that should always be set for this
2253 ** file. For .c files this is normally 0. For .h files it is PS_Interface.
2254 */
2255 static int ParseFile(Token *pList, int initFlags){
2256 int nErr = 0;
@@ -2279,11 +2279,11 @@
2279 pStart = 0;
2280 flags = presetFlags;
2281 break;
2282
2283 case '=':
2284 if( pList->pPrev->nText==8
2285 && strncmp(pList->pPrev->zText,"operator",8)==0 ){
2286 break;
2287 }
2288 nErr += ProcessDecl(pStart,pList,flags);
2289 pStart = 0;
@@ -2471,11 +2471,11 @@
2471 pDecl->zExtra = 0;
2472 }
2473
2474 /*
2475 ** Reset the DP_Forward and DP_Declared flags on all Decl structures.
2476 ** Set both flags for anything that is tagged as local and isn't
2477 ** in the file zFilename so that it won't be printing in other files.
2478 */
2479 static void ResetDeclFlags(char *zFilename){
2480 Decl *pDecl;
2481
@@ -2574,11 +2574,11 @@
2574 int flag;
2575 int isCpp; /* True if generating C++ */
2576 int doneTypedef = 0; /* True if a typedef has been done for this object */
2577
2578 /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
2579 /*
2580 ** For any object that has a forward declaration, go ahead and do the
2581 ** forward declaration first.
2582 */
2583 isCpp = (pState->flags & DP_Cplusplus) != 0;
2584 for(p=pDecl; p; p=p->pSameName){
@@ -2626,12 +2626,12 @@
2626 ** function on a recursive call with the same pDecl. Hence, recursive
2627 ** calls to this function (through ScanText()) can never change the
2628 ** value of DP_Flag out from under us.
2629 */
2630 for(p=pDecl; p; p=p->pSameName){
2631 if( !DeclHasProperty(p,DP_Declared)
2632 && (p->zFwd==0 || needFullDecl)
2633 && p->zDecl!=0
2634 ){
2635 DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
2636 }else{
2637 DeclClearProperty(p,DP_Flag);
@@ -2735,12 +2735,12 @@
2735 ** by sToken.
2736 */
2737 pDecl = FindDecl(sToken.zText,sToken.nText);
2738 if( pDecl==0 ) continue;
2739
2740 /*
2741 ** If we get this far, we've found an identifier that has a
2742 ** declaration in the database. Now see if we the full declaration
2743 ** or just a forward declaration.
2744 */
2745 GetNonspaceToken(&sIn,&sNext);
2746 if( sNext.zText[0]=='*' ){
@@ -2770,12 +2770,12 @@
2770 int progress;
2771
2772 do{
2773 progress = 0;
2774 for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
2775 if( DeclHasProperty(pDecl,DP_Forward)
2776 && !DeclHasProperty(pDecl,DP_Declared)
2777 ){
2778 DeclareObject(pDecl,pState,1);
2779 progress = 1;
2780 assert( DeclHasProperty(pDecl,DP_Declared) );
2781 }
@@ -2842,11 +2842,11 @@
2842 nErr++;
2843 }
2844 }else if( report ){
2845 fprintf(report,"unchanged\n");
2846 }
2847 SafeFree(zOldVersion);
2848 IdentTableReset(&includeTable);
2849 StringReset(&outStr);
2850 return nErr;
2851 }
2852
@@ -2878,11 +2878,11 @@
2878 }
2879 ChangeIfContext(0,&sState);
2880 printf("%s",StringGet(&outStr));
2881 IdentTableReset(&includeTable);
2882 StringReset(&outStr);
2883 return 0;
2884 }
2885
2886 #ifdef DEBUG
2887 /*
2888 ** Return the number of characters in the given string prior to the
@@ -3040,11 +3040,11 @@
3040 int nSrc;
3041 char *zSrc;
3042 InFile *pFile;
3043 int i;
3044
3045 /*
3046 ** Get the name of the input file to be scanned. The input file is
3047 ** everything before the first ':' or the whole file if no ':' is seen.
3048 **
3049 ** Except, on windows, ignore any ':' that occurs as the second character
3050 ** since it might be part of the drive specifier. So really, the ":' has
@@ -3099,11 +3099,11 @@
3099 }
3100 }
3101
3102 /*
3103 ** If pFile->zSrc contains no 'c' or 'C' in its extension, it
3104 ** must be a header file. In that case, we need to set the
3105 ** PS_Interface flag.
3106 */
3107 pFile->flags |= PS_Interface;
3108 for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
3109 if( zSrc[i]=='c' || zSrc[i]=='C' ){
@@ -3110,11 +3110,11 @@
3110 pFile->flags &= ~PS_Interface;
3111 break;
3112 }
3113 }
3114
3115 /* Done!
3116 */
3117 return pFile;
3118 }
3119
3120 /* MS-Windows and MS-DOS both have the following serious OS bug: the
@@ -3162,11 +3162,11 @@
3162 while( c!=EOF ){
3163 while( c!=EOF && isspace(c) ){
3164 if( c=='\n' ){
3165 startOfLine = 1;
3166 }
3167 c = getc(in);
3168 if( startOfLine && c=='#' ){
3169 while( c!=EOF && c!='\n' ){
3170 c = getc(in);
3171 }
3172 }
@@ -3184,11 +3184,11 @@
3184 if( nAlloc==0 ){
3185 nAlloc = 100 + argc;
3186 zNew = malloc( sizeof(char*) * nAlloc );
3187 }else{
3188 nAlloc *= 2;
3189 zNew = realloc( zNew, sizeof(char*) * nAlloc );
3190 }
3191 }
3192 if( zNew ){
3193 int j = nNew + index;
3194 zNew[j] = malloc( n + 1 );
@@ -3254,11 +3254,11 @@
3254
3255 /*
3256 ** The following text contains a few simple #defines that we want
3257 ** to be available to every file.
3258 */
3259 static const char zInit[] =
3260 "#define INTERFACE 0\n"
3261 "#define EXPORT_INTERFACE 0\n"
3262 "#define LOCAL_INTERFACE 0\n"
3263 "#define EXPORT\n"
3264 "#define LOCAL static\n"
3265
+22 -9
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1,8 +1,8 @@
11
#!/usr/bin/tclsh
22
#
3
-# Run this TCL script to generate the various makefiles for a variety
3
+# Run this Tcl script to generate the various makefiles for a variety
44
# of platforms. Files generated include:
55
#
66
# src/main.mk # makefile for all unix systems
77
# win/Makefile.mingw # makefile for mingw on windows
88
# win/Makefile.* # makefiles for other windows compilers
@@ -110,10 +110,11 @@
110110
sitemap
111111
skins
112112
sqlcmd
113113
stash
114114
stat
115
+ statrep
115116
style
116117
sync
117118
tag
118119
tar
119120
th_main
@@ -142,10 +143,12 @@
142143
143144
# Additional resource files that get built into the executable.
144145
#
145146
set extra_files {
146147
diff.tcl
148
+ markdown.md
149
+ ../skins/*/*.txt
147150
}
148151
149152
# Options used to compile the included SQLite library.
150153
#
151154
set SQLITE_OPTIONS {
@@ -203,10 +206,19 @@
203206
}
204207
205208
# STOP HERE.
206209
# Unless the build procedures changes, you should not have to edit anything
207210
# below this line.
211
+
212
+# Expand any wildcards in "extra_files"
213
+set new_extra_files {}
214
+foreach file $extra_files {
215
+ foreach x [glob -nocomplain $file] {
216
+ lappend new_extra_files $x
217
+ }
218
+}
219
+set extra_files $new_extra_files
208220
209221
##############################################################################
210222
##############################################################################
211223
##############################################################################
212224
# Start by generating the "main.mk" makefile used for all unix systems.
@@ -362,11 +374,11 @@
362374
set mhargs [string map [list <<<NEXT_LINE>>> \\\n\t] $mhargs]
363375
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
364376
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >\$@\n"
365377
366378
writeln "\$(OBJDIR)/builtin_data.h: \$(OBJDIR)/mkbuiltin \$(EXTRA_FILES)"
367
-writeln "\t\$(OBJDIR)/mkbuiltin \$(EXTRA_FILES) >\$@\n"
379
+writeln "\t\$(OBJDIR)/mkbuiltin --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n"
368380
369381
writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
370382
writeln "\t\$(OBJDIR)/makeheaders $mhargs"
371383
writeln "\ttouch \$(OBJDIR)/headers"
372384
writeln "\$(OBJDIR)/headers: Makefile"
@@ -573,12 +585,13 @@
573585
#### The directories where the OpenSSL include and library files are located.
574586
# The recommended usage here is to use the Sysinternals junction tool
575587
# to create a hard link between an "openssl-1.x" sub-directory of the
576588
# Fossil source code directory and the target OpenSSL source directory.
577589
#
578
-OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include
579
-OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j
590
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
591
+OPENSSLINCDIR = $(OPENSSLDIR)/include
592
+OPENSSLLIBDIR = $(OPENSSLDIR)
580593
581594
#### Either the directory where the Tcl library is installed or the Tcl
582595
# source code directory resides (depending on the value of the macro
583596
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
584597
# this directory must have "include" and "lib" sub-directories. If
@@ -1014,11 +1027,11 @@
10141027
append mhargs " \\\n\t\t\$(OBJDIR)/VERSION.h"
10151028
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(MKINDEX)"
10161029
writeln "\t\$(MKINDEX) \$(TRANS_SRC) >\$@\n"
10171030
10181031
writeln "\$(OBJDIR)/builtin_data.h:\t\$(MKBUILTIN) \$(EXTRA_FILES)"
1019
-writeln "\t\$(MKBUILTIN) \$(EXTRA_FILES) >\$@\n"
1032
+writeln "\t\$(MKBUILTIN) --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n"
10201033
10211034
writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(MAKEHEADERS) \$(OBJDIR)/VERSION.h"
10221035
writeln "\t\$(MAKEHEADERS) $mhargs"
10231036
writeln "\techo Done >\$(OBJDIR)/headers\n"
10241037
writeln "\$(OBJDIR)/headers: Makefile\n"
@@ -1193,11 +1206,11 @@
11931206
11941207
page_index.h: mkindex$E $(SRC)
11951208
+$** > $@
11961209
11971210
builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
1198
- +$** > $@
1211
+ mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
11991212
12001213
clean:
12011214
-del $(OBJDIR)\*.obj
12021215
-del *.obj *_.c *.h *.map
12031216
@@ -1305,11 +1318,11 @@
13051318
13061319
# Uncomment to enable Tcl support
13071320
# FOSSIL_ENABLE_TCL = 1
13081321
13091322
!ifdef FOSSIL_ENABLE_SSL
1310
-SSLDIR = $(B)\compat\openssl-1.0.1j
1323
+SSLDIR = $(B)\compat\openssl-1.0.2
13111324
SSLINCDIR = $(SSLDIR)\inc32
13121325
SSLLIBDIR = $(SSLDIR)\out32
13131326
SSLLFLAGS = /nologo /opt:ref /debug
13141327
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
13151328
!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
@@ -1587,11 +1600,11 @@
15871600
15881601
page_index.h: mkindex$E $(SRC)
15891602
$** > $@
15901603
15911604
builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
1592
- $** > $@
1605
+ mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
15931606
15941607
clean:
15951608
-del $(OX)\*.obj
15961609
-del *.obj
15971610
-del *_.c
@@ -1819,11 +1832,11 @@
18191832
# generate the index source, containing all web references,..
18201833
page_index.h: $(TRANSLATEDSRC) mkindex.exe
18211834
mkindex.exe $(TRANSLATEDSRC) >$@
18221835
18231836
builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe
1824
- mkbuiltin.exe $(EXTRA_FILES) >$@
1837
+ mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
18251838
18261839
# extracting version info from manifest
18271840
VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION
18281841
version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@
18291842
18301843
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1,8 +1,8 @@
1 #!/usr/bin/tclsh
2 #
3 # Run this TCL script to generate the various makefiles for a variety
4 # of platforms. Files generated include:
5 #
6 # src/main.mk # makefile for all unix systems
7 # win/Makefile.mingw # makefile for mingw on windows
8 # win/Makefile.* # makefiles for other windows compilers
@@ -110,10 +110,11 @@
110 sitemap
111 skins
112 sqlcmd
113 stash
114 stat
 
115 style
116 sync
117 tag
118 tar
119 th_main
@@ -142,10 +143,12 @@
142
143 # Additional resource files that get built into the executable.
144 #
145 set extra_files {
146 diff.tcl
 
 
147 }
148
149 # Options used to compile the included SQLite library.
150 #
151 set SQLITE_OPTIONS {
@@ -203,10 +206,19 @@
203 }
204
205 # STOP HERE.
206 # Unless the build procedures changes, you should not have to edit anything
207 # below this line.
 
 
 
 
 
 
 
 
 
208
209 ##############################################################################
210 ##############################################################################
211 ##############################################################################
212 # Start by generating the "main.mk" makefile used for all unix systems.
@@ -362,11 +374,11 @@
362 set mhargs [string map [list <<<NEXT_LINE>>> \\\n\t] $mhargs]
363 writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
364 writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >\$@\n"
365
366 writeln "\$(OBJDIR)/builtin_data.h: \$(OBJDIR)/mkbuiltin \$(EXTRA_FILES)"
367 writeln "\t\$(OBJDIR)/mkbuiltin \$(EXTRA_FILES) >\$@\n"
368
369 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
370 writeln "\t\$(OBJDIR)/makeheaders $mhargs"
371 writeln "\ttouch \$(OBJDIR)/headers"
372 writeln "\$(OBJDIR)/headers: Makefile"
@@ -573,12 +585,13 @@
573 #### The directories where the OpenSSL include and library files are located.
574 # The recommended usage here is to use the Sysinternals junction tool
575 # to create a hard link between an "openssl-1.x" sub-directory of the
576 # Fossil source code directory and the target OpenSSL source directory.
577 #
578 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include
579 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j
 
580
581 #### Either the directory where the Tcl library is installed or the Tcl
582 # source code directory resides (depending on the value of the macro
583 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
584 # this directory must have "include" and "lib" sub-directories. If
@@ -1014,11 +1027,11 @@
1014 append mhargs " \\\n\t\t\$(OBJDIR)/VERSION.h"
1015 writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(MKINDEX)"
1016 writeln "\t\$(MKINDEX) \$(TRANS_SRC) >\$@\n"
1017
1018 writeln "\$(OBJDIR)/builtin_data.h:\t\$(MKBUILTIN) \$(EXTRA_FILES)"
1019 writeln "\t\$(MKBUILTIN) \$(EXTRA_FILES) >\$@\n"
1020
1021 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(MAKEHEADERS) \$(OBJDIR)/VERSION.h"
1022 writeln "\t\$(MAKEHEADERS) $mhargs"
1023 writeln "\techo Done >\$(OBJDIR)/headers\n"
1024 writeln "\$(OBJDIR)/headers: Makefile\n"
@@ -1193,11 +1206,11 @@
1193
1194 page_index.h: mkindex$E $(SRC)
1195 +$** > $@
1196
1197 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
1198 +$** > $@
1199
1200 clean:
1201 -del $(OBJDIR)\*.obj
1202 -del *.obj *_.c *.h *.map
1203
@@ -1305,11 +1318,11 @@
1305
1306 # Uncomment to enable Tcl support
1307 # FOSSIL_ENABLE_TCL = 1
1308
1309 !ifdef FOSSIL_ENABLE_SSL
1310 SSLDIR = $(B)\compat\openssl-1.0.1j
1311 SSLINCDIR = $(SSLDIR)\inc32
1312 SSLLIBDIR = $(SSLDIR)\out32
1313 SSLLFLAGS = /nologo /opt:ref /debug
1314 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
1315 !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
@@ -1587,11 +1600,11 @@
1587
1588 page_index.h: mkindex$E $(SRC)
1589 $** > $@
1590
1591 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
1592 $** > $@
1593
1594 clean:
1595 -del $(OX)\*.obj
1596 -del *.obj
1597 -del *_.c
@@ -1819,11 +1832,11 @@
1819 # generate the index source, containing all web references,..
1820 page_index.h: $(TRANSLATEDSRC) mkindex.exe
1821 mkindex.exe $(TRANSLATEDSRC) >$@
1822
1823 builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe
1824 mkbuiltin.exe $(EXTRA_FILES) >$@
1825
1826 # extracting version info from manifest
1827 VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION
1828 version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@
1829
1830
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1,8 +1,8 @@
1 #!/usr/bin/tclsh
2 #
3 # Run this Tcl script to generate the various makefiles for a variety
4 # of platforms. Files generated include:
5 #
6 # src/main.mk # makefile for all unix systems
7 # win/Makefile.mingw # makefile for mingw on windows
8 # win/Makefile.* # makefiles for other windows compilers
@@ -110,10 +110,11 @@
110 sitemap
111 skins
112 sqlcmd
113 stash
114 stat
115 statrep
116 style
117 sync
118 tag
119 tar
120 th_main
@@ -142,10 +143,12 @@
143
144 # Additional resource files that get built into the executable.
145 #
146 set extra_files {
147 diff.tcl
148 markdown.md
149 ../skins/*/*.txt
150 }
151
152 # Options used to compile the included SQLite library.
153 #
154 set SQLITE_OPTIONS {
@@ -203,10 +206,19 @@
206 }
207
208 # STOP HERE.
209 # Unless the build procedures changes, you should not have to edit anything
210 # below this line.
211
212 # Expand any wildcards in "extra_files"
213 set new_extra_files {}
214 foreach file $extra_files {
215 foreach x [glob -nocomplain $file] {
216 lappend new_extra_files $x
217 }
218 }
219 set extra_files $new_extra_files
220
221 ##############################################################################
222 ##############################################################################
223 ##############################################################################
224 # Start by generating the "main.mk" makefile used for all unix systems.
@@ -362,11 +374,11 @@
374 set mhargs [string map [list <<<NEXT_LINE>>> \\\n\t] $mhargs]
375 writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
376 writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >\$@\n"
377
378 writeln "\$(OBJDIR)/builtin_data.h: \$(OBJDIR)/mkbuiltin \$(EXTRA_FILES)"
379 writeln "\t\$(OBJDIR)/mkbuiltin --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n"
380
381 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
382 writeln "\t\$(OBJDIR)/makeheaders $mhargs"
383 writeln "\ttouch \$(OBJDIR)/headers"
384 writeln "\$(OBJDIR)/headers: Makefile"
@@ -573,12 +585,13 @@
585 #### The directories where the OpenSSL include and library files are located.
586 # The recommended usage here is to use the Sysinternals junction tool
587 # to create a hard link between an "openssl-1.x" sub-directory of the
588 # Fossil source code directory and the target OpenSSL source directory.
589 #
590 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
591 OPENSSLINCDIR = $(OPENSSLDIR)/include
592 OPENSSLLIBDIR = $(OPENSSLDIR)
593
594 #### Either the directory where the Tcl library is installed or the Tcl
595 # source code directory resides (depending on the value of the macro
596 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
597 # this directory must have "include" and "lib" sub-directories. If
@@ -1014,11 +1027,11 @@
1027 append mhargs " \\\n\t\t\$(OBJDIR)/VERSION.h"
1028 writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(MKINDEX)"
1029 writeln "\t\$(MKINDEX) \$(TRANS_SRC) >\$@\n"
1030
1031 writeln "\$(OBJDIR)/builtin_data.h:\t\$(MKBUILTIN) \$(EXTRA_FILES)"
1032 writeln "\t\$(MKBUILTIN) --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n"
1033
1034 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(MAKEHEADERS) \$(OBJDIR)/VERSION.h"
1035 writeln "\t\$(MAKEHEADERS) $mhargs"
1036 writeln "\techo Done >\$(OBJDIR)/headers\n"
1037 writeln "\$(OBJDIR)/headers: Makefile\n"
@@ -1193,11 +1206,11 @@
1206
1207 page_index.h: mkindex$E $(SRC)
1208 +$** > $@
1209
1210 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
1211 mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
1212
1213 clean:
1214 -del $(OBJDIR)\*.obj
1215 -del *.obj *_.c *.h *.map
1216
@@ -1305,11 +1318,11 @@
1318
1319 # Uncomment to enable Tcl support
1320 # FOSSIL_ENABLE_TCL = 1
1321
1322 !ifdef FOSSIL_ENABLE_SSL
1323 SSLDIR = $(B)\compat\openssl-1.0.2
1324 SSLINCDIR = $(SSLDIR)\inc32
1325 SSLLIBDIR = $(SSLDIR)\out32
1326 SSLLFLAGS = /nologo /opt:ref /debug
1327 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
1328 !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
@@ -1587,11 +1600,11 @@
1600
1601 page_index.h: mkindex$E $(SRC)
1602 $** > $@
1603
1604 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
1605 mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
1606
1607 clean:
1608 -del $(OX)\*.obj
1609 -del *.obj
1610 -del *_.c
@@ -1819,11 +1832,11 @@
1832 # generate the index source, containing all web references,..
1833 page_index.h: $(TRANSLATEDSRC) mkindex.exe
1834 mkindex.exe $(TRANSLATEDSRC) >$@
1835
1836 builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe
1837 mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
1838
1839 # extracting version info from manifest
1840 VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION
1841 version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@
1842
1843
+64 -53
--- src/manifest.c
+++ src/manifest.c
@@ -1187,16 +1187,18 @@
11871187
/*
11881188
** Add a single entry to the mlink table. Also add the filename to
11891189
** the filename table if it is not there already.
11901190
*/
11911191
static void add_one_mlink(
1192
+ int pmid, /* The parent manifest */
1193
+ const char *zFromUuid, /* UUID for content in parent */
11921194
int mid, /* The record ID of the manifest */
1193
- const char *zFromUuid, /* UUID for the mlink.pid. "" to add file */
1194
- const char *zToUuid, /* UUID for the mlink.fid. "" to delete */
1195
+ const char *zToUuid, /* UUID for content in child */
11951196
const char *zFilename, /* Filename */
11961197
const char *zPrior, /* Previous filename. NULL if unchanged */
11971198
int isPublic, /* True if mid is not a private manifest */
1199
+ int isPrimary, /* pmid is the primary parent of mid */
11981200
int mperm /* 1: exec, 2: symlink */
11991201
){
12001202
int fnid, pfnid, pid, fid;
12011203
static Stmt s1;
12021204
@@ -1216,19 +1218,21 @@
12161218
}else{
12171219
fid = uuid_to_rid(zToUuid, 1);
12181220
if( isPublic ) content_make_public(fid);
12191221
}
12201222
db_static_prepare(&s1,
1221
- "INSERT INTO mlink(mid,pid,fid,fnid,pfnid,mperm)"
1222
- "VALUES(:m,:p,:f,:n,:pfn,:mp)"
1223
+ "INSERT INTO mlink(mid,fid,pmid,pid,fnid,pfnid,mperm,isaux)"
1224
+ "VALUES(:m,:f,:pm,:p,:n,:pfn,:mp,:isaux)"
12231225
);
12241226
db_bind_int(&s1, ":m", mid);
1225
- db_bind_int(&s1, ":p", pid);
12261227
db_bind_int(&s1, ":f", fid);
1228
+ db_bind_int(&s1, ":pm", pmid);
1229
+ db_bind_int(&s1, ":p", pid);
12271230
db_bind_int(&s1, ":n", fnid);
12281231
db_bind_int(&s1, ":pfn", pfnid);
12291232
db_bind_int(&s1, ":mp", mperm);
1233
+ db_bind_int(&s1, ":isaux", isPrimary==0);
12301234
db_exec(&s1);
12311235
if( pid && fid ){
12321236
content_deltify(pid, fid, 0);
12331237
}
12341238
}
@@ -1342,24 +1346,29 @@
13421346
**
13431347
** Deleted files have mlink.fid=0.
13441348
** Added files have mlink.pid=0.
13451349
** Edited files have both mlink.pid!=0 and mlink.fid!=0
13461350
*/
1347
-static void add_mlink(int pid, Manifest *pParent, int cid, Manifest *pChild){
1351
+static void add_mlink(
1352
+ int pmid, Manifest *pParent, /* Parent check-in */
1353
+ int mid, Manifest *pChild, /* The child check-in */
1354
+ int isPrim /* TRUE if pmid is the primary parent of mid */
1355
+){
13481356
Blob otherContent;
13491357
int otherRid;
13501358
int i, rc;
13511359
ManifestFile *pChildFile, *pParentFile;
13521360
Manifest **ppOther;
13531361
static Stmt eq;
13541362
int isPublic; /* True if pChild is non-private */
13551363
1356
- /* If mlink table entires are already set for cid, then abort early
1357
- ** doing no work.
1364
+ /* If mlink table entires are already exist for the pmid-to-mid transition,
1365
+ ** then abort early doing no work.
13581366
*/
1359
- db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid");
1360
- db_bind_int(&eq, ":mid", cid);
1367
+ db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid AND pmid=:pmid");
1368
+ db_bind_int(&eq, ":mid", mid);
1369
+ db_bind_int(&eq, ":pmid", pmid);
13611370
rc = db_step(&eq);
13621371
db_reset(&eq);
13631372
if( rc==SQLITE_ROW ) return;
13641373
13651374
/* Compute the value of the missing pParent or pChild parameter.
@@ -1366,14 +1375,14 @@
13661375
** Fetch the baseline checkins for both.
13671376
*/
13681377
assert( pParent==0 || pChild==0 );
13691378
if( pParent==0 ){
13701379
ppOther = &pParent;
1371
- otherRid = pid;
1380
+ otherRid = pmid;
13721381
}else{
13731382
ppOther = &pChild;
1374
- otherRid = cid;
1383
+ otherRid = mid;
13751384
}
13761385
if( (*ppOther = manifest_cache_find(otherRid))==0 ){
13771386
content_get(otherRid, &otherContent);
13781387
if( blob_size(&otherContent)==0 ) return;
13791388
*ppOther = manifest_parse(&otherContent, otherRid, 0);
@@ -1381,20 +1390,20 @@
13811390
}
13821391
if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
13831392
manifest_destroy(*ppOther);
13841393
return;
13851394
}
1386
- isPublic = !content_is_private(cid);
1395
+ isPublic = !content_is_private(mid);
13871396
13881397
/* Try to make the parent manifest a delta from the child, if that
13891398
** is an appropriate thing to do. For a new baseline, make the
13901399
** previous baseline a delta from the current baseline.
13911400
*/
13921401
if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
1393
- content_deltify(pid, cid, 0);
1402
+ content_deltify(pmid, mid, 0);
13941403
}else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
1395
- content_deltify(pParent->pBaseline->rid, cid, 0);
1404
+ content_deltify(pParent->pBaseline->rid, mid, 0);
13961405
}
13971406
13981407
/* Remember all children less than a few seconds younger than their parent,
13991408
** as we might want to fudge the times for those children.
14001409
*/
@@ -1414,31 +1423,32 @@
14141423
int mperm = manifest_file_mperm(pChildFile);
14151424
if( pChildFile->zPrior ){
14161425
pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
14171426
if( pParentFile ){
14181427
/* File with name change */
1419
- add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1420
- pChildFile->zName, pChildFile->zPrior, isPublic, mperm);
1428
+ add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
1429
+ pChildFile->zName, pChildFile->zPrior,
1430
+ isPublic, isPrim, mperm);
14211431
}else{
14221432
/* File name changed, but the old name is not found in the parent!
14231433
** Treat this like a new file. */
1424
- add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1425
- isPublic, mperm);
1434
+ add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
1435
+ isPublic, isPrim, mperm);
14261436
}
14271437
}else{
14281438
pParentFile = manifest_file_seek(pParent, pChildFile->zName, 0);
14291439
if( pParentFile==0 ){
14301440
if( pChildFile->zUuid ){
14311441
/* A new file */
1432
- add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1433
- isPublic, mperm);
1442
+ add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
1443
+ isPublic, isPrim, mperm);
14341444
}
14351445
}else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0
14361446
|| manifest_file_mperm(pParentFile)!=mperm ){
14371447
/* Changes in file content or permissions */
1438
- add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1439
- pChildFile->zName, 0, isPublic, mperm);
1448
+ add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
1449
+ pChildFile->zName, 0, isPublic, isPrim, mperm);
14401450
}
14411451
}
14421452
}
14431453
if( pParent->zBaseline && pChild->zBaseline ){
14441454
/* Both parent and child are delta manifests. Look for files that
@@ -1450,22 +1460,22 @@
14501460
pChildFile = manifest_file_seek_base(pChild, pParentFile->zName, 0);
14511461
if( pChildFile==0 ){
14521462
/* The child file reverts to baseline. Show this as a change */
14531463
pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
14541464
if( pChildFile ){
1455
- add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1456
- pChildFile->zName, 0, isPublic,
1465
+ add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
1466
+ pChildFile->zName, 0, isPublic, isPrim,
14571467
manifest_file_mperm(pChildFile));
14581468
}
14591469
}
14601470
}else{
14611471
pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
14621472
if( pChildFile ){
14631473
/* File resurrected in the child after having been deleted in
14641474
** the parent. Show this as an added file. */
1465
- add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1466
- isPublic, manifest_file_mperm(pChildFile));
1475
+ add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
1476
+ isPublic, isPrim, manifest_file_mperm(pChildFile));
14671477
}
14681478
}
14691479
}
14701480
}else if( pChild->zBaseline==0 ){
14711481
/* pChild is a baseline. Look for files that are present in pParent
@@ -1472,12 +1482,12 @@
14721482
** but are missing from pChild and mark them as having been deleted. */
14731483
manifest_file_rewind(pParent);
14741484
while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
14751485
pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
14761486
if( pChildFile==0 && pParentFile->zUuid!=0 ){
1477
- add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
1478
- isPublic, 0);
1487
+ add_one_mlink(pmid, pParentFile->zUuid, mid, 0, pParentFile->zName, 0,
1488
+ isPublic, isPrim, 0);
14791489
}
14801490
}
14811491
}
14821492
manifest_cache_insert(*ppOther);
14831493
}
@@ -1781,45 +1791,46 @@
17811791
sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
17821792
uuid_to_rid(p->zBaseline,1));
17831793
}else{
17841794
sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
17851795
}
1786
- (void)db_schema_is_outofdate(); /* Make sure g.zAuxSchema is initialized */
17871796
for(i=0; i<p->nParent; i++){
17881797
int pid = uuid_to_rid(p->azParent[i], 1);
1789
- if( strcmp(g.zAuxSchema,"2014-11-24 20:35")>=0 ){
1790
- /* Support for PLINK.BASEID added on 2014-11-24 */
1791
- db_multi_exec(
1792
- "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
1793
- "VALUES(%d, %d, %d, %.17g, %s)",
1794
- pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);
1795
- }else{
1796
- /* Continue to work with older schema to avoid an unnecessary
1797
- ** rebuild */
1798
- db_multi_exec(
1799
- "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
1800
- "VALUES(%d, %d, %d, %.17g)",
1801
- pid, rid, i==0, p->rDate);
1802
- }
1803
- if( i==0 ){
1804
- add_mlink(pid, 0, rid, p);
1805
- parentid = pid;
1806
- }
1807
- }
1808
- db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d AND isprim", rid);
1798
+ db_multi_exec(
1799
+ "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
1800
+ "VALUES(%d, %d, %d, %.17g, %s)",
1801
+ pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);
1802
+ add_mlink(pid, 0, rid, p, i==0);
1803
+ if( i==0 ) parentid = pid;
1804
+ }
1805
+ if( p->nParent>1 ){
1806
+ /* Remove incorrect MLINK create-file entries that arise when a
1807
+ ** file is added by merge. */
1808
+ db_multi_exec(
1809
+ "DELETE FROM mlink"
1810
+ " WHERE mid=%d"
1811
+ " AND pid=0"
1812
+ " AND fnid IN "
1813
+ " (SELECT fnid FROM mlink WHERE mid=%d GROUP BY fnid"
1814
+ " HAVING count(*)<%d)",
1815
+ rid, rid, p->nParent
1816
+ );
1817
+ }
1818
+ db_prepare(&q, "SELECT cid, isprim FROM plink WHERE pid=%d", rid);
18091819
while( db_step(&q)==SQLITE_ROW ){
18101820
int cid = db_column_int(&q, 0);
1811
- add_mlink(rid, p, cid, 0);
1821
+ int isprim = db_column_int(&q, 1);
1822
+ add_mlink(rid, p, cid, 0, isprim);
18121823
}
18131824
db_finalize(&q);
18141825
if( p->nParent==0 ){
18151826
/* For root files (files without parents) add mlink entries
18161827
** showing all content as new. */
18171828
int isPublic = !content_is_private(rid);
18181829
for(i=0; i<p->nFile; i++){
1819
- add_one_mlink(rid, 0, p->aFile[i].zUuid, p->aFile[i].zName, 0,
1820
- isPublic, manifest_file_mperm(&p->aFile[i]));
1830
+ add_one_mlink(0, 0, rid, p->aFile[i].zUuid, p->aFile[i].zName, 0,
1831
+ isPublic, 1, manifest_file_mperm(&p->aFile[i]));
18211832
}
18221833
}
18231834
db_multi_exec(
18241835
"REPLACE INTO event(type,mtime,objid,user,comment,"
18251836
"bgcolor,euser,ecomment,omtime)"
18261837
18271838
ADDED src/markdown.md
--- src/manifest.c
+++ src/manifest.c
@@ -1187,16 +1187,18 @@
1187 /*
1188 ** Add a single entry to the mlink table. Also add the filename to
1189 ** the filename table if it is not there already.
1190 */
1191 static void add_one_mlink(
 
 
1192 int mid, /* The record ID of the manifest */
1193 const char *zFromUuid, /* UUID for the mlink.pid. "" to add file */
1194 const char *zToUuid, /* UUID for the mlink.fid. "" to delete */
1195 const char *zFilename, /* Filename */
1196 const char *zPrior, /* Previous filename. NULL if unchanged */
1197 int isPublic, /* True if mid is not a private manifest */
 
1198 int mperm /* 1: exec, 2: symlink */
1199 ){
1200 int fnid, pfnid, pid, fid;
1201 static Stmt s1;
1202
@@ -1216,19 +1218,21 @@
1216 }else{
1217 fid = uuid_to_rid(zToUuid, 1);
1218 if( isPublic ) content_make_public(fid);
1219 }
1220 db_static_prepare(&s1,
1221 "INSERT INTO mlink(mid,pid,fid,fnid,pfnid,mperm)"
1222 "VALUES(:m,:p,:f,:n,:pfn,:mp)"
1223 );
1224 db_bind_int(&s1, ":m", mid);
1225 db_bind_int(&s1, ":p", pid);
1226 db_bind_int(&s1, ":f", fid);
 
 
1227 db_bind_int(&s1, ":n", fnid);
1228 db_bind_int(&s1, ":pfn", pfnid);
1229 db_bind_int(&s1, ":mp", mperm);
 
1230 db_exec(&s1);
1231 if( pid && fid ){
1232 content_deltify(pid, fid, 0);
1233 }
1234 }
@@ -1342,24 +1346,29 @@
1342 **
1343 ** Deleted files have mlink.fid=0.
1344 ** Added files have mlink.pid=0.
1345 ** Edited files have both mlink.pid!=0 and mlink.fid!=0
1346 */
1347 static void add_mlink(int pid, Manifest *pParent, int cid, Manifest *pChild){
 
 
 
 
1348 Blob otherContent;
1349 int otherRid;
1350 int i, rc;
1351 ManifestFile *pChildFile, *pParentFile;
1352 Manifest **ppOther;
1353 static Stmt eq;
1354 int isPublic; /* True if pChild is non-private */
1355
1356 /* If mlink table entires are already set for cid, then abort early
1357 ** doing no work.
1358 */
1359 db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid");
1360 db_bind_int(&eq, ":mid", cid);
 
1361 rc = db_step(&eq);
1362 db_reset(&eq);
1363 if( rc==SQLITE_ROW ) return;
1364
1365 /* Compute the value of the missing pParent or pChild parameter.
@@ -1366,14 +1375,14 @@
1366 ** Fetch the baseline checkins for both.
1367 */
1368 assert( pParent==0 || pChild==0 );
1369 if( pParent==0 ){
1370 ppOther = &pParent;
1371 otherRid = pid;
1372 }else{
1373 ppOther = &pChild;
1374 otherRid = cid;
1375 }
1376 if( (*ppOther = manifest_cache_find(otherRid))==0 ){
1377 content_get(otherRid, &otherContent);
1378 if( blob_size(&otherContent)==0 ) return;
1379 *ppOther = manifest_parse(&otherContent, otherRid, 0);
@@ -1381,20 +1390,20 @@
1381 }
1382 if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
1383 manifest_destroy(*ppOther);
1384 return;
1385 }
1386 isPublic = !content_is_private(cid);
1387
1388 /* Try to make the parent manifest a delta from the child, if that
1389 ** is an appropriate thing to do. For a new baseline, make the
1390 ** previous baseline a delta from the current baseline.
1391 */
1392 if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
1393 content_deltify(pid, cid, 0);
1394 }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
1395 content_deltify(pParent->pBaseline->rid, cid, 0);
1396 }
1397
1398 /* Remember all children less than a few seconds younger than their parent,
1399 ** as we might want to fudge the times for those children.
1400 */
@@ -1414,31 +1423,32 @@
1414 int mperm = manifest_file_mperm(pChildFile);
1415 if( pChildFile->zPrior ){
1416 pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
1417 if( pParentFile ){
1418 /* File with name change */
1419 add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1420 pChildFile->zName, pChildFile->zPrior, isPublic, mperm);
 
1421 }else{
1422 /* File name changed, but the old name is not found in the parent!
1423 ** Treat this like a new file. */
1424 add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1425 isPublic, mperm);
1426 }
1427 }else{
1428 pParentFile = manifest_file_seek(pParent, pChildFile->zName, 0);
1429 if( pParentFile==0 ){
1430 if( pChildFile->zUuid ){
1431 /* A new file */
1432 add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1433 isPublic, mperm);
1434 }
1435 }else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0
1436 || manifest_file_mperm(pParentFile)!=mperm ){
1437 /* Changes in file content or permissions */
1438 add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1439 pChildFile->zName, 0, isPublic, mperm);
1440 }
1441 }
1442 }
1443 if( pParent->zBaseline && pChild->zBaseline ){
1444 /* Both parent and child are delta manifests. Look for files that
@@ -1450,22 +1460,22 @@
1450 pChildFile = manifest_file_seek_base(pChild, pParentFile->zName, 0);
1451 if( pChildFile==0 ){
1452 /* The child file reverts to baseline. Show this as a change */
1453 pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
1454 if( pChildFile ){
1455 add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
1456 pChildFile->zName, 0, isPublic,
1457 manifest_file_mperm(pChildFile));
1458 }
1459 }
1460 }else{
1461 pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
1462 if( pChildFile ){
1463 /* File resurrected in the child after having been deleted in
1464 ** the parent. Show this as an added file. */
1465 add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
1466 isPublic, manifest_file_mperm(pChildFile));
1467 }
1468 }
1469 }
1470 }else if( pChild->zBaseline==0 ){
1471 /* pChild is a baseline. Look for files that are present in pParent
@@ -1472,12 +1482,12 @@
1472 ** but are missing from pChild and mark them as having been deleted. */
1473 manifest_file_rewind(pParent);
1474 while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
1475 pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
1476 if( pChildFile==0 && pParentFile->zUuid!=0 ){
1477 add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
1478 isPublic, 0);
1479 }
1480 }
1481 }
1482 manifest_cache_insert(*ppOther);
1483 }
@@ -1781,45 +1791,46 @@
1781 sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
1782 uuid_to_rid(p->zBaseline,1));
1783 }else{
1784 sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
1785 }
1786 (void)db_schema_is_outofdate(); /* Make sure g.zAuxSchema is initialized */
1787 for(i=0; i<p->nParent; i++){
1788 int pid = uuid_to_rid(p->azParent[i], 1);
1789 if( strcmp(g.zAuxSchema,"2014-11-24 20:35")>=0 ){
1790 /* Support for PLINK.BASEID added on 2014-11-24 */
1791 db_multi_exec(
1792 "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
1793 "VALUES(%d, %d, %d, %.17g, %s)",
1794 pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);
1795 }else{
1796 /* Continue to work with older schema to avoid an unnecessary
1797 ** rebuild */
1798 db_multi_exec(
1799 "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
1800 "VALUES(%d, %d, %d, %.17g)",
1801 pid, rid, i==0, p->rDate);
1802 }
1803 if( i==0 ){
1804 add_mlink(pid, 0, rid, p);
1805 parentid = pid;
1806 }
1807 }
1808 db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d AND isprim", rid);
 
1809 while( db_step(&q)==SQLITE_ROW ){
1810 int cid = db_column_int(&q, 0);
1811 add_mlink(rid, p, cid, 0);
 
1812 }
1813 db_finalize(&q);
1814 if( p->nParent==0 ){
1815 /* For root files (files without parents) add mlink entries
1816 ** showing all content as new. */
1817 int isPublic = !content_is_private(rid);
1818 for(i=0; i<p->nFile; i++){
1819 add_one_mlink(rid, 0, p->aFile[i].zUuid, p->aFile[i].zName, 0,
1820 isPublic, manifest_file_mperm(&p->aFile[i]));
1821 }
1822 }
1823 db_multi_exec(
1824 "REPLACE INTO event(type,mtime,objid,user,comment,"
1825 "bgcolor,euser,ecomment,omtime)"
1826
1827 DDED src/markdown.md
--- src/manifest.c
+++ src/manifest.c
@@ -1187,16 +1187,18 @@
1187 /*
1188 ** Add a single entry to the mlink table. Also add the filename to
1189 ** the filename table if it is not there already.
1190 */
1191 static void add_one_mlink(
1192 int pmid, /* The parent manifest */
1193 const char *zFromUuid, /* UUID for content in parent */
1194 int mid, /* The record ID of the manifest */
1195 const char *zToUuid, /* UUID for content in child */
 
1196 const char *zFilename, /* Filename */
1197 const char *zPrior, /* Previous filename. NULL if unchanged */
1198 int isPublic, /* True if mid is not a private manifest */
1199 int isPrimary, /* pmid is the primary parent of mid */
1200 int mperm /* 1: exec, 2: symlink */
1201 ){
1202 int fnid, pfnid, pid, fid;
1203 static Stmt s1;
1204
@@ -1216,19 +1218,21 @@
1218 }else{
1219 fid = uuid_to_rid(zToUuid, 1);
1220 if( isPublic ) content_make_public(fid);
1221 }
1222 db_static_prepare(&s1,
1223 "INSERT INTO mlink(mid,fid,pmid,pid,fnid,pfnid,mperm,isaux)"
1224 "VALUES(:m,:f,:pm,:p,:n,:pfn,:mp,:isaux)"
1225 );
1226 db_bind_int(&s1, ":m", mid);
 
1227 db_bind_int(&s1, ":f", fid);
1228 db_bind_int(&s1, ":pm", pmid);
1229 db_bind_int(&s1, ":p", pid);
1230 db_bind_int(&s1, ":n", fnid);
1231 db_bind_int(&s1, ":pfn", pfnid);
1232 db_bind_int(&s1, ":mp", mperm);
1233 db_bind_int(&s1, ":isaux", isPrimary==0);
1234 db_exec(&s1);
1235 if( pid && fid ){
1236 content_deltify(pid, fid, 0);
1237 }
1238 }
@@ -1342,24 +1346,29 @@
1346 **
1347 ** Deleted files have mlink.fid=0.
1348 ** Added files have mlink.pid=0.
1349 ** Edited files have both mlink.pid!=0 and mlink.fid!=0
1350 */
1351 static void add_mlink(
1352 int pmid, Manifest *pParent, /* Parent check-in */
1353 int mid, Manifest *pChild, /* The child check-in */
1354 int isPrim /* TRUE if pmid is the primary parent of mid */
1355 ){
1356 Blob otherContent;
1357 int otherRid;
1358 int i, rc;
1359 ManifestFile *pChildFile, *pParentFile;
1360 Manifest **ppOther;
1361 static Stmt eq;
1362 int isPublic; /* True if pChild is non-private */
1363
1364 /* If mlink table entires are already exist for the pmid-to-mid transition,
1365 ** then abort early doing no work.
1366 */
1367 db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid AND pmid=:pmid");
1368 db_bind_int(&eq, ":mid", mid);
1369 db_bind_int(&eq, ":pmid", pmid);
1370 rc = db_step(&eq);
1371 db_reset(&eq);
1372 if( rc==SQLITE_ROW ) return;
1373
1374 /* Compute the value of the missing pParent or pChild parameter.
@@ -1366,14 +1375,14 @@
1375 ** Fetch the baseline checkins for both.
1376 */
1377 assert( pParent==0 || pChild==0 );
1378 if( pParent==0 ){
1379 ppOther = &pParent;
1380 otherRid = pmid;
1381 }else{
1382 ppOther = &pChild;
1383 otherRid = mid;
1384 }
1385 if( (*ppOther = manifest_cache_find(otherRid))==0 ){
1386 content_get(otherRid, &otherContent);
1387 if( blob_size(&otherContent)==0 ) return;
1388 *ppOther = manifest_parse(&otherContent, otherRid, 0);
@@ -1381,20 +1390,20 @@
1390 }
1391 if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
1392 manifest_destroy(*ppOther);
1393 return;
1394 }
1395 isPublic = !content_is_private(mid);
1396
1397 /* Try to make the parent manifest a delta from the child, if that
1398 ** is an appropriate thing to do. For a new baseline, make the
1399 ** previous baseline a delta from the current baseline.
1400 */
1401 if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
1402 content_deltify(pmid, mid, 0);
1403 }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
1404 content_deltify(pParent->pBaseline->rid, mid, 0);
1405 }
1406
1407 /* Remember all children less than a few seconds younger than their parent,
1408 ** as we might want to fudge the times for those children.
1409 */
@@ -1414,31 +1423,32 @@
1423 int mperm = manifest_file_mperm(pChildFile);
1424 if( pChildFile->zPrior ){
1425 pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
1426 if( pParentFile ){
1427 /* File with name change */
1428 add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
1429 pChildFile->zName, pChildFile->zPrior,
1430 isPublic, isPrim, mperm);
1431 }else{
1432 /* File name changed, but the old name is not found in the parent!
1433 ** Treat this like a new file. */
1434 add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
1435 isPublic, isPrim, mperm);
1436 }
1437 }else{
1438 pParentFile = manifest_file_seek(pParent, pChildFile->zName, 0);
1439 if( pParentFile==0 ){
1440 if( pChildFile->zUuid ){
1441 /* A new file */
1442 add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
1443 isPublic, isPrim, mperm);
1444 }
1445 }else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0
1446 || manifest_file_mperm(pParentFile)!=mperm ){
1447 /* Changes in file content or permissions */
1448 add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
1449 pChildFile->zName, 0, isPublic, isPrim, mperm);
1450 }
1451 }
1452 }
1453 if( pParent->zBaseline && pChild->zBaseline ){
1454 /* Both parent and child are delta manifests. Look for files that
@@ -1450,22 +1460,22 @@
1460 pChildFile = manifest_file_seek_base(pChild, pParentFile->zName, 0);
1461 if( pChildFile==0 ){
1462 /* The child file reverts to baseline. Show this as a change */
1463 pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
1464 if( pChildFile ){
1465 add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
1466 pChildFile->zName, 0, isPublic, isPrim,
1467 manifest_file_mperm(pChildFile));
1468 }
1469 }
1470 }else{
1471 pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
1472 if( pChildFile ){
1473 /* File resurrected in the child after having been deleted in
1474 ** the parent. Show this as an added file. */
1475 add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
1476 isPublic, isPrim, manifest_file_mperm(pChildFile));
1477 }
1478 }
1479 }
1480 }else if( pChild->zBaseline==0 ){
1481 /* pChild is a baseline. Look for files that are present in pParent
@@ -1472,12 +1482,12 @@
1482 ** but are missing from pChild and mark them as having been deleted. */
1483 manifest_file_rewind(pParent);
1484 while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
1485 pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
1486 if( pChildFile==0 && pParentFile->zUuid!=0 ){
1487 add_one_mlink(pmid, pParentFile->zUuid, mid, 0, pParentFile->zName, 0,
1488 isPublic, isPrim, 0);
1489 }
1490 }
1491 }
1492 manifest_cache_insert(*ppOther);
1493 }
@@ -1781,45 +1791,46 @@
1791 sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
1792 uuid_to_rid(p->zBaseline,1));
1793 }else{
1794 sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
1795 }
 
1796 for(i=0; i<p->nParent; i++){
1797 int pid = uuid_to_rid(p->azParent[i], 1);
1798 db_multi_exec(
1799 "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
1800 "VALUES(%d, %d, %d, %.17g, %s)",
1801 pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);
1802 add_mlink(pid, 0, rid, p, i==0);
1803 if( i==0 ) parentid = pid;
1804 }
1805 if( p->nParent>1 ){
1806 /* Remove incorrect MLINK create-file entries that arise when a
1807 ** file is added by merge. */
1808 db_multi_exec(
1809 "DELETE FROM mlink"
1810 " WHERE mid=%d"
1811 " AND pid=0"
1812 " AND fnid IN "
1813 " (SELECT fnid FROM mlink WHERE mid=%d GROUP BY fnid"
1814 " HAVING count(*)<%d)",
1815 rid, rid, p->nParent
1816 );
1817 }
1818 db_prepare(&q, "SELECT cid, isprim FROM plink WHERE pid=%d", rid);
1819 while( db_step(&q)==SQLITE_ROW ){
1820 int cid = db_column_int(&q, 0);
1821 int isprim = db_column_int(&q, 1);
1822 add_mlink(rid, p, cid, 0, isprim);
1823 }
1824 db_finalize(&q);
1825 if( p->nParent==0 ){
1826 /* For root files (files without parents) add mlink entries
1827 ** showing all content as new. */
1828 int isPublic = !content_is_private(rid);
1829 for(i=0; i<p->nFile; i++){
1830 add_one_mlink(0, 0, rid, p->aFile[i].zUuid, p->aFile[i].zName, 0,
1831 isPublic, 1, manifest_file_mperm(&p->aFile[i]));
1832 }
1833 }
1834 db_multi_exec(
1835 "REPLACE INTO event(type,mtime,objid,user,comment,"
1836 "bgcolor,euser,ecomment,omtime)"
1837
1838 DDED src/markdown.md
--- a/src/markdown.md
+++ b/src/markdown.md
@@ -0,0 +1,224 @@
1
+# Markdown formatting rules
2
+
3
+In addition to its native Wiki formatting syntax, Fossil supports Mark down syntax as specified by
4
+[John Gruber's original Markdown implementation](http://daringfireba
5
+[syntax description](http://daringfireball.net/projects/markdown/syntax), of which the page you
6
+are reading is an extract.
7
+
8
+This page itself uses Markdown formatting.
9
+
10
+## Summary
11
+
12
+ - Block elements
13
+
14
+ * A **paragraph** is a group of consecutive lines. Paragraphs are separated by blank lines.
15
+
16
+ * A **Header** is a line of text underlined with equal signs or hyphens, or prefixed by a
17
+ in s, or prefixed by a
18
+ number of hash marks.
19
+
20
+ * **Block quotes** are blocks of text prefixed by '>'.
21
+
22
+ * **Ordered list** items are prefixed by a number and a period. **Unordered list** items
23
+ are prefixed by a hyphen, asterisk or plus sign. Pre
24
+
25
+ * **Code blocks** are formed by lines of text (possibly including empty lines) prefixed by
26
+ at least 4 spaces or a tab.
27
+
28
+ * A **horizontal rule** is a line consisting of 3 or more asterisks, hyphens or underscores,
29
+ with optional whitespace between them.
30
+
31
+ - Span elements
32
+
33
+ * 3 types of **links** exist:
34
+
35
+ - **automatic links** are URLs or email addresses enclosed in angle brackets
36
+ ('<' and '>'), and are displayed as such.
37
+
38
+ - **inline links** consist of the displayed link text in squ
39
+ followed by the
40
+
41
+ - **reference links** separate _link instance_ from _link definition_. A link instance efinition_. A link instance
42
+ consists of the displayed link text
43
+ in square brackets. in square brackets.
44
+ The corresponding link definition can occur anywhere on the page, and consists
45
+ of the link definition name in s a colon, whitespace and the
46
+ link target.
47
+
48
+ * **Emphasis** can be given by wrapping text in one or two asterisks or underscores - use
49
+ one for HTML `<em>`, and two for `<strong>` emphasis.
50
+
51
+ * A **code span** is text wrapped in backticks ('`').
52
+
53
+ * **Images** use a syntax much like inline or reference links, # Markdown formatting rules
54
+
55
+In addition to its native Wiki formatting syntax, Fossil supports Markdown syntax as specified by
56
+[John Gruber's original Markdown implementation](http://daringfireball.net/projects/markdown/).
57
+For lots of examples - not repeated here - please refer to its
58
+[syntax description](http://daringfireball.net/projects/markdown/syntax), of which the page you
59
+are reading is an extract.
60
+
61
+This page itself uses Markdown formatting.
62
+
63
+## Summary
64
+
65
+ - Block elements
66
+
67
+ * A **paragraph** is a group of consecutive lines. Paragraphs are separated by blank lines.
68
+
69
+ * A **Header** is a line of text underlined with equal signs or hyphens, or prefixed by a
70
+ number of hash marks.
71
+
72
+ * **Block quotes** are blocks of text prefixed by '>'.
73
+
74
+ * **Ordered list** items are prefixed by a number and a period. **Unordered list** items
75
+ are prefixed by a hyphen, asterisk or plus sign. Prefix and item text are separated by
76
+ whitespace.
77
+
78
+ * **Code blocks** are formed by lines of text (possibly including empty lines) prefixed by
79
+ at least 4 spaces or a tab.
80
+
81
+ * A **horizontal rule** is a line consisting of 3 or more asterisks, hyphens or underscores,
82
+ with optional whitespace between them.
83
+
84
+ - Span elements
85
+
86
+ * 3 types of **links** exist:
87
+
88
+ - **automatic links** are URLs or email addresses enclosed in angle brackets
89
+ a * **Emphasis** can be given by wrapping text in one or two asterisks or underscores - use
90
+ one for HTML `<em>`, and two for `<strong>` emphasis.
91
+
92
+ * A **code span** is text wrapped in backticks ('`').
93
+
94
+ * **Images** use a syntax much like inline or reference links, but with alt attribute text
95
+ ('img alt=...') instead of link text, and the first pair of square
96
+ brackets m prefix; the items will be
97
+renumbered during rendering. However, future implementations may
98
+for the first item in a list indicates an offset to be used for subsequent items.
99
+
100
+For list items spanning multiple lines, subsequent lines can be indented using an arbitrary amount
101
+of whitespace.
102
+
103
+List items will be wrapped in HTML `<p>` tags if they are separated by blank lines.
104
+
105
+A list item may span multiple paragraphs. At least the first line
106
+be indented using at least 4 spaces or a tab character.
107
+
108
+Block quotes within list items must have their '>' delimiters indented using 4 up to 7 spaces.
109
+
110
+Code blocks within list items need to be indented _twice_, that is, using 8 spaces or 2 tab
111
+characters.
112
+
113
+### Code blocks
114
+
115
+Lines within a code block are rendered verbatim using HTML `<pre>` and `<code>` tags, except that
116
+HTML punctuation characters like '<' and '&' are automatically converted to HTML entities. Thus,
117
+there is no need to explicitly escape HTML syntax within a code block.
118
+
119
+A code block runs until the first non blank line with indent less than 4 spaces or 1 tab character.
120
+
121
+
122
+Regular Markdown syntax is not processed within code blocks.
123
+
124
+### Links
125
+
126
+#### Automatic links
127
+
128
+When rendering automatic links to email addresses, HTML enco
129
+prevent some spambots from harvesting.
130
+
131
+#### Inline links
132
+
133
+Links to resources on the same server can use relative paths (i.e. can start with a '/').
134
+
135
+An optional title for the link (e.g. to have mouseover text in the b rowser) may be given behind
136
+the link target but within the parentheses, in single and double quo
137
+link target by whitespace.
138
+link target by whitespace.
139
+
140
+# reference link consists of
141
+>
142
+> - one or more _link instances_ at appropriate locations in the page text
143
+> - a single _link definition_ at an arbit
144
+> During rendering, each link instance is resolved, and the corresponding definition is
145
+> filled in. No separate link definition clauses occu r in the rendered output.
146
+>
147
+> There are 3 fields involved in link instances and definitions:
148
+>
149
+> - link text (i.e. the text that is displayed at the resulting link)
150
+> - link definition name (i.e. an unique ID binding link instances to link definition)
151
+> - link target (a target URL for the link)
152
+
153
+Multiple link instances may reference the same link definition using its link definition
154
+name.
155
+
156
+Link definition names are case insensitive, and may contain letters, numbers, spaces and
157
+punctuation.
158
+
159
+##### Link instance
160
+
161
+A space may be inserted between the bracket pairs for link text and link definition name.
162
+
163
+A link instance can use an _implicit link definition name_ shortcut, in which case the link
164
+text is used as the link definition name. The second set of brackets then remains empty, e.g.
165
+'[Google][]' ('Google' being used as both link text and link definition name).
166
+
167
+##### Link definition
168
+
169
+The first bracket pair containing the link definition name may be indented using up to 3 spaces.
170
+
171
+The link target may optionally be surrounded by angle brackets ('<' and '>').
172
+
173
+A link target may be followed by an optional title (e.g. to have mouseover text in the browser).
174
+This title may be enclosed in parentheses, single or double quotes.
175
+
176
+Link definitions may be split into 2 lines, with the title on the second line, arbitrarily
177
+indented. This may be more visually pleasing when using long link targets.
178
+
179
+### Emphasis
180
+
181
+The same character(s) used for starting the emphasis must be used to end it; don't mix
182
+asterisks and underscores.
183
+
184
+Emphasis can be used in the middle of a word. That is, there need not be whitespace on either
185
+side of emphasis start or end punctuation characters.
186
+
187
+### Code spans
188
+
189
+To include a literal backtick character in a code span, use multiple backticks as opening and
190
+closing delimiters.
191
+
192
+Whitespace may exist immediately after the opening delimiter and b Markdown formatting rules
193
+
194
+In addition to its native Wiki formatting syntax, Fossil supports Markdown syntax as specified by
195
+[John Gruber's original Markdown implementation](http://daringfireball.net/projects/markdown/).
196
+For lots of examples - not repeated here - please refer to its
197
+[syntax description](http://daringfireball.net/projects/markdownr
198
+a HTML block level construct (`<div>`, `<table>` etc) must be separated from surrounding
199
+context using blank lines, and must both occur at the start of a line.
200
+
201
+No extra unwanted `<p>` HTML tags are added around HTML block level tags.
202
+
203
+Markdown formatting within HTML block level tags is not processed; however, formatting within
204
+span level tags (e.g. `<mark>`) is processed normally.
205
+
206
+### Escaping Markdown punctuation
207
+
208
+The following punctuation characters can be escaped using backslash:
209
+
210
+ - \\ backslash
211
+ - ` backtick
212
+ - * asterisk
213
+ - _ underscore
214
+ - {} curly braces
215
+ - [] square brackets
216
+ - () parentheses
217
+ - # hash mark
218
+ - + plus sign
219
+ - - minus sign (hyphen)
220
+ - . dot
221
+ - ! exclamation mark
222
+
223
+To render a literal backslash, use 2 backslashes ('\\\\').
224
+
--- a/src/markdown.md
+++ b/src/markdown.md
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/markdown.md
+++ b/src/markdown.md
@@ -0,0 +1,224 @@
1 # Markdown formatting rules
2
3 In addition to its native Wiki formatting syntax, Fossil supports Mark down syntax as specified by
4 [John Gruber's original Markdown implementation](http://daringfireba
5 [syntax description](http://daringfireball.net/projects/markdown/syntax), of which the page you
6 are reading is an extract.
7
8 This page itself uses Markdown formatting.
9
10 ## Summary
11
12 - Block elements
13
14 * A **paragraph** is a group of consecutive lines. Paragraphs are separated by blank lines.
15
16 * A **Header** is a line of text underlined with equal signs or hyphens, or prefixed by a
17 in s, or prefixed by a
18 number of hash marks.
19
20 * **Block quotes** are blocks of text prefixed by '>'.
21
22 * **Ordered list** items are prefixed by a number and a period. **Unordered list** items
23 are prefixed by a hyphen, asterisk or plus sign. Pre
24
25 * **Code blocks** are formed by lines of text (possibly including empty lines) prefixed by
26 at least 4 spaces or a tab.
27
28 * A **horizontal rule** is a line consisting of 3 or more asterisks, hyphens or underscores,
29 with optional whitespace between them.
30
31 - Span elements
32
33 * 3 types of **links** exist:
34
35 - **automatic links** are URLs or email addresses enclosed in angle brackets
36 ('<' and '>'), and are displayed as such.
37
38 - **inline links** consist of the displayed link text in squ
39 followed by the
40
41 - **reference links** separate _link instance_ from _link definition_. A link instance efinition_. A link instance
42 consists of the displayed link text
43 in square brackets. in square brackets.
44 The corresponding link definition can occur anywhere on the page, and consists
45 of the link definition name in s a colon, whitespace and the
46 link target.
47
48 * **Emphasis** can be given by wrapping text in one or two asterisks or underscores - use
49 one for HTML `<em>`, and two for `<strong>` emphasis.
50
51 * A **code span** is text wrapped in backticks ('`').
52
53 * **Images** use a syntax much like inline or reference links, # Markdown formatting rules
54
55 In addition to its native Wiki formatting syntax, Fossil supports Markdown syntax as specified by
56 [John Gruber's original Markdown implementation](http://daringfireball.net/projects/markdown/).
57 For lots of examples - not repeated here - please refer to its
58 [syntax description](http://daringfireball.net/projects/markdown/syntax), of which the page you
59 are reading is an extract.
60
61 This page itself uses Markdown formatting.
62
63 ## Summary
64
65 - Block elements
66
67 * A **paragraph** is a group of consecutive lines. Paragraphs are separated by blank lines.
68
69 * A **Header** is a line of text underlined with equal signs or hyphens, or prefixed by a
70 number of hash marks.
71
72 * **Block quotes** are blocks of text prefixed by '>'.
73
74 * **Ordered list** items are prefixed by a number and a period. **Unordered list** items
75 are prefixed by a hyphen, asterisk or plus sign. Prefix and item text are separated by
76 whitespace.
77
78 * **Code blocks** are formed by lines of text (possibly including empty lines) prefixed by
79 at least 4 spaces or a tab.
80
81 * A **horizontal rule** is a line consisting of 3 or more asterisks, hyphens or underscores,
82 with optional whitespace between them.
83
84 - Span elements
85
86 * 3 types of **links** exist:
87
88 - **automatic links** are URLs or email addresses enclosed in angle brackets
89 a * **Emphasis** can be given by wrapping text in one or two asterisks or underscores - use
90 one for HTML `<em>`, and two for `<strong>` emphasis.
91
92 * A **code span** is text wrapped in backticks ('`').
93
94 * **Images** use a syntax much like inline or reference links, but with alt attribute text
95 ('img alt=...') instead of link text, and the first pair of square
96 brackets m prefix; the items will be
97 renumbered during rendering. However, future implementations may
98 for the first item in a list indicates an offset to be used for subsequent items.
99
100 For list items spanning multiple lines, subsequent lines can be indented using an arbitrary amount
101 of whitespace.
102
103 List items will be wrapped in HTML `<p>` tags if they are separated by blank lines.
104
105 A list item may span multiple paragraphs. At least the first line
106 be indented using at least 4 spaces or a tab character.
107
108 Block quotes within list items must have their '>' delimiters indented using 4 up to 7 spaces.
109
110 Code blocks within list items need to be indented _twice_, that is, using 8 spaces or 2 tab
111 characters.
112
113 ### Code blocks
114
115 Lines within a code block are rendered verbatim using HTML `<pre>` and `<code>` tags, except that
116 HTML punctuation characters like '<' and '&' are automatically converted to HTML entities. Thus,
117 there is no need to explicitly escape HTML syntax within a code block.
118
119 A code block runs until the first non blank line with indent less than 4 spaces or 1 tab character.
120
121
122 Regular Markdown syntax is not processed within code blocks.
123
124 ### Links
125
126 #### Automatic links
127
128 When rendering automatic links to email addresses, HTML enco
129 prevent some spambots from harvesting.
130
131 #### Inline links
132
133 Links to resources on the same server can use relative paths (i.e. can start with a '/').
134
135 An optional title for the link (e.g. to have mouseover text in the b rowser) may be given behind
136 the link target but within the parentheses, in single and double quo
137 link target by whitespace.
138 link target by whitespace.
139
140 # reference link consists of
141 >
142 > - one or more _link instances_ at appropriate locations in the page text
143 > - a single _link definition_ at an arbit
144 > During rendering, each link instance is resolved, and the corresponding definition is
145 > filled in. No separate link definition clauses occu r in the rendered output.
146 >
147 > There are 3 fields involved in link instances and definitions:
148 >
149 > - link text (i.e. the text that is displayed at the resulting link)
150 > - link definition name (i.e. an unique ID binding link instances to link definition)
151 > - link target (a target URL for the link)
152
153 Multiple link instances may reference the same link definition using its link definition
154 name.
155
156 Link definition names are case insensitive, and may contain letters, numbers, spaces and
157 punctuation.
158
159 ##### Link instance
160
161 A space may be inserted between the bracket pairs for link text and link definition name.
162
163 A link instance can use an _implicit link definition name_ shortcut, in which case the link
164 text is used as the link definition name. The second set of brackets then remains empty, e.g.
165 '[Google][]' ('Google' being used as both link text and link definition name).
166
167 ##### Link definition
168
169 The first bracket pair containing the link definition name may be indented using up to 3 spaces.
170
171 The link target may optionally be surrounded by angle brackets ('<' and '>').
172
173 A link target may be followed by an optional title (e.g. to have mouseover text in the browser).
174 This title may be enclosed in parentheses, single or double quotes.
175
176 Link definitions may be split into 2 lines, with the title on the second line, arbitrarily
177 indented. This may be more visually pleasing when using long link targets.
178
179 ### Emphasis
180
181 The same character(s) used for starting the emphasis must be used to end it; don't mix
182 asterisks and underscores.
183
184 Emphasis can be used in the middle of a word. That is, there need not be whitespace on either
185 side of emphasis start or end punctuation characters.
186
187 ### Code spans
188
189 To include a literal backtick character in a code span, use multiple backticks as opening and
190 closing delimiters.
191
192 Whitespace may exist immediately after the opening delimiter and b Markdown formatting rules
193
194 In addition to its native Wiki formatting syntax, Fossil supports Markdown syntax as specified by
195 [John Gruber's original Markdown implementation](http://daringfireball.net/projects/markdown/).
196 For lots of examples - not repeated here - please refer to its
197 [syntax description](http://daringfireball.net/projects/markdownr
198 a HTML block level construct (`<div>`, `<table>` etc) must be separated from surrounding
199 context using blank lines, and must both occur at the start of a line.
200
201 No extra unwanted `<p>` HTML tags are added around HTML block level tags.
202
203 Markdown formatting within HTML block level tags is not processed; however, formatting within
204 span level tags (e.g. `<mark>`) is processed normally.
205
206 ### Escaping Markdown punctuation
207
208 The following punctuation characters can be escaped using backslash:
209
210 - \\ backslash
211 - ` backtick
212 - * asterisk
213 - _ underscore
214 - {} curly braces
215 - [] square brackets
216 - () parentheses
217 - # hash mark
218 - + plus sign
219 - - minus sign (hyphen)
220 - . dot
221 - ! exclamation mark
222
223 To render a literal backslash, use 2 backslashes ('\\\\').
224
+5 -5
--- src/md5.c
+++ src/md5.c
@@ -177,11 +177,11 @@
177177
178178
/*
179179
* Update context to reflect the concatenation of another buffer full
180180
* of bytes.
181181
*/
182
-static
182
+static
183183
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
184184
struct Context *ctx = (struct Context *)pCtx;
185185
uint32 t;
186186
187187
/* Update bitcount */
@@ -224,11 +224,11 @@
224224
225225
memcpy(ctx->in, buf, len);
226226
}
227227
228228
/*
229
- * Final wrapup - pad to 64-byte boundary with the bit pattern
229
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
230230
* 1 0* (64-bit count of bits processed, MSB-first)
231231
*/
232232
static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
233233
struct Context *ctx = (struct Context *)pCtx;
234234
unsigned count;
@@ -274,11 +274,11 @@
274274
** "unsigned char digest[16]" in the calling function. The MD5
275275
** digest is stored in the first 16 bytes. zBuf should
276276
** be "char zBuf[33]".
277277
*/
278278
static void DigestToBase16(unsigned char *digest, char *zBuf){
279
- static char const zEncode[] = "0123456789abcdef";
279
+ static const char zEncode[] = "0123456789abcdef";
280280
int i, j;
281281
282282
for(j=i=0; i<16; i++){
283283
int a = digest[i];
284284
zBuf[j++] = zEncode[(a>>4)&0xf];
@@ -343,11 +343,11 @@
343343
return zResult;
344344
}
345345
346346
/*
347347
** Finish the incremental MD5 checksum. Store the result in blob pOut
348
-** if pOut!=0. Also return a pointer to the result.
348
+** if pOut!=0. Also return a pointer to the result.
349349
**
350350
** This resets the incremental checksum preparing for the next round
351351
** of computation. The return pointer points to a static buffer that
352352
** is overwritten by subsequent calls to this function.
353353
*/
@@ -431,11 +431,11 @@
431431
*/
432432
void md5sum_test(void){
433433
int i;
434434
Blob in;
435435
Blob cksum;
436
-
436
+
437437
for(i=2; i<g.argc; i++){
438438
blob_init(&cksum, "********** not found ***********", -1);
439439
if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
440440
blob_read_from_channel(&in, stdin, -1);
441441
md5sum_blob(&in, &cksum);
442442
--- src/md5.c
+++ src/md5.c
@@ -177,11 +177,11 @@
177
178 /*
179 * Update context to reflect the concatenation of another buffer full
180 * of bytes.
181 */
182 static
183 void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
184 struct Context *ctx = (struct Context *)pCtx;
185 uint32 t;
186
187 /* Update bitcount */
@@ -224,11 +224,11 @@
224
225 memcpy(ctx->in, buf, len);
226 }
227
228 /*
229 * Final wrapup - pad to 64-byte boundary with the bit pattern
230 * 1 0* (64-bit count of bits processed, MSB-first)
231 */
232 static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
233 struct Context *ctx = (struct Context *)pCtx;
234 unsigned count;
@@ -274,11 +274,11 @@
274 ** "unsigned char digest[16]" in the calling function. The MD5
275 ** digest is stored in the first 16 bytes. zBuf should
276 ** be "char zBuf[33]".
277 */
278 static void DigestToBase16(unsigned char *digest, char *zBuf){
279 static char const zEncode[] = "0123456789abcdef";
280 int i, j;
281
282 for(j=i=0; i<16; i++){
283 int a = digest[i];
284 zBuf[j++] = zEncode[(a>>4)&0xf];
@@ -343,11 +343,11 @@
343 return zResult;
344 }
345
346 /*
347 ** Finish the incremental MD5 checksum. Store the result in blob pOut
348 ** if pOut!=0. Also return a pointer to the result.
349 **
350 ** This resets the incremental checksum preparing for the next round
351 ** of computation. The return pointer points to a static buffer that
352 ** is overwritten by subsequent calls to this function.
353 */
@@ -431,11 +431,11 @@
431 */
432 void md5sum_test(void){
433 int i;
434 Blob in;
435 Blob cksum;
436
437 for(i=2; i<g.argc; i++){
438 blob_init(&cksum, "********** not found ***********", -1);
439 if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
440 blob_read_from_channel(&in, stdin, -1);
441 md5sum_blob(&in, &cksum);
442
--- src/md5.c
+++ src/md5.c
@@ -177,11 +177,11 @@
177
178 /*
179 * Update context to reflect the concatenation of another buffer full
180 * of bytes.
181 */
182 static
183 void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
184 struct Context *ctx = (struct Context *)pCtx;
185 uint32 t;
186
187 /* Update bitcount */
@@ -224,11 +224,11 @@
224
225 memcpy(ctx->in, buf, len);
226 }
227
228 /*
229 * Final wrapup - pad to 64-byte boundary with the bit pattern
230 * 1 0* (64-bit count of bits processed, MSB-first)
231 */
232 static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
233 struct Context *ctx = (struct Context *)pCtx;
234 unsigned count;
@@ -274,11 +274,11 @@
274 ** "unsigned char digest[16]" in the calling function. The MD5
275 ** digest is stored in the first 16 bytes. zBuf should
276 ** be "char zBuf[33]".
277 */
278 static void DigestToBase16(unsigned char *digest, char *zBuf){
279 static const char zEncode[] = "0123456789abcdef";
280 int i, j;
281
282 for(j=i=0; i<16; i++){
283 int a = digest[i];
284 zBuf[j++] = zEncode[(a>>4)&0xf];
@@ -343,11 +343,11 @@
343 return zResult;
344 }
345
346 /*
347 ** Finish the incremental MD5 checksum. Store the result in blob pOut
348 ** if pOut!=0. Also return a pointer to the result.
349 **
350 ** This resets the incremental checksum preparing for the next round
351 ** of computation. The return pointer points to a static buffer that
352 ** is overwritten by subsequent calls to this function.
353 */
@@ -431,11 +431,11 @@
431 */
432 void md5sum_test(void){
433 int i;
434 Blob in;
435 Blob cksum;
436
437 for(i=2; i<g.argc; i++){
438 blob_init(&cksum, "********** not found ***********", -1);
439 if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
440 blob_read_from_channel(&in, stdin, -1);
441 md5sum_blob(&in, &cksum);
442
+6 -6
--- src/merge.c
+++ src/merge.c
@@ -41,11 +41,11 @@
4141
if( zTagList && zTagList[0] ){
4242
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
4343
}else{
4444
zCom = mprintf("%s", db_column_text(&q,2));
4545
}
46
- fossil_print("%-*s [%S] by %s on %s\n%*s",
46
+ fossil_print("%-*s [%S] by %s on %s\n%*s",
4747
indent-1, zLabel,
4848
db_column_text(&q, 3),
4949
db_column_text(&q, 1),
5050
db_column_text(&q, 0),
5151
indent, "");
@@ -166,11 +166,11 @@
166166
}else if( g.argc==2 ){
167167
/* No version specified on the command-line so pick the most recent
168168
** leaf that is (1) not the version currently checked out and (2)
169169
** has not already been merged into the current checkout and (3)
170170
** the leaf is not closed and (4) the leaf is in the same branch
171
- ** as the current checkout.
171
+ ** as the current checkout.
172172
*/
173173
Stmt q;
174174
if( pickFlag || backoutFlag || integrateFlag){
175175
fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
176176
}
@@ -472,13 +472,13 @@
472472
undo_save(zName);
473473
vfile_to_disk(0, idm, 0, 0);
474474
}
475475
}
476476
db_finalize(&q);
477
-
477
+
478478
/*
479
- ** Find files that have changed from P->M but not P->V.
479
+ ** Find files that have changed from P->M but not P->V.
480480
** Copy the M content over into V.
481481
*/
482482
db_prepare(&q,
483483
"SELECT idv, ridm, fn, islinkm FROM fv"
484484
" WHERE idp>0 AND idv>0 AND idm>0"
@@ -524,18 +524,18 @@
524524
int rc;
525525
char *zFullPath;
526526
Blob m, p, r;
527527
/* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
528528
if( verboseFlag ){
529
- fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
529
+ fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
530530
zName, ridp, ridm, ridv);
531531
}else{
532532
fossil_print("MERGE %s\n", zName);
533533
}
534534
if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
535535
fossil_print("***** Cannot merge symlink %s\n", zName);
536
- nConflict++;
536
+ nConflict++;
537537
}else{
538538
undo_save(zName);
539539
zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
540540
content_get(ridp, &p);
541541
content_get(ridm, &m);
542542
--- src/merge.c
+++ src/merge.c
@@ -41,11 +41,11 @@
41 if( zTagList && zTagList[0] ){
42 zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
43 }else{
44 zCom = mprintf("%s", db_column_text(&q,2));
45 }
46 fossil_print("%-*s [%S] by %s on %s\n%*s",
47 indent-1, zLabel,
48 db_column_text(&q, 3),
49 db_column_text(&q, 1),
50 db_column_text(&q, 0),
51 indent, "");
@@ -166,11 +166,11 @@
166 }else if( g.argc==2 ){
167 /* No version specified on the command-line so pick the most recent
168 ** leaf that is (1) not the version currently checked out and (2)
169 ** has not already been merged into the current checkout and (3)
170 ** the leaf is not closed and (4) the leaf is in the same branch
171 ** as the current checkout.
172 */
173 Stmt q;
174 if( pickFlag || backoutFlag || integrateFlag){
175 fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
176 }
@@ -472,13 +472,13 @@
472 undo_save(zName);
473 vfile_to_disk(0, idm, 0, 0);
474 }
475 }
476 db_finalize(&q);
477
478 /*
479 ** Find files that have changed from P->M but not P->V.
480 ** Copy the M content over into V.
481 */
482 db_prepare(&q,
483 "SELECT idv, ridm, fn, islinkm FROM fv"
484 " WHERE idp>0 AND idv>0 AND idm>0"
@@ -524,18 +524,18 @@
524 int rc;
525 char *zFullPath;
526 Blob m, p, r;
527 /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
528 if( verboseFlag ){
529 fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
530 zName, ridp, ridm, ridv);
531 }else{
532 fossil_print("MERGE %s\n", zName);
533 }
534 if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
535 fossil_print("***** Cannot merge symlink %s\n", zName);
536 nConflict++;
537 }else{
538 undo_save(zName);
539 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
540 content_get(ridp, &p);
541 content_get(ridm, &m);
542
--- src/merge.c
+++ src/merge.c
@@ -41,11 +41,11 @@
41 if( zTagList && zTagList[0] ){
42 zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
43 }else{
44 zCom = mprintf("%s", db_column_text(&q,2));
45 }
46 fossil_print("%-*s [%S] by %s on %s\n%*s",
47 indent-1, zLabel,
48 db_column_text(&q, 3),
49 db_column_text(&q, 1),
50 db_column_text(&q, 0),
51 indent, "");
@@ -166,11 +166,11 @@
166 }else if( g.argc==2 ){
167 /* No version specified on the command-line so pick the most recent
168 ** leaf that is (1) not the version currently checked out and (2)
169 ** has not already been merged into the current checkout and (3)
170 ** the leaf is not closed and (4) the leaf is in the same branch
171 ** as the current checkout.
172 */
173 Stmt q;
174 if( pickFlag || backoutFlag || integrateFlag){
175 fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
176 }
@@ -472,13 +472,13 @@
472 undo_save(zName);
473 vfile_to_disk(0, idm, 0, 0);
474 }
475 }
476 db_finalize(&q);
477
478 /*
479 ** Find files that have changed from P->M but not P->V.
480 ** Copy the M content over into V.
481 */
482 db_prepare(&q,
483 "SELECT idv, ridm, fn, islinkm FROM fv"
484 " WHERE idp>0 AND idv>0 AND idm>0"
@@ -524,18 +524,18 @@
524 int rc;
525 char *zFullPath;
526 Blob m, p, r;
527 /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
528 if( verboseFlag ){
529 fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
530 zName, ridp, ridm, ridv);
531 }else{
532 fossil_print("MERGE %s\n", zName);
533 }
534 if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
535 fossil_print("***** Cannot merge symlink %s\n", zName);
536 nConflict++;
537 }else{
538 undo_save(zName);
539 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
540 content_get(ridp, &p);
541 content_get(ridm, &m);
542
+32 -13
--- src/mkbuiltin.c
+++ src/mkbuiltin.c
@@ -29,11 +29,11 @@
2929
#include <string.h>
3030
3131
3232
/*
3333
** Read the entire content of the file named zFilename into memory obtained
34
-** from malloc() and retur a pointer to that memory. Write the size of the
34
+** from malloc() and return a pointer to that memory. Write the size of the
3535
** file into *pnByte.
3636
*/
3737
static unsigned char *read_file(const char *zFilename, int *pnByte){
3838
FILE *in;
3939
unsigned char *z;
@@ -62,10 +62,11 @@
6262
*/
6363
typedef struct Resource Resource;
6464
struct Resource {
6565
const char *zName;
6666
int nByte;
67
+ int idx;
6768
};
6869
6970
/*
7071
** Compare two Resource objects for sorting purposes. They sort
7172
** in zName order so that Fossil can search for resources using
@@ -79,14 +80,22 @@
7980
8081
int main(int argc, char **argv){
8182
int i, sz;
8283
int j, n;
8384
Resource *aRes;
84
- int nRes = argc-1;
85
+ int nRes;
8586
unsigned char *pData;
8687
int nErr = 0;
87
-
88
+ int nSkip;
89
+ int nPrefix = 0;
90
+
91
+ if( argc>3 && strcmp(argv[1],"--prefix")==0 ){
92
+ nPrefix = (int)strlen(argv[2]);
93
+ argc -= 2;
94
+ argv += 2;
95
+ }
96
+ nRes = argc - 1;
8897
aRes = malloc( nRes*sizeof(aRes[0]) );
8998
if( aRes==0 ){
9099
fprintf(stderr, "malloc failed\n");
91100
return 1;
92101
}
@@ -103,15 +112,24 @@
103112
if( pData==0 ){
104113
fprintf(stderr, "Cannot open file [%s]\n", aRes[i].zName);
105114
nErr++;
106115
continue;
107116
}
108
- aRes[i].nByte = sz;
117
+
118
+ /* Skip initial lines beginning with # */
119
+ nSkip = 0;
120
+ while( pData[nSkip]=='#' ){
121
+ while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; }
122
+ if( pData[nSkip]=='\n' ) nSkip++;
123
+ }
124
+
125
+ aRes[i].nByte = sz - nSkip;
126
+ aRes[i].idx = i;
109127
printf("/* Content of file %s */\n", aRes[i].zName);
110128
printf("static const unsigned char bidata%d[%d] = {\n ",
111
- i, sz+1);
112
- for(j=n=0; j<=sz; j++){
129
+ i, sz+1-nSkip);
130
+ for(j=nSkip, n=0; j<=sz; j++){
113131
printf("%3d", pData[j]);
114132
if( j==sz ){
115133
printf(" };\n");
116134
}else if( n==14 ){
117135
printf(",\n ");
@@ -129,17 +147,18 @@
129147
printf(" const unsigned char *pData;\n");
130148
printf(" int nByte;\n");
131149
printf("};\n");
132150
printf("static const BuiltinFileTable aBuiltinFiles[] = {\n");
133151
for(i=0; i<nRes; i++){
134
- const char *zTail;
135152
const char *z = aRes[i].zName;
136
- zTail = z;
137
- while( z && z[0] ){
138
- if( z[0]=='/' || z[0]=='\\' ) zTail = &z[1];
139
- z++;
140
- }
141
- printf(" { \"%s\", bidata%d, %d },\n", zTail, i, aRes[i].nByte);
153
+ if( strlen(z)>=nPrefix ) z += nPrefix;
154
+ while( z[0]=='.' || z[0]=='/' ){ z++; }
155
+ aRes[i].zName = z;
156
+ }
157
+ qsort(aRes, nRes, sizeof(aRes[0]), compareResource);
158
+ for(i=0; i<nRes; i++){
159
+ printf(" { \"%s\", bidata%d, %d },\n",
160
+ aRes[i].zName, aRes[i].idx, aRes[i].nByte);
142161
}
143162
printf("};\n");
144163
return nErr;
145164
}
146165
--- src/mkbuiltin.c
+++ src/mkbuiltin.c
@@ -29,11 +29,11 @@
29 #include <string.h>
30
31
32 /*
33 ** Read the entire content of the file named zFilename into memory obtained
34 ** from malloc() and retur a pointer to that memory. Write the size of the
35 ** file into *pnByte.
36 */
37 static unsigned char *read_file(const char *zFilename, int *pnByte){
38 FILE *in;
39 unsigned char *z;
@@ -62,10 +62,11 @@
62 */
63 typedef struct Resource Resource;
64 struct Resource {
65 const char *zName;
66 int nByte;
 
67 };
68
69 /*
70 ** Compare two Resource objects for sorting purposes. They sort
71 ** in zName order so that Fossil can search for resources using
@@ -79,14 +80,22 @@
79
80 int main(int argc, char **argv){
81 int i, sz;
82 int j, n;
83 Resource *aRes;
84 int nRes = argc-1;
85 unsigned char *pData;
86 int nErr = 0;
87
 
 
 
 
 
 
 
 
88 aRes = malloc( nRes*sizeof(aRes[0]) );
89 if( aRes==0 ){
90 fprintf(stderr, "malloc failed\n");
91 return 1;
92 }
@@ -103,15 +112,24 @@
103 if( pData==0 ){
104 fprintf(stderr, "Cannot open file [%s]\n", aRes[i].zName);
105 nErr++;
106 continue;
107 }
108 aRes[i].nByte = sz;
 
 
 
 
 
 
 
 
 
109 printf("/* Content of file %s */\n", aRes[i].zName);
110 printf("static const unsigned char bidata%d[%d] = {\n ",
111 i, sz+1);
112 for(j=n=0; j<=sz; j++){
113 printf("%3d", pData[j]);
114 if( j==sz ){
115 printf(" };\n");
116 }else if( n==14 ){
117 printf(",\n ");
@@ -129,17 +147,18 @@
129 printf(" const unsigned char *pData;\n");
130 printf(" int nByte;\n");
131 printf("};\n");
132 printf("static const BuiltinFileTable aBuiltinFiles[] = {\n");
133 for(i=0; i<nRes; i++){
134 const char *zTail;
135 const char *z = aRes[i].zName;
136 zTail = z;
137 while( z && z[0] ){
138 if( z[0]=='/' || z[0]=='\\' ) zTail = &z[1];
139 z++;
140 }
141 printf(" { \"%s\", bidata%d, %d },\n", zTail, i, aRes[i].nByte);
 
 
142 }
143 printf("};\n");
144 return nErr;
145 }
146
--- src/mkbuiltin.c
+++ src/mkbuiltin.c
@@ -29,11 +29,11 @@
29 #include <string.h>
30
31
32 /*
33 ** Read the entire content of the file named zFilename into memory obtained
34 ** from malloc() and return a pointer to that memory. Write the size of the
35 ** file into *pnByte.
36 */
37 static unsigned char *read_file(const char *zFilename, int *pnByte){
38 FILE *in;
39 unsigned char *z;
@@ -62,10 +62,11 @@
62 */
63 typedef struct Resource Resource;
64 struct Resource {
65 const char *zName;
66 int nByte;
67 int idx;
68 };
69
70 /*
71 ** Compare two Resource objects for sorting purposes. They sort
72 ** in zName order so that Fossil can search for resources using
@@ -79,14 +80,22 @@
80
81 int main(int argc, char **argv){
82 int i, sz;
83 int j, n;
84 Resource *aRes;
85 int nRes;
86 unsigned char *pData;
87 int nErr = 0;
88 int nSkip;
89 int nPrefix = 0;
90
91 if( argc>3 && strcmp(argv[1],"--prefix")==0 ){
92 nPrefix = (int)strlen(argv[2]);
93 argc -= 2;
94 argv += 2;
95 }
96 nRes = argc - 1;
97 aRes = malloc( nRes*sizeof(aRes[0]) );
98 if( aRes==0 ){
99 fprintf(stderr, "malloc failed\n");
100 return 1;
101 }
@@ -103,15 +112,24 @@
112 if( pData==0 ){
113 fprintf(stderr, "Cannot open file [%s]\n", aRes[i].zName);
114 nErr++;
115 continue;
116 }
117
118 /* Skip initial lines beginning with # */
119 nSkip = 0;
120 while( pData[nSkip]=='#' ){
121 while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; }
122 if( pData[nSkip]=='\n' ) nSkip++;
123 }
124
125 aRes[i].nByte = sz - nSkip;
126 aRes[i].idx = i;
127 printf("/* Content of file %s */\n", aRes[i].zName);
128 printf("static const unsigned char bidata%d[%d] = {\n ",
129 i, sz+1-nSkip);
130 for(j=nSkip, n=0; j<=sz; j++){
131 printf("%3d", pData[j]);
132 if( j==sz ){
133 printf(" };\n");
134 }else if( n==14 ){
135 printf(",\n ");
@@ -129,17 +147,18 @@
147 printf(" const unsigned char *pData;\n");
148 printf(" int nByte;\n");
149 printf("};\n");
150 printf("static const BuiltinFileTable aBuiltinFiles[] = {\n");
151 for(i=0; i<nRes; i++){
 
152 const char *z = aRes[i].zName;
153 if( strlen(z)>=nPrefix ) z += nPrefix;
154 while( z[0]=='.' || z[0]=='/' ){ z++; }
155 aRes[i].zName = z;
156 }
157 qsort(aRes, nRes, sizeof(aRes[0]), compareResource);
158 for(i=0; i<nRes; i++){
159 printf(" { \"%s\", bidata%d, %d },\n",
160 aRes[i].zName, aRes[i].idx, aRes[i].nByte);
161 }
162 printf("};\n");
163 return nErr;
164 }
165
+3 -3
--- src/mkindex.c
+++ src/mkindex.c
@@ -217,11 +217,11 @@
217217
if( zLine[i]!='(' ) goto page_skip;
218218
nFixed = nUsed;
219219
nHelp = 0;
220220
return;
221221
222
-page_skip:
222
+page_skip:
223223
for(i=nFixed; i<nUsed; i++){
224224
fprintf(stderr,"%s:%d: skipping page \"%s\"\n",
225225
zFile, nLine, aEntry[i].zPath);
226226
}
227227
nUsed = nFixed;
@@ -327,11 +327,11 @@
327327
aEntry[i].zHelp[0] = 0;
328328
}
329329
}
330330
puts("struct CmdHelp {"
331331
"int eType; "
332
- "char const * zText;"
332
+ "const char *zText;"
333333
"};");
334334
puts("static struct CmdHelp aCmdHelp[] = {");
335335
for(i=0; i<nFixed; i++){
336336
if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
337337
if( aEntry[i].zHelp==0 ){
@@ -361,11 +361,11 @@
361361
scan_for_label("WEBPAGE:",zLine,0);
362362
scan_for_label("COMMAND:",zLine,1);
363363
scan_for_func(zLine);
364364
}
365365
fclose(in);
366
- nUsed = nFixed;
366
+ nUsed = nFixed;
367367
}
368368
369369
int main(int argc, char **argv){
370370
int i;
371371
for(i=1; i<argc; i++){
372372
--- src/mkindex.c
+++ src/mkindex.c
@@ -217,11 +217,11 @@
217 if( zLine[i]!='(' ) goto page_skip;
218 nFixed = nUsed;
219 nHelp = 0;
220 return;
221
222 page_skip:
223 for(i=nFixed; i<nUsed; i++){
224 fprintf(stderr,"%s:%d: skipping page \"%s\"\n",
225 zFile, nLine, aEntry[i].zPath);
226 }
227 nUsed = nFixed;
@@ -327,11 +327,11 @@
327 aEntry[i].zHelp[0] = 0;
328 }
329 }
330 puts("struct CmdHelp {"
331 "int eType; "
332 "char const * zText;"
333 "};");
334 puts("static struct CmdHelp aCmdHelp[] = {");
335 for(i=0; i<nFixed; i++){
336 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
337 if( aEntry[i].zHelp==0 ){
@@ -361,11 +361,11 @@
361 scan_for_label("WEBPAGE:",zLine,0);
362 scan_for_label("COMMAND:",zLine,1);
363 scan_for_func(zLine);
364 }
365 fclose(in);
366 nUsed = nFixed;
367 }
368
369 int main(int argc, char **argv){
370 int i;
371 for(i=1; i<argc; i++){
372
--- src/mkindex.c
+++ src/mkindex.c
@@ -217,11 +217,11 @@
217 if( zLine[i]!='(' ) goto page_skip;
218 nFixed = nUsed;
219 nHelp = 0;
220 return;
221
222 page_skip:
223 for(i=nFixed; i<nUsed; i++){
224 fprintf(stderr,"%s:%d: skipping page \"%s\"\n",
225 zFile, nLine, aEntry[i].zPath);
226 }
227 nUsed = nFixed;
@@ -327,11 +327,11 @@
327 aEntry[i].zHelp[0] = 0;
328 }
329 }
330 puts("struct CmdHelp {"
331 "int eType; "
332 "const char *zText;"
333 "};");
334 puts("static struct CmdHelp aCmdHelp[] = {");
335 for(i=0; i<nFixed; i++){
336 if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
337 if( aEntry[i].zHelp==0 ){
@@ -361,11 +361,11 @@
361 scan_for_label("WEBPAGE:",zLine,0);
362 scan_for_label("COMMAND:",zLine,1);
363 scan_for_func(zLine);
364 }
365 fclose(in);
366 nUsed = nFixed;
367 }
368
369 int main(int argc, char **argv){
370 int i;
371 for(i=1; i<argc; i++){
372
+1 -1
--- src/mkversion.c
+++ src/mkversion.c
@@ -43,11 +43,11 @@
4343
exit(1);
4444
}
4545
fclose(v);
4646
for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
4747
*z = 0;
48
- printf("#define RELEASE_VERSION \"%s\"\n", b);
48
+ printf("#define RELEASE_VERSION \"%s\"\n", b);
4949
x=0;
5050
i=0;
5151
z=b;
5252
while(1){
5353
if( z[0]>='0' && z[0]<='9' ){
5454
--- src/mkversion.c
+++ src/mkversion.c
@@ -43,11 +43,11 @@
43 exit(1);
44 }
45 fclose(v);
46 for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
47 *z = 0;
48 printf("#define RELEASE_VERSION \"%s\"\n", b);
49 x=0;
50 i=0;
51 z=b;
52 while(1){
53 if( z[0]>='0' && z[0]<='9' ){
54
--- src/mkversion.c
+++ src/mkversion.c
@@ -43,11 +43,11 @@
43 exit(1);
44 }
45 fclose(v);
46 for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
47 *z = 0;
48 printf("#define RELEASE_VERSION \"%s\"\n", b);
49 x=0;
50 i=0;
51 z=b;
52 while(1){
53 if( z[0]>='0' && z[0]<='9' ){
54
+1 -1
--- src/publish.c
+++ src/publish.c
@@ -58,11 +58,11 @@
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
** branch, or to publish a bundle that was imported privately.
6262
**
63
-** If any of TAGS names a branch, then all checkins on that most recent
63
+** If any of TAGS names a branch, then all checkins on the most recent
6464
** instance of that branch are included, not just the most recent checkin.
6565
**
6666
** If any of TAGS name checkins then all files and tags associated with
6767
** those checkins are also published automatically. Except if the --only
6868
** option is used, then only the specific artifacts identified by TAGS
6969
--- src/publish.c
+++ src/publish.c
@@ -58,11 +58,11 @@
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 ** branch, or to publish a bundle that was imported privately.
62 **
63 ** If any of TAGS names a branch, then all checkins on that most recent
64 ** instance of that branch are included, not just the most recent checkin.
65 **
66 ** If any of TAGS name checkins then all files and tags associated with
67 ** those checkins are also published automatically. Except if the --only
68 ** option is used, then only the specific artifacts identified by TAGS
69
--- src/publish.c
+++ src/publish.c
@@ -58,11 +58,11 @@
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 ** branch, or to publish a bundle that was imported privately.
62 **
63 ** If any of TAGS names a branch, then all checkins on the most recent
64 ** instance of that branch are included, not just the most recent checkin.
65 **
66 ** If any of TAGS name checkins then all files and tags associated with
67 ** those checkins are also published automatically. Except if the --only
68 ** option is used, then only the specific artifacts identified by TAGS
69
+9 -9
--- src/regexp.c
+++ src/regexp.c
@@ -127,11 +127,11 @@
127127
pSet->aState[pSet->nState++] = newState;
128128
}
129129
130130
/* Extract the next unicode character from *pzIn and return it. Advance
131131
** *pzIn to the first byte past the end of the character returned. To
132
-** be clear: this routine converts utf8 to unicode. This routine is
132
+** be clear: this routine converts utf8 to unicode. This routine is
133133
** optimized for the common case where the next character is a single byte.
134134
*/
135135
static unsigned re_next_char(ReInput *p){
136136
unsigned c;
137137
if( p->i>=p->mx ) return 0;
@@ -191,16 +191,16 @@
191191
int rc = 0;
192192
ReInput in;
193193
194194
in.z = zIn;
195195
in.i = 0;
196
- in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
196
+ in.mx = nIn>=0 ? nIn : strlen((const char*)zIn);
197197
198198
/* Look for the initial prefix match, if there is one. */
199199
if( pRe->nInit ){
200200
unsigned char x = pRe->zInit[0];
201
- while( in.i+pRe->nInit<=in.mx
201
+ while( in.i+pRe->nInit<=in.mx
202202
&& (zIn[in.i]!=x ||
203203
strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
204204
){
205205
in.i++;
206206
}
@@ -303,11 +303,11 @@
303303
}
304304
}
305305
}
306306
if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
307307
if( hit ) re_add_state(pNext, x+n);
308
- break;
308
+ break;
309309
}
310310
}
311311
}
312312
}
313313
for(i=0; i<pNext->nState; i++){
@@ -464,11 +464,11 @@
464464
const char *zErr;
465465
while( (c = p->xNextChar(&p->sIn))!=0 ){
466466
iStart = p->nState;
467467
switch( c ){
468468
case '|':
469
- case '$':
469
+ case '$':
470470
case ')': {
471471
p->sIn.i--;
472472
return 0;
473473
}
474474
case '(': {
@@ -480,11 +480,11 @@
480480
}
481481
case '.': {
482482
if( rePeek(p)=='*' ){
483483
re_append(p, RE_OP_ANYSTAR, 0);
484484
p->sIn.i++;
485
- }else{
485
+ }else{
486486
re_append(p, RE_OP_ANY, 0);
487487
}
488488
break;
489489
}
490490
case '*': {
@@ -652,11 +652,11 @@
652652
}
653653
654654
/* The following is a performance optimization. If the regex begins with
655655
** ".*" (if the input regex lacks an initial "^") and afterwards there are
656656
** one or more matching characters, enter those matching characters into
657
- ** zInit[]. The re_match() routine can then search ahead in the input
657
+ ** zInit[]. The re_match() routine can then search ahead in the input
658658
** string looking for the initial match without having to run the whole
659659
** regex engine over the string. Do not worry able trying to match
660660
** unicode characters beyond plane 0 - those are very rare and this is
661661
** just an optimization. */
662662
if( pRe->aOp[0]==RE_OP_ANYSTAR ){
@@ -689,12 +689,12 @@
689689
** A REGEXP B
690690
**
691691
** is implemented as regexp(B,A).
692692
*/
693693
static void re_sql_func(
694
- sqlite3_context *context,
695
- int argc,
694
+ sqlite3_context *context,
695
+ int argc,
696696
sqlite3_value **argv
697697
){
698698
ReCompiled *pRe; /* Compiled regular expression */
699699
const char *zPattern; /* The regular expression */
700700
const unsigned char *zStr;/* String being searched */
701701
--- src/regexp.c
+++ src/regexp.c
@@ -127,11 +127,11 @@
127 pSet->aState[pSet->nState++] = newState;
128 }
129
130 /* Extract the next unicode character from *pzIn and return it. Advance
131 ** *pzIn to the first byte past the end of the character returned. To
132 ** be clear: this routine converts utf8 to unicode. This routine is
133 ** optimized for the common case where the next character is a single byte.
134 */
135 static unsigned re_next_char(ReInput *p){
136 unsigned c;
137 if( p->i>=p->mx ) return 0;
@@ -191,16 +191,16 @@
191 int rc = 0;
192 ReInput in;
193
194 in.z = zIn;
195 in.i = 0;
196 in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
197
198 /* Look for the initial prefix match, if there is one. */
199 if( pRe->nInit ){
200 unsigned char x = pRe->zInit[0];
201 while( in.i+pRe->nInit<=in.mx
202 && (zIn[in.i]!=x ||
203 strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
204 ){
205 in.i++;
206 }
@@ -303,11 +303,11 @@
303 }
304 }
305 }
306 if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
307 if( hit ) re_add_state(pNext, x+n);
308 break;
309 }
310 }
311 }
312 }
313 for(i=0; i<pNext->nState; i++){
@@ -464,11 +464,11 @@
464 const char *zErr;
465 while( (c = p->xNextChar(&p->sIn))!=0 ){
466 iStart = p->nState;
467 switch( c ){
468 case '|':
469 case '$':
470 case ')': {
471 p->sIn.i--;
472 return 0;
473 }
474 case '(': {
@@ -480,11 +480,11 @@
480 }
481 case '.': {
482 if( rePeek(p)=='*' ){
483 re_append(p, RE_OP_ANYSTAR, 0);
484 p->sIn.i++;
485 }else{
486 re_append(p, RE_OP_ANY, 0);
487 }
488 break;
489 }
490 case '*': {
@@ -652,11 +652,11 @@
652 }
653
654 /* The following is a performance optimization. If the regex begins with
655 ** ".*" (if the input regex lacks an initial "^") and afterwards there are
656 ** one or more matching characters, enter those matching characters into
657 ** zInit[]. The re_match() routine can then search ahead in the input
658 ** string looking for the initial match without having to run the whole
659 ** regex engine over the string. Do not worry able trying to match
660 ** unicode characters beyond plane 0 - those are very rare and this is
661 ** just an optimization. */
662 if( pRe->aOp[0]==RE_OP_ANYSTAR ){
@@ -689,12 +689,12 @@
689 ** A REGEXP B
690 **
691 ** is implemented as regexp(B,A).
692 */
693 static void re_sql_func(
694 sqlite3_context *context,
695 int argc,
696 sqlite3_value **argv
697 ){
698 ReCompiled *pRe; /* Compiled regular expression */
699 const char *zPattern; /* The regular expression */
700 const unsigned char *zStr;/* String being searched */
701
--- src/regexp.c
+++ src/regexp.c
@@ -127,11 +127,11 @@
127 pSet->aState[pSet->nState++] = newState;
128 }
129
130 /* Extract the next unicode character from *pzIn and return it. Advance
131 ** *pzIn to the first byte past the end of the character returned. To
132 ** be clear: this routine converts utf8 to unicode. This routine is
133 ** optimized for the common case where the next character is a single byte.
134 */
135 static unsigned re_next_char(ReInput *p){
136 unsigned c;
137 if( p->i>=p->mx ) return 0;
@@ -191,16 +191,16 @@
191 int rc = 0;
192 ReInput in;
193
194 in.z = zIn;
195 in.i = 0;
196 in.mx = nIn>=0 ? nIn : strlen((const char*)zIn);
197
198 /* Look for the initial prefix match, if there is one. */
199 if( pRe->nInit ){
200 unsigned char x = pRe->zInit[0];
201 while( in.i+pRe->nInit<=in.mx
202 && (zIn[in.i]!=x ||
203 strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
204 ){
205 in.i++;
206 }
@@ -303,11 +303,11 @@
303 }
304 }
305 }
306 if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
307 if( hit ) re_add_state(pNext, x+n);
308 break;
309 }
310 }
311 }
312 }
313 for(i=0; i<pNext->nState; i++){
@@ -464,11 +464,11 @@
464 const char *zErr;
465 while( (c = p->xNextChar(&p->sIn))!=0 ){
466 iStart = p->nState;
467 switch( c ){
468 case '|':
469 case '$':
470 case ')': {
471 p->sIn.i--;
472 return 0;
473 }
474 case '(': {
@@ -480,11 +480,11 @@
480 }
481 case '.': {
482 if( rePeek(p)=='*' ){
483 re_append(p, RE_OP_ANYSTAR, 0);
484 p->sIn.i++;
485 }else{
486 re_append(p, RE_OP_ANY, 0);
487 }
488 break;
489 }
490 case '*': {
@@ -652,11 +652,11 @@
652 }
653
654 /* The following is a performance optimization. If the regex begins with
655 ** ".*" (if the input regex lacks an initial "^") and afterwards there are
656 ** one or more matching characters, enter those matching characters into
657 ** zInit[]. The re_match() routine can then search ahead in the input
658 ** string looking for the initial match without having to run the whole
659 ** regex engine over the string. Do not worry able trying to match
660 ** unicode characters beyond plane 0 - those are very rare and this is
661 ** just an optimization. */
662 if( pRe->aOp[0]==RE_OP_ANYSTAR ){
@@ -689,12 +689,12 @@
689 ** A REGEXP B
690 **
691 ** is implemented as regexp(B,A).
692 */
693 static void re_sql_func(
694 sqlite3_context *context,
695 int argc,
696 sqlite3_value **argv
697 ){
698 ReCompiled *pRe; /* Compiled regular expression */
699 const char *zPattern; /* The regular expression */
700 const unsigned char *zStr;/* String being searched */
701
+89 -30
--- src/report.c
+++ src/report.c
@@ -171,10 +171,11 @@
171171
/* We've already seen an error. No need to continue. */
172172
return SQLITE_OK;
173173
}
174174
switch( code ){
175175
case SQLITE_SELECT:
176
+ case SQLITE_RECURSIVE:
176177
case SQLITE_FUNCTION: {
177178
break;
178179
}
179180
case SQLITE_READ: {
180181
static const char *const azAllowed[] = {
@@ -201,15 +202,10 @@
201202
}else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
202203
rc = SQLITE_IGNORE;
203204
}
204205
break;
205206
}
206
- case SQLITE_RECURSIVE: {
207
- *(char**)pError = mprintf("recursive queries are not allowed");
208
- rc = SQLITE_DENY;
209
- break;
210
- }
211207
default: {
212208
*(char**)pError = mprintf("only SELECT statements are allowed");
213209
rc = SQLITE_DENY;
214210
break;
215211
}
@@ -240,15 +236,17 @@
240236
const char *zTail;
241237
sqlite3_stmt *pStmt;
242238
int rc;
243239
244240
/* First make sure the SQL is a single query command by verifying that
245
- ** the first token is "SELECT" and that there are no unquoted semicolons.
241
+ ** the first token is "SELECT" or "WITH" and that there are no unquoted
242
+ ** semicolons.
246243
*/
247244
for(i=0; fossil_isspace(zSql[i]); i++){}
248
- if( fossil_strnicmp(&zSql[i],"select",6)!=0 ){
249
- return mprintf("The SQL must be a SELECT statement");
245
+ if( fossil_strnicmp(&zSql[i], "select", 6)!=0
246
+ && fossil_strnicmp(&zSql[i], "with", 4)!=0 ){
247
+ return mprintf("The SQL must be a SELECT or WITH statement");
250248
}
251249
for(i=0; zSql[i]; i++){
252250
if( zSql[i]==';' ){
253251
int bad;
254252
int c = zSql[i+1];
@@ -922,79 +920,140 @@
922920
923921
/*
924922
** Output Javascript code that will enables sorting of the table with
925923
** the id zTableId by clicking.
926924
**
927
-** The javascript is derived from:
925
+** The javascript was originally derived from:
928926
**
929927
** http://www.webtoolkit.info/sortable-html-table.html
928
+**
929
+** But there have been extensive modifications.
930930
**
931931
** This variation allows column types to be expressed using the second
932932
** argument. Each character of the second argument represent a column.
933
-** "t" means sort as text. "n" means sort numerically. "x" means do not
934
-** sort on this column. If there are fewer characters in zColumnTypes[] than
935
-** their are columns, the all extra columns assume type "t" (text).
933
+**
934
+** t Sort by text
935
+** n Sort numerically
936
+** k Sort by the data-sortkey property
937
+** x This column is not sortable
938
+**
939
+** Capital letters mean sort in reverse order.
940
+** If there are fewer characters in zColumnTypes[] than their are columns,
941
+** the all extra columns assume type "t" (text).
942
+**
943
+** The third parameter is the column that was initially sorted (using 1-based
944
+** column numbers, like SQL). Make this value 0 if none of the columns are
945
+** initially sorted. Make the value negative if the column is initially sorted
946
+** in reverse order.
947
+**
948
+** Clicking on the same column header twice in a row inverts the sort.
936949
*/
937
-void output_table_sorting_javascript(const char *zTableId, const char *zColumnTypes){
950
+void output_table_sorting_javascript(
951
+ const char *zTableId, /* ID of table to sort */
952
+ const char *zColumnTypes, /* String for column types */
953
+ int iInitSort /* Initially sorted column. Leftmost is 1. 0 for NONE */
954
+){
938955
@ <script>
939
- @ function SortableTable(tableEl,columnTypes){
956
+ @ function SortableTable(tableEl,columnTypes,initSort){
940957
@ this.tbody = tableEl.getElementsByTagName('tbody');
958
+ @ this.columnTypes = columnTypes;
941959
@ this.sort = function (cell) {
942960
@ var column = cell.cellIndex;
943
- @ var sortFn = cell.sortType=="n" ? this.sortNumeric : this.sortText;
961
+ @ var sortFn;
962
+ @ switch( cell.sortType ){
963
+ @ case "N": case "n": sortFn = this.sortNumeric; break;
964
+ @ case "T": case "t": sortFn = this.sortText; break;
965
+ @ case "K": case "k": sortFn = this.sortKey; break;
966
+ @ default: return;
967
+ @ }
944968
@ this.sortIndex = column;
945969
@ var newRows = new Array();
946970
@ for (j = 0; j < this.tbody[0].rows.length; j++) {
947971
@ newRows[j] = this.tbody[0].rows[j];
948972
@ }
949
- @ newRows.sort(sortFn);
950
- @ if (cell.getAttribute("sortdir") == 'down') {
951
- @ newRows.reverse();
952
- @ cell.setAttribute('sortdir','up');
953
- @ } else {
954
- @ cell.setAttribute('sortdir','down');
973
+ @ if( this.sortIndex==Math.abs(this.prevColumn)-1 ){
974
+ @ newRows.reverse();
975
+ @ this.prevColumn = -this.prevColumn;
976
+ @ }else{
977
+ @ newRows.sort(sortFn);
978
+ @ this.prevColumn = this.sortIndex+1;
979
+ @ if( cell.sortType>="A" && cell.sortType<="Z" ){
980
+ @ newRows.reverse();
981
+ @ }
955982
@ }
956983
@ for (i=0;i<newRows.length;i++) {
957984
@ this.tbody[0].appendChild(newRows[i]);
958985
@ }
986
+ @ this.setHdrIcons();
987
+ @ }
988
+ @ this.setHdrIcons = function() {
989
+ @ for (var i=0; i<this.hdrRow.cells.length; i++) {
990
+ @ if( this.columnTypes[i]=='x' ) continue;
991
+ @ var sortType;
992
+ @ if( this.prevColumn==i+1 ){
993
+ @ sortType = 'asc';
994
+ @ }else if( this.prevColumn==(-1-i) ){
995
+ @ sortType = 'desc'
996
+ @ }else{
997
+ @ sortType = 'none';
998
+ @ }
999
+ @ var hdrCell = this.hdrRow.cells[i];
1000
+ @ var clsName = hdrCell.className.replace(/\s*\bsort\s*\w+/, '');
1001
+ @ clsName += ' sort ' + sortType;
1002
+ @ hdrCell.className = clsName;
1003
+ @ }
9591004
@ }
9601005
@ this.sortText = function(a,b) {
9611006
@ var i = thisObject.sortIndex;
9621007
@ aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
9631008
@ bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
964
- @ if(aa==bb) return 0;
1009
+ @ if(aa==bb) return a.rowIndex-b.rowIndex;
9651010
@ if(aa<bb) return -1;
9661011
@ return 1;
9671012
@ }
9681013
@ this.sortNumeric = function(a,b) {
9691014
@ var i = thisObject.sortIndex;
9701015
@ aa = parseFloat(a.cells[i].textContent);
9711016
@ if (isNaN(aa)) aa = 0;
9721017
@ bb = parseFloat(b.cells[i].textContent);
9731018
@ if (isNaN(bb)) bb = 0;
1019
+ @ if(aa==bb) return a.rowIndex-b.rowIndex;
9741020
@ return aa-bb;
9751021
@ }
976
- @ var thisObject = this;
1022
+ @ this.sortKey = function(a,b) {
1023
+ @ var i = thisObject.sortIndex;
1024
+ @ aa = a.cells[i].getAttribute("data-sortkey");
1025
+ @ bb = b.cells[i].getAttribute("data-sortkey");
1026
+ @ if(aa==bb) return a.rowIndex-b.rowIndex;
1027
+ @ if(aa<bb) return -1;
1028
+ @ return 1;
1029
+ @ }
9771030
@ var x = tableEl.getElementsByTagName('thead');
9781031
@ if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
9791032
@ return;
9801033
@ }
9811034
@ if(x && x[0].rows && x[0].rows.length > 0) {
982
- @ var sortRow = x[0].rows[0];
1035
+ @ this.hdrRow = x[0].rows[0];
9831036
@ } else {
9841037
@ return;
9851038
@ }
986
- @ for (var i=0; i<sortRow.cells.length; i++) {
987
- @ sortRow.cells[i].sTable = this;
988
- @ sortRow.cells[i].sortType = columnTypes[i] || 't';
989
- @ sortRow.cells[i].onclick = function () {
1039
+ @ var thisObject = this;
1040
+ @ this.prevColumn = initSort;
1041
+ @ for (var i=0; i<this.hdrRow.cells.length; i++) {
1042
+ @ if( columnTypes[i]=='x' ) continue;
1043
+ @ var hdrcell = this.hdrRow.cells[i];
1044
+ @ hdrcell.sTable = this;
1045
+ @ hdrcell.style.cursor = "pointer";
1046
+ @ hdrcell.sortType = columnTypes[i] || 't';
1047
+ @ hdrcell.onclick = function () {
9901048
@ this.sTable.sort(this);
9911049
@ return false;
9921050
@ }
9931051
@ }
1052
+ @ this.setHdrIcons()
9941053
@ }
995
- @ var t = new SortableTable(gebi("%s(zTableId)"),"%s(zColumnTypes)");
1054
+ @ var t = new SortableTable(gebi("%s(zTableId)"),"%s(zColumnTypes)",%d(iInitSort));
9961055
@ </script>
9971056
}
9981057
9991058
10001059
/*
@@ -1086,11 +1145,11 @@
10861145
if( zErr1 ){
10871146
@ <p class="reportError">Error: %h(zErr1)</p>
10881147
}else if( zErr2 ){
10891148
@ <p class="reportError">Error: %h(zErr2)</p>
10901149
}
1091
- output_table_sorting_javascript("reportTable","");
1150
+ output_table_sorting_javascript("reportTable","",0);
10921151
style_footer();
10931152
}else{
10941153
report_restrict_sql(&zErr1);
10951154
db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
10961155
report_unrestrict_sql();
10971156
--- src/report.c
+++ src/report.c
@@ -171,10 +171,11 @@
171 /* We've already seen an error. No need to continue. */
172 return SQLITE_OK;
173 }
174 switch( code ){
175 case SQLITE_SELECT:
 
176 case SQLITE_FUNCTION: {
177 break;
178 }
179 case SQLITE_READ: {
180 static const char *const azAllowed[] = {
@@ -201,15 +202,10 @@
201 }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
202 rc = SQLITE_IGNORE;
203 }
204 break;
205 }
206 case SQLITE_RECURSIVE: {
207 *(char**)pError = mprintf("recursive queries are not allowed");
208 rc = SQLITE_DENY;
209 break;
210 }
211 default: {
212 *(char**)pError = mprintf("only SELECT statements are allowed");
213 rc = SQLITE_DENY;
214 break;
215 }
@@ -240,15 +236,17 @@
240 const char *zTail;
241 sqlite3_stmt *pStmt;
242 int rc;
243
244 /* First make sure the SQL is a single query command by verifying that
245 ** the first token is "SELECT" and that there are no unquoted semicolons.
 
246 */
247 for(i=0; fossil_isspace(zSql[i]); i++){}
248 if( fossil_strnicmp(&zSql[i],"select",6)!=0 ){
249 return mprintf("The SQL must be a SELECT statement");
 
250 }
251 for(i=0; zSql[i]; i++){
252 if( zSql[i]==';' ){
253 int bad;
254 int c = zSql[i+1];
@@ -922,79 +920,140 @@
922
923 /*
924 ** Output Javascript code that will enables sorting of the table with
925 ** the id zTableId by clicking.
926 **
927 ** The javascript is derived from:
928 **
929 ** http://www.webtoolkit.info/sortable-html-table.html
 
 
930 **
931 ** This variation allows column types to be expressed using the second
932 ** argument. Each character of the second argument represent a column.
933 ** "t" means sort as text. "n" means sort numerically. "x" means do not
934 ** sort on this column. If there are fewer characters in zColumnTypes[] than
935 ** their are columns, the all extra columns assume type "t" (text).
 
 
 
 
 
 
 
 
 
 
 
 
 
936 */
937 void output_table_sorting_javascript(const char *zTableId, const char *zColumnTypes){
 
 
 
 
938 @ <script>
939 @ function SortableTable(tableEl,columnTypes){
940 @ this.tbody = tableEl.getElementsByTagName('tbody');
 
941 @ this.sort = function (cell) {
942 @ var column = cell.cellIndex;
943 @ var sortFn = cell.sortType=="n" ? this.sortNumeric : this.sortText;
 
 
 
 
 
 
944 @ this.sortIndex = column;
945 @ var newRows = new Array();
946 @ for (j = 0; j < this.tbody[0].rows.length; j++) {
947 @ newRows[j] = this.tbody[0].rows[j];
948 @ }
949 @ newRows.sort(sortFn);
950 @ if (cell.getAttribute("sortdir") == 'down') {
951 @ newRows.reverse();
952 @ cell.setAttribute('sortdir','up');
953 @ } else {
954 @ cell.setAttribute('sortdir','down');
 
 
 
955 @ }
956 @ for (i=0;i<newRows.length;i++) {
957 @ this.tbody[0].appendChild(newRows[i]);
958 @ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959 @ }
960 @ this.sortText = function(a,b) {
961 @ var i = thisObject.sortIndex;
962 @ aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
963 @ bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
964 @ if(aa==bb) return 0;
965 @ if(aa<bb) return -1;
966 @ return 1;
967 @ }
968 @ this.sortNumeric = function(a,b) {
969 @ var i = thisObject.sortIndex;
970 @ aa = parseFloat(a.cells[i].textContent);
971 @ if (isNaN(aa)) aa = 0;
972 @ bb = parseFloat(b.cells[i].textContent);
973 @ if (isNaN(bb)) bb = 0;
 
974 @ return aa-bb;
975 @ }
976 @ var thisObject = this;
 
 
 
 
 
 
 
977 @ var x = tableEl.getElementsByTagName('thead');
978 @ if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
979 @ return;
980 @ }
981 @ if(x && x[0].rows && x[0].rows.length > 0) {
982 @ var sortRow = x[0].rows[0];
983 @ } else {
984 @ return;
985 @ }
986 @ for (var i=0; i<sortRow.cells.length; i++) {
987 @ sortRow.cells[i].sTable = this;
988 @ sortRow.cells[i].sortType = columnTypes[i] || 't';
989 @ sortRow.cells[i].onclick = function () {
 
 
 
 
 
990 @ this.sTable.sort(this);
991 @ return false;
992 @ }
993 @ }
 
994 @ }
995 @ var t = new SortableTable(gebi("%s(zTableId)"),"%s(zColumnTypes)");
996 @ </script>
997 }
998
999
1000 /*
@@ -1086,11 +1145,11 @@
1086 if( zErr1 ){
1087 @ <p class="reportError">Error: %h(zErr1)</p>
1088 }else if( zErr2 ){
1089 @ <p class="reportError">Error: %h(zErr2)</p>
1090 }
1091 output_table_sorting_javascript("reportTable","");
1092 style_footer();
1093 }else{
1094 report_restrict_sql(&zErr1);
1095 db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
1096 report_unrestrict_sql();
1097
--- src/report.c
+++ src/report.c
@@ -171,10 +171,11 @@
171 /* We've already seen an error. No need to continue. */
172 return SQLITE_OK;
173 }
174 switch( code ){
175 case SQLITE_SELECT:
176 case SQLITE_RECURSIVE:
177 case SQLITE_FUNCTION: {
178 break;
179 }
180 case SQLITE_READ: {
181 static const char *const azAllowed[] = {
@@ -201,15 +202,10 @@
202 }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
203 rc = SQLITE_IGNORE;
204 }
205 break;
206 }
 
 
 
 
 
207 default: {
208 *(char**)pError = mprintf("only SELECT statements are allowed");
209 rc = SQLITE_DENY;
210 break;
211 }
@@ -240,15 +236,17 @@
236 const char *zTail;
237 sqlite3_stmt *pStmt;
238 int rc;
239
240 /* First make sure the SQL is a single query command by verifying that
241 ** the first token is "SELECT" or "WITH" and that there are no unquoted
242 ** semicolons.
243 */
244 for(i=0; fossil_isspace(zSql[i]); i++){}
245 if( fossil_strnicmp(&zSql[i], "select", 6)!=0
246 && fossil_strnicmp(&zSql[i], "with", 4)!=0 ){
247 return mprintf("The SQL must be a SELECT or WITH statement");
248 }
249 for(i=0; zSql[i]; i++){
250 if( zSql[i]==';' ){
251 int bad;
252 int c = zSql[i+1];
@@ -922,79 +920,140 @@
920
921 /*
922 ** Output Javascript code that will enables sorting of the table with
923 ** the id zTableId by clicking.
924 **
925 ** The javascript was originally derived from:
926 **
927 ** http://www.webtoolkit.info/sortable-html-table.html
928 **
929 ** But there have been extensive modifications.
930 **
931 ** This variation allows column types to be expressed using the second
932 ** argument. Each character of the second argument represent a column.
933 **
934 ** t Sort by text
935 ** n Sort numerically
936 ** k Sort by the data-sortkey property
937 ** x This column is not sortable
938 **
939 ** Capital letters mean sort in reverse order.
940 ** If there are fewer characters in zColumnTypes[] than their are columns,
941 ** the all extra columns assume type "t" (text).
942 **
943 ** The third parameter is the column that was initially sorted (using 1-based
944 ** column numbers, like SQL). Make this value 0 if none of the columns are
945 ** initially sorted. Make the value negative if the column is initially sorted
946 ** in reverse order.
947 **
948 ** Clicking on the same column header twice in a row inverts the sort.
949 */
950 void output_table_sorting_javascript(
951 const char *zTableId, /* ID of table to sort */
952 const char *zColumnTypes, /* String for column types */
953 int iInitSort /* Initially sorted column. Leftmost is 1. 0 for NONE */
954 ){
955 @ <script>
956 @ function SortableTable(tableEl,columnTypes,initSort){
957 @ this.tbody = tableEl.getElementsByTagName('tbody');
958 @ this.columnTypes = columnTypes;
959 @ this.sort = function (cell) {
960 @ var column = cell.cellIndex;
961 @ var sortFn;
962 @ switch( cell.sortType ){
963 @ case "N": case "n": sortFn = this.sortNumeric; break;
964 @ case "T": case "t": sortFn = this.sortText; break;
965 @ case "K": case "k": sortFn = this.sortKey; break;
966 @ default: return;
967 @ }
968 @ this.sortIndex = column;
969 @ var newRows = new Array();
970 @ for (j = 0; j < this.tbody[0].rows.length; j++) {
971 @ newRows[j] = this.tbody[0].rows[j];
972 @ }
973 @ if( this.sortIndex==Math.abs(this.prevColumn)-1 ){
974 @ newRows.reverse();
975 @ this.prevColumn = -this.prevColumn;
976 @ }else{
977 @ newRows.sort(sortFn);
978 @ this.prevColumn = this.sortIndex+1;
979 @ if( cell.sortType>="A" && cell.sortType<="Z" ){
980 @ newRows.reverse();
981 @ }
982 @ }
983 @ for (i=0;i<newRows.length;i++) {
984 @ this.tbody[0].appendChild(newRows[i]);
985 @ }
986 @ this.setHdrIcons();
987 @ }
988 @ this.setHdrIcons = function() {
989 @ for (var i=0; i<this.hdrRow.cells.length; i++) {
990 @ if( this.columnTypes[i]=='x' ) continue;
991 @ var sortType;
992 @ if( this.prevColumn==i+1 ){
993 @ sortType = 'asc';
994 @ }else if( this.prevColumn==(-1-i) ){
995 @ sortType = 'desc'
996 @ }else{
997 @ sortType = 'none';
998 @ }
999 @ var hdrCell = this.hdrRow.cells[i];
1000 @ var clsName = hdrCell.className.replace(/\s*\bsort\s*\w+/, '');
1001 @ clsName += ' sort ' + sortType;
1002 @ hdrCell.className = clsName;
1003 @ }
1004 @ }
1005 @ this.sortText = function(a,b) {
1006 @ var i = thisObject.sortIndex;
1007 @ aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
1008 @ bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
1009 @ if(aa==bb) return a.rowIndex-b.rowIndex;
1010 @ if(aa<bb) return -1;
1011 @ return 1;
1012 @ }
1013 @ this.sortNumeric = function(a,b) {
1014 @ var i = thisObject.sortIndex;
1015 @ aa = parseFloat(a.cells[i].textContent);
1016 @ if (isNaN(aa)) aa = 0;
1017 @ bb = parseFloat(b.cells[i].textContent);
1018 @ if (isNaN(bb)) bb = 0;
1019 @ if(aa==bb) return a.rowIndex-b.rowIndex;
1020 @ return aa-bb;
1021 @ }
1022 @ this.sortKey = function(a,b) {
1023 @ var i = thisObject.sortIndex;
1024 @ aa = a.cells[i].getAttribute("data-sortkey");
1025 @ bb = b.cells[i].getAttribute("data-sortkey");
1026 @ if(aa==bb) return a.rowIndex-b.rowIndex;
1027 @ if(aa<bb) return -1;
1028 @ return 1;
1029 @ }
1030 @ var x = tableEl.getElementsByTagName('thead');
1031 @ if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
1032 @ return;
1033 @ }
1034 @ if(x && x[0].rows && x[0].rows.length > 0) {
1035 @ this.hdrRow = x[0].rows[0];
1036 @ } else {
1037 @ return;
1038 @ }
1039 @ var thisObject = this;
1040 @ this.prevColumn = initSort;
1041 @ for (var i=0; i<this.hdrRow.cells.length; i++) {
1042 @ if( columnTypes[i]=='x' ) continue;
1043 @ var hdrcell = this.hdrRow.cells[i];
1044 @ hdrcell.sTable = this;
1045 @ hdrcell.style.cursor = "pointer";
1046 @ hdrcell.sortType = columnTypes[i] || 't';
1047 @ hdrcell.onclick = function () {
1048 @ this.sTable.sort(this);
1049 @ return false;
1050 @ }
1051 @ }
1052 @ this.setHdrIcons()
1053 @ }
1054 @ var t = new SortableTable(gebi("%s(zTableId)"),"%s(zColumnTypes)",%d(iInitSort));
1055 @ </script>
1056 }
1057
1058
1059 /*
@@ -1086,11 +1145,11 @@
1145 if( zErr1 ){
1146 @ <p class="reportError">Error: %h(zErr1)</p>
1147 }else if( zErr2 ){
1148 @ <p class="reportError">Error: %h(zErr2)</p>
1149 }
1150 output_table_sorting_javascript("reportTable","",0);
1151 style_footer();
1152 }else{
1153 report_restrict_sql(&zErr1);
1154 db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
1155 report_unrestrict_sql();
1156
+35 -12
--- src/schema.c
+++ src/schema.c
@@ -12,11 +12,11 @@
1212
** Author contact information:
1313
** [email protected]
1414
** http://www.hwaci.com/drh/
1515
**
1616
*******************************************************************************
17
-**
17
+**
1818
** This file contains string constants that implement the database schema.
1919
*/
2020
#include "config.h"
2121
#include "schema.h"
2222
@@ -45,11 +45,14 @@
4545
** we have to execute special procedures to update the schema. When
4646
** the aux schema changes, all we need to do is rebuild the database.
4747
*/
4848
#define CONTENT_SCHEMA "2"
4949
#define AUX_SCHEMA_MIN "2011-04-25 19:50"
50
-#define AUX_SCHEMA_MAX "2014-11-24 20:35"
50
+#define AUX_SCHEMA_MAX "2015-01-24"
51
+/* NB: Some features require the latest schema. Warning or error messages
52
+** will appear if an older schema is used. However, the older schemas are
53
+** adequate for many common functions. */
5154
5255
#endif /* INTERFACE */
5356
5457
5558
/*
@@ -81,11 +84,11 @@
8184
@ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content
8285
@ content BLOB, -- Compressed content of this record
8386
@ CHECK( length(uuid)==40 AND rid>0 )
8487
@ );
8588
@ CREATE TABLE delta(
86
-@ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
89
+@ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
8790
@ srcid INTEGER NOT NULL REFERENCES blob -- Baseline for delta-compression
8891
@ );
8992
@ CREATE INDEX delta_i1 ON delta(srcid);
9093
@
9194
@ -------------------------------------------------------------------------
@@ -126,11 +129,11 @@
126129
@ info TEXT, -- contact information
127130
@ mtime DATE, -- last change. seconds since 1970
128131
@ photo BLOB -- JPEG image of this user
129132
@ );
130133
@
131
-@ -- The VAR table holds miscellanous information about the repository.
134
+@ -- The config table holds miscellanous information about the repository.
132135
@ -- in the form of name-value pairs.
133136
@ --
134137
@ CREATE TABLE config(
135138
@ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
136139
@ value CLOB, -- Content of the named parameter
@@ -227,21 +230,41 @@
227230
@ name TEXT UNIQUE -- Name of file page
228231
@ );
229232
@
230233
@ -- Linkages between checkins, files created by each checkin, and
231234
@ -- the names of those files.
235
+@ --
236
+@ -- Each entry represents a file that changed content from pid to fid
237
+@ -- due to the check-in that goes from pmid to mid. fnid is the name
238
+@ -- of the file in the mid check-in. If the file was renamed as part
239
+@ -- of the mid check-in, then pfnid is the previous filename.
240
+@
241
+@ -- There can be multiple entries for (mid,fid) if the mid checkin was
242
+@ -- a merge. Entries with isaux==0 are from the primary parent. Merge
243
+@ -- parents have isaux set to true.
244
+@ --
245
+@ -- Field name mnemonics:
246
+@ -- mid = Manifest ID. (Each check-in is stored as a "Manifest")
247
+@ -- fid = File ID.
248
+@ -- pmid = Parent Manifest ID.
249
+@ -- pid = Parent file ID.
250
+@ -- fnid = File Name ID.
251
+@ -- pfnid = Parent File Name ID.
252
+@ -- isaux = pmid IS AUXiliary parent, not primary parent
232253
@ --
233254
@ -- pid==0 if the file is added by checkin mid.
234255
@ -- fid==0 if the file is removed by checkin mid.
235256
@ --
236257
@ CREATE TABLE mlink(
237
-@ mid INTEGER REFERENCES blob, -- Manifest ID where change occurs
238
-@ pid INTEGER REFERENCES blob, -- File ID in parent manifest
239
-@ fid INTEGER REFERENCES blob, -- Changed file ID in this manifest
258
+@ mid INTEGER REFERENCES plink(cid), -- Checkin that contains fid
259
+@ fid INTEGER REFERENCES blob, -- New file content. 0 if deleted
260
+@ pmid INTEGER REFERENCES plink(cid), -- Checkin that contains pid
261
+@ pid INTEGER REFERENCES blob, -- Prev file content. 0 if new
240262
@ fnid INTEGER REFERENCES filename, -- Name of the file
241263
@ pfnid INTEGER REFERENCES filename, -- Previous name. 0 if unchanged
242
-@ mperm INTEGER -- File permissions. 1==exec
264
+@ mperm INTEGER, -- File permissions. 1==exec
265
+@ isaux BOOLEAN DEFAULT 0 -- TRUE if pmid is the primary
243266
@ );
244267
@ CREATE INDEX mlink_i1 ON mlink(mid);
245268
@ CREATE INDEX mlink_i2 ON mlink(fnid);
246269
@ CREATE INDEX mlink_i3 ON mlink(fid);
247270
@ CREATE INDEX mlink_i4 ON mlink(pid);
@@ -251,11 +274,11 @@
251274
@ CREATE TABLE plink(
252275
@ pid INTEGER REFERENCES blob, -- Parent manifest
253276
@ cid INTEGER REFERENCES blob, -- Child manifest
254277
@ isprim BOOLEAN, -- pid is the primary parent of cid
255278
@ mtime DATETIME, -- the date/time stamp on cid. Julian day.
256
-@ baseid INTEGER REFERENCES blob, -- Baseline if child is a delta manifest
279
+@ baseid INTEGER REFERENCES blob, -- Baseline if cid is a delta manifest.
257280
@ UNIQUE(pid, cid)
258281
@ );
259282
@ CREATE INDEX plink_i2 ON plink(cid,pid);
260283
@
261284
@ -- A "leaf" checkin is a checkin that has no children in the same
@@ -481,18 +504,18 @@
481504
@ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
482505
@ -- been edited or which have been subjected to a 3-way merge.
483506
@ -- Vfile.chnged is 2 if the file has been replaced from a different
484507
@ -- version by the merge and 3 if the file has been added by a merge.
485508
@ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
486
-@ -- done by an --integrate merge. The difference between vfile.chnged==2|4
487
-@ -- and a regular add is that with vfile.chnged==2|4 we know that the
509
+@ -- done by an --integrate merge. The difference between vfile.chnged==3|5
510
+@ -- and a regular add is that with vfile.chnged==3|5 we know that the
488511
@ -- current version of the file is already in the repository.
489512
@ --
490513
@ CREATE TABLE vfile(
491514
@ id INTEGER PRIMARY KEY, -- ID of the checked out file
492515
@ vid INTEGER REFERENCES blob, -- The baseline this file is part of.
493
-@ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add 4:i-chng 5:i-add
516
+@ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add
494517
@ deleted BOOLEAN DEFAULT 0, -- True if deleted
495518
@ isexe BOOLEAN, -- True if file should be executable
496519
@ islink BOOLEAN, -- True if file should be symlink
497520
@ rid INTEGER, -- Originally from this repository record
498521
@ mrid INTEGER, -- Based on this record due to a merge
499522
--- src/schema.c
+++ src/schema.c
@@ -12,11 +12,11 @@
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains string constants that implement the database schema.
19 */
20 #include "config.h"
21 #include "schema.h"
22
@@ -45,11 +45,14 @@
45 ** we have to execute special procedures to update the schema. When
46 ** the aux schema changes, all we need to do is rebuild the database.
47 */
48 #define CONTENT_SCHEMA "2"
49 #define AUX_SCHEMA_MIN "2011-04-25 19:50"
50 #define AUX_SCHEMA_MAX "2014-11-24 20:35"
 
 
 
51
52 #endif /* INTERFACE */
53
54
55 /*
@@ -81,11 +84,11 @@
81 @ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content
82 @ content BLOB, -- Compressed content of this record
83 @ CHECK( length(uuid)==40 AND rid>0 )
84 @ );
85 @ CREATE TABLE delta(
86 @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
87 @ srcid INTEGER NOT NULL REFERENCES blob -- Baseline for delta-compression
88 @ );
89 @ CREATE INDEX delta_i1 ON delta(srcid);
90 @
91 @ -------------------------------------------------------------------------
@@ -126,11 +129,11 @@
126 @ info TEXT, -- contact information
127 @ mtime DATE, -- last change. seconds since 1970
128 @ photo BLOB -- JPEG image of this user
129 @ );
130 @
131 @ -- The VAR table holds miscellanous information about the repository.
132 @ -- in the form of name-value pairs.
133 @ --
134 @ CREATE TABLE config(
135 @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
136 @ value CLOB, -- Content of the named parameter
@@ -227,21 +230,41 @@
227 @ name TEXT UNIQUE -- Name of file page
228 @ );
229 @
230 @ -- Linkages between checkins, files created by each checkin, and
231 @ -- the names of those files.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232 @ --
233 @ -- pid==0 if the file is added by checkin mid.
234 @ -- fid==0 if the file is removed by checkin mid.
235 @ --
236 @ CREATE TABLE mlink(
237 @ mid INTEGER REFERENCES blob, -- Manifest ID where change occurs
238 @ pid INTEGER REFERENCES blob, -- File ID in parent manifest
239 @ fid INTEGER REFERENCES blob, -- Changed file ID in this manifest
 
240 @ fnid INTEGER REFERENCES filename, -- Name of the file
241 @ pfnid INTEGER REFERENCES filename, -- Previous name. 0 if unchanged
242 @ mperm INTEGER -- File permissions. 1==exec
 
243 @ );
244 @ CREATE INDEX mlink_i1 ON mlink(mid);
245 @ CREATE INDEX mlink_i2 ON mlink(fnid);
246 @ CREATE INDEX mlink_i3 ON mlink(fid);
247 @ CREATE INDEX mlink_i4 ON mlink(pid);
@@ -251,11 +274,11 @@
251 @ CREATE TABLE plink(
252 @ pid INTEGER REFERENCES blob, -- Parent manifest
253 @ cid INTEGER REFERENCES blob, -- Child manifest
254 @ isprim BOOLEAN, -- pid is the primary parent of cid
255 @ mtime DATETIME, -- the date/time stamp on cid. Julian day.
256 @ baseid INTEGER REFERENCES blob, -- Baseline if child is a delta manifest
257 @ UNIQUE(pid, cid)
258 @ );
259 @ CREATE INDEX plink_i2 ON plink(cid,pid);
260 @
261 @ -- A "leaf" checkin is a checkin that has no children in the same
@@ -481,18 +504,18 @@
481 @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
482 @ -- been edited or which have been subjected to a 3-way merge.
483 @ -- Vfile.chnged is 2 if the file has been replaced from a different
484 @ -- version by the merge and 3 if the file has been added by a merge.
485 @ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
486 @ -- done by an --integrate merge. The difference between vfile.chnged==2|4
487 @ -- and a regular add is that with vfile.chnged==2|4 we know that the
488 @ -- current version of the file is already in the repository.
489 @ --
490 @ CREATE TABLE vfile(
491 @ id INTEGER PRIMARY KEY, -- ID of the checked out file
492 @ vid INTEGER REFERENCES blob, -- The baseline this file is part of.
493 @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add 4:i-chng 5:i-add
494 @ deleted BOOLEAN DEFAULT 0, -- True if deleted
495 @ isexe BOOLEAN, -- True if file should be executable
496 @ islink BOOLEAN, -- True if file should be symlink
497 @ rid INTEGER, -- Originally from this repository record
498 @ mrid INTEGER, -- Based on this record due to a merge
499
--- src/schema.c
+++ src/schema.c
@@ -12,11 +12,11 @@
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains string constants that implement the database schema.
19 */
20 #include "config.h"
21 #include "schema.h"
22
@@ -45,11 +45,14 @@
45 ** we have to execute special procedures to update the schema. When
46 ** the aux schema changes, all we need to do is rebuild the database.
47 */
48 #define CONTENT_SCHEMA "2"
49 #define AUX_SCHEMA_MIN "2011-04-25 19:50"
50 #define AUX_SCHEMA_MAX "2015-01-24"
51 /* NB: Some features require the latest schema. Warning or error messages
52 ** will appear if an older schema is used. However, the older schemas are
53 ** adequate for many common functions. */
54
55 #endif /* INTERFACE */
56
57
58 /*
@@ -81,11 +84,11 @@
84 @ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content
85 @ content BLOB, -- Compressed content of this record
86 @ CHECK( length(uuid)==40 AND rid>0 )
87 @ );
88 @ CREATE TABLE delta(
89 @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
90 @ srcid INTEGER NOT NULL REFERENCES blob -- Baseline for delta-compression
91 @ );
92 @ CREATE INDEX delta_i1 ON delta(srcid);
93 @
94 @ -------------------------------------------------------------------------
@@ -126,11 +129,11 @@
129 @ info TEXT, -- contact information
130 @ mtime DATE, -- last change. seconds since 1970
131 @ photo BLOB -- JPEG image of this user
132 @ );
133 @
134 @ -- The config table holds miscellanous information about the repository.
135 @ -- in the form of name-value pairs.
136 @ --
137 @ CREATE TABLE config(
138 @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry
139 @ value CLOB, -- Content of the named parameter
@@ -227,21 +230,41 @@
230 @ name TEXT UNIQUE -- Name of file page
231 @ );
232 @
233 @ -- Linkages between checkins, files created by each checkin, and
234 @ -- the names of those files.
235 @ --
236 @ -- Each entry represents a file that changed content from pid to fid
237 @ -- due to the check-in that goes from pmid to mid. fnid is the name
238 @ -- of the file in the mid check-in. If the file was renamed as part
239 @ -- of the mid check-in, then pfnid is the previous filename.
240 @
241 @ -- There can be multiple entries for (mid,fid) if the mid checkin was
242 @ -- a merge. Entries with isaux==0 are from the primary parent. Merge
243 @ -- parents have isaux set to true.
244 @ --
245 @ -- Field name mnemonics:
246 @ -- mid = Manifest ID. (Each check-in is stored as a "Manifest")
247 @ -- fid = File ID.
248 @ -- pmid = Parent Manifest ID.
249 @ -- pid = Parent file ID.
250 @ -- fnid = File Name ID.
251 @ -- pfnid = Parent File Name ID.
252 @ -- isaux = pmid IS AUXiliary parent, not primary parent
253 @ --
254 @ -- pid==0 if the file is added by checkin mid.
255 @ -- fid==0 if the file is removed by checkin mid.
256 @ --
257 @ CREATE TABLE mlink(
258 @ mid INTEGER REFERENCES plink(cid), -- Checkin that contains fid
259 @ fid INTEGER REFERENCES blob, -- New file content. 0 if deleted
260 @ pmid INTEGER REFERENCES plink(cid), -- Checkin that contains pid
261 @ pid INTEGER REFERENCES blob, -- Prev file content. 0 if new
262 @ fnid INTEGER REFERENCES filename, -- Name of the file
263 @ pfnid INTEGER REFERENCES filename, -- Previous name. 0 if unchanged
264 @ mperm INTEGER, -- File permissions. 1==exec
265 @ isaux BOOLEAN DEFAULT 0 -- TRUE if pmid is the primary
266 @ );
267 @ CREATE INDEX mlink_i1 ON mlink(mid);
268 @ CREATE INDEX mlink_i2 ON mlink(fnid);
269 @ CREATE INDEX mlink_i3 ON mlink(fid);
270 @ CREATE INDEX mlink_i4 ON mlink(pid);
@@ -251,11 +274,11 @@
274 @ CREATE TABLE plink(
275 @ pid INTEGER REFERENCES blob, -- Parent manifest
276 @ cid INTEGER REFERENCES blob, -- Child manifest
277 @ isprim BOOLEAN, -- pid is the primary parent of cid
278 @ mtime DATETIME, -- the date/time stamp on cid. Julian day.
279 @ baseid INTEGER REFERENCES blob, -- Baseline if cid is a delta manifest.
280 @ UNIQUE(pid, cid)
281 @ );
282 @ CREATE INDEX plink_i2 ON plink(cid,pid);
283 @
284 @ -- A "leaf" checkin is a checkin that has no children in the same
@@ -481,18 +504,18 @@
504 @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
505 @ -- been edited or which have been subjected to a 3-way merge.
506 @ -- Vfile.chnged is 2 if the file has been replaced from a different
507 @ -- version by the merge and 3 if the file has been added by a merge.
508 @ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
509 @ -- done by an --integrate merge. The difference between vfile.chnged==3|5
510 @ -- and a regular add is that with vfile.chnged==3|5 we know that the
511 @ -- current version of the file is already in the repository.
512 @ --
513 @ CREATE TABLE vfile(
514 @ id INTEGER PRIMARY KEY, -- ID of the checked out file
515 @ vid INTEGER REFERENCES blob, -- The baseline this file is part of.
516 @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add
517 @ deleted BOOLEAN DEFAULT 0, -- True if deleted
518 @ isexe BOOLEAN, -- True if file should be executable
519 @ islink BOOLEAN, -- True if file should be symlink
520 @ rid INTEGER, -- Originally from this repository record
521 @ mrid INTEGER, -- Based on this record due to a merge
522
+621 -83
--- src/search.c
+++ src/search.c
@@ -26,54 +26,42 @@
2626
#include "config.h"
2727
#include "search.h"
2828
#include <assert.h>
2929
3030
#if INTERFACE
31
+
32
+/* Maximum number of search terms */
33
+#define SEARCH_MAX_TERM 8
34
+
3135
/*
3236
** A compiled search pattern
3337
*/
3438
struct Search {
3539
int nTerm; /* Number of search terms */
3640
struct srchTerm { /* For each search term */
3741
char *z; /* Text */
3842
int n; /* length */
39
- } a[8];
43
+ } a[SEARCH_MAX_TERM];
44
+ /* Snippet controls */
45
+ char *zPattern; /* The search pattern */
46
+ char *zMarkBegin; /* Start of a match */
47
+ char *zMarkEnd; /* End of a match */
48
+ char *zMarkGap; /* A gap between two matches */
49
+ unsigned fSrchFlg; /* Flags */
4050
};
51
+
52
+#define SRCHFLG_HTML 0x01 /* Escape snippet text for HTML */
53
+#define SRCHFLG_SCORE 0x02 /* Prepend the score to each snippet */
54
+#define SRCHFLG_STATIC 0x04 /* The static gSearch object */
55
+
4156
#endif
4257
4358
/*
44
-** Compile a search pattern
45
-*/
46
-Search *search_init(const char *zPattern){
47
- int nPattern = strlen(zPattern);
48
- Search *p;
49
- char *z;
50
- int i;
51
-
52
- p = fossil_malloc( nPattern + sizeof(*p) + 1);
53
- z = (char*)&p[1];
54
- memcpy(z, zPattern, nPattern+1);
55
- memset(p, 0, sizeof(*p));
56
- while( *z && p->nTerm<sizeof(p->a)/sizeof(p->a[0]) ){
57
- while( !fossil_isalnum(*z) && *z ){ z++; }
58
- if( *z==0 ) break;
59
- p->a[p->nTerm].z = z;
60
- for(i=1; fossil_isalnum(z[i]) || z[i]=='_'; i++){}
61
- p->a[p->nTerm].n = i;
62
- z += i;
63
- p->nTerm++;
64
- }
65
- return p;
66
-}
67
-
68
-
69
-/*
70
-** Destroy a search context.
71
-*/
72
-void search_end(Search *p){
73
- free(p);
74
-}
59
+** There is a single global Search object:
60
+*/
61
+static Search gSearch;
62
+
7563
7664
/*
7765
** Theses characters constitute a word boundary
7866
*/
7967
static const char isBoundary[] = {
@@ -92,95 +80,388 @@
9280
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9381
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9482
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9583
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9684
};
85
+#define ISALNUM(x) (!isBoundary[(x)&0xff])
86
+
87
+
88
+/*
89
+** Destroy a search context.
90
+*/
91
+void search_end(Search *p){
92
+ if( p ){
93
+ fossil_free(p->zPattern);
94
+ fossil_free(p->zMarkBegin);
95
+ fossil_free(p->zMarkEnd);
96
+ fossil_free(p->zMarkGap);
97
+ memset(p, 0, sizeof(*p));
98
+ if( p!=&gSearch ) fossil_free(p);
99
+ }
100
+}
101
+
102
+/*
103
+** Compile a search pattern
104
+*/
105
+Search *search_init(
106
+ const char *zPattern, /* The search pattern */
107
+ const char *zMarkBegin, /* Start of a match */
108
+ const char *zMarkEnd, /* End of a match */
109
+ const char *zMarkGap, /* A gap between two matches */
110
+ unsigned fSrchFlg /* Flags */
111
+){
112
+ Search *p;
113
+ char *z;
114
+ int i;
115
+
116
+ if( fSrchFlg & SRCHFLG_STATIC ){
117
+ p = &gSearch;
118
+ search_end(p);
119
+ }else{
120
+ p = fossil_malloc(sizeof(*p));
121
+ memset(p, 0, sizeof(*p));
122
+ }
123
+ p->zPattern = z = mprintf("%s", zPattern);
124
+ p->zMarkBegin = mprintf("%s", zMarkBegin);
125
+ p->zMarkEnd = mprintf("%s", zMarkEnd);
126
+ p->zMarkGap = mprintf("%s", zMarkGap);
127
+ p->fSrchFlg = fSrchFlg;
128
+ while( *z && p->nTerm<SEARCH_MAX_TERM ){
129
+ while( *z && !ISALNUM(*z) ){ z++; }
130
+ if( *z==0 ) break;
131
+ p->a[p->nTerm].z = z;
132
+ for(i=1; ISALNUM(z[i]); i++){}
133
+ p->a[p->nTerm].n = i;
134
+ z += i;
135
+ p->nTerm++;
136
+ }
137
+ return p;
138
+}
139
+
140
+
141
+/*
142
+** Append n bytes of text to snippet zTxt. Encode the text appropriately.
143
+*/
144
+static void snippet_text_append(
145
+ Search *p, /* The search context */
146
+ Blob *pSnip, /* Append to this snippet */
147
+ const char *zTxt, /* Text to append */
148
+ int n /* How many bytes to append */
149
+){
150
+ if( n>0 ){
151
+ if( p->fSrchFlg & SRCHFLG_HTML ){
152
+ blob_appendf(pSnip, "%#h", n, zTxt);
153
+ }else{
154
+ blob_append(pSnip, zTxt, n);
155
+ }
156
+ }
157
+}
97158
98159
/*
99
-** Compare a search pattern against an input string and return a score.
160
+** Compare a search pattern against one or more input strings which
161
+** collectively comprise a document. Return a match score. Optionally
162
+** also return a "snippet".
100163
**
101164
** Scoring:
102165
** * All terms must match at least once or the score is zero
103
-** * 10 bonus points if the first occurrence is an exact match
104
-** * 1 additional point for each subsequent match of the same word
105
-** * Extra points of two consecutive words of the pattern are consecutive
166
+** * One point for each matching term
167
+** * Extra points if consecutive words of the pattern are consecutive
106168
** in the document
107169
*/
108
-int search_score(Search *p, int nDoc, const char **azDoc){
109
- int iPrev = 999;
110
- int score = 10;
111
- int iBonus = 0;
112
- int i, j, k;
113
- const char *zDoc;
114
- unsigned char seen[8];
115
-
116
- memset(seen, 0, sizeof(seen));
117
- for(k=0; k<nDoc; k++){
118
- zDoc = azDoc[k];
170
+static int search_score(
171
+ Search *p, /* Search pattern and flags */
172
+ int nDoc, /* Number of strings in this document */
173
+ const char **azDoc, /* Text of each string */
174
+ Blob *pSnip /* If not NULL: Write a snippet here */
175
+){
176
+ int score; /* Final score */
177
+ int i; /* Offset into current document */
178
+ int ii; /* Loop counter */
179
+ int j; /* Loop over search terms */
180
+ int k; /* Loop over prior terms */
181
+ int iWord = 0; /* Current word number */
182
+ int iDoc; /* Current document number */
183
+ int wantGap = 0; /* True if a zMarkGap is wanted */
184
+ const char *zDoc; /* Current document text */
185
+ const int CTX = 50; /* Amount of snippet context */
186
+ int anMatch[SEARCH_MAX_TERM]; /* Number of terms in best match */
187
+ int aiBestDoc[SEARCH_MAX_TERM]; /* Document containing best match */
188
+ int aiBestOfst[SEARCH_MAX_TERM]; /* Byte offset to start of best match */
189
+ int aiLastDoc[SEARCH_MAX_TERM]; /* Document containing most recent match */
190
+ int aiLastOfst[SEARCH_MAX_TERM]; /* Byte offset to the most recent match */
191
+ int aiWordIdx[SEARCH_MAX_TERM]; /* Word index of most recent match */
192
+
193
+ memset(anMatch, 0, sizeof(anMatch));
194
+ memset(aiWordIdx, 0xff, sizeof(aiWordIdx));
195
+ for(iDoc=0; iDoc<nDoc; iDoc++){
196
+ zDoc = azDoc[iDoc];
119197
if( zDoc==0 ) continue;
198
+ iWord++;
120199
for(i=0; zDoc[i]; i++){
121
- char c = zDoc[i];
122
- if( isBoundary[c&0xff] ) continue;
200
+ if( !ISALNUM(zDoc[i]) ) continue;
201
+ iWord++;
202
+ for(j=0; j<p->nTerm; j++){
203
+ int n = p->a[j].n;
204
+ if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0
205
+ && (!ISALNUM(zDoc[i+n]) || p->a[j].z[n]=='*')
206
+ ){
207
+ aiWordIdx[j] = iWord;
208
+ aiLastDoc[j] = iDoc;
209
+ aiLastOfst[j] = i;
210
+ for(k=1; j-k>=0 && anMatch[j-k] && aiWordIdx[j-k]==iWord-k; k++){}
211
+ for(ii=0; ii<k; ii++){
212
+ if( anMatch[j-ii]<k ){
213
+ anMatch[j-ii] = k;
214
+ aiBestDoc[j-ii] = aiLastDoc[j-ii];
215
+ aiBestOfst[j-ii] = aiLastOfst[j-ii];
216
+ }
217
+ }
218
+ break;
219
+ }
220
+ }
221
+ while( ISALNUM(zDoc[i]) ){ i++; }
222
+ }
223
+ }
224
+
225
+ /* Finished search all documents.
226
+ ** Every term must be seen or else the score is zero
227
+ */
228
+ score = 1;
229
+ for(j=0; j<p->nTerm; j++) score *= anMatch[j];
230
+ if( score==0 || pSnip==0 ) return score;
231
+
232
+
233
+ /* Prepare a snippet that describes the matching text.
234
+ */
235
+ blob_init(pSnip, 0, 0);
236
+ if( p->fSrchFlg & SRCHFLG_SCORE ) blob_appendf(pSnip, "%08x", score);
237
+
238
+ while(1){
239
+ int iOfst;
240
+ int iTail;
241
+ int iBest;
242
+ for(ii=0; ii<p->nTerm && anMatch[ii]==0; ii++){}
243
+ if( ii>=p->nTerm ) break; /* This is where the loop exits */
244
+ iBest = ii;
245
+ iDoc = aiBestDoc[ii];
246
+ iOfst = aiBestOfst[ii];
247
+ for(; ii<p->nTerm; ii++){
248
+ if( anMatch[ii]==0 ) continue;
249
+ if( aiBestDoc[ii]>iDoc ) continue;
250
+ if( aiBestOfst[ii]>iOfst ) continue;
251
+ iDoc = aiBestDoc[ii];
252
+ iOfst = aiBestOfst[ii];
253
+ iBest = ii;
254
+ }
255
+ iTail = iOfst + p->a[iBest].n;
256
+ anMatch[iBest] = 0;
257
+ for(ii=0; ii<p->nTerm; ii++){
258
+ if( anMatch[ii]==0 ) continue;
259
+ if( aiBestDoc[ii]!=iDoc ) continue;
260
+ if( aiBestOfst[ii]<=iTail+CTX*2 ){
261
+ if( iTail<aiBestOfst[ii]+p->a[ii].n ){
262
+ iTail = aiBestOfst[ii]+p->a[ii].n;
263
+ }
264
+ anMatch[ii] = 0;
265
+ ii = -1;
266
+ continue;
267
+ }
268
+ }
269
+ zDoc = azDoc[iDoc];
270
+ iOfst -= CTX;
271
+ if( iOfst<0 ) iOfst = 0;
272
+ while( iOfst>0 && ISALNUM(zDoc[iOfst-1]) ) iOfst--;
273
+ while( zDoc[iOfst] && !ISALNUM(zDoc[iOfst]) ) iOfst++;
274
+ for(ii=0; ii<CTX && zDoc[iTail]; ii++, iTail++){}
275
+ while( ISALNUM(zDoc[iTail]) ) iTail++;
276
+ if( iOfst>0 || wantGap ) blob_append(pSnip, p->zMarkGap, -1);
277
+ wantGap = zDoc[iTail]!=0;
278
+ zDoc += iOfst;
279
+ iTail -= iOfst;
280
+
281
+ /* Add a snippet segment using characters iOfst..iOfst+iTail from zDoc */
282
+ for(i=0; i<iTail; i++){
283
+ if( !ISALNUM(zDoc[i]) ) continue;
123284
for(j=0; j<p->nTerm; j++){
124285
int n = p->a[j].n;
125
- if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
126
- score += 1;
127
- if( !seen[j] ){
128
- if( isBoundary[zDoc[i+n]&0xff] ) score += 10;
129
- seen[j] = 1;
130
- }
131
- if( j==iPrev+1 ){
132
- score += iBonus;
133
- }
134
- i += n-1;
135
- iPrev = j;
136
- iBonus = 50;
286
+ if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0
287
+ && (!ISALNUM(zDoc[i+n]) || p->a[j].z[n]=='*')
288
+ ){
289
+ snippet_text_append(p, pSnip, zDoc, i);
290
+ zDoc += i;
291
+ iTail -= i;
292
+ blob_append(pSnip, p->zMarkBegin, -1);
293
+ if( p->a[j].z[n]=='*' ){
294
+ while( ISALNUM(zDoc[n]) ) n++;
295
+ }
296
+ snippet_text_append(p, pSnip, zDoc, n);
297
+ zDoc += n;
298
+ iTail -= n;
299
+ blob_append(pSnip, p->zMarkEnd, -1);
300
+ i = -1;
137301
break;
138
- }
139
- }
140
- iBonus /= 2;
141
- while( !isBoundary[zDoc[i]&0xff] ){ i++; }
142
- }
143
- }
144
-
145
- /* Every term must be seen or else the score is zero */
146
- for(j=0; j<p->nTerm; j++){
147
- if( !seen[j] ) return 0;
148
- }
149
-
302
+ } /* end-if */
303
+ } /* end for(j) */
304
+ if( j<p->nTerm ){
305
+ while( ISALNUM(zDoc[i]) && i<iTail ){ i++; }
306
+ }
307
+ } /* end for(i) */
308
+ snippet_text_append(p, pSnip, zDoc, iTail);
309
+ }
310
+ if( wantGap ) blob_append(pSnip, p->zMarkGap, -1);
150311
return score;
151312
}
313
+
314
+/*
315
+** COMMAND: test-snippet
316
+**
317
+** Usage: fossil test-snippet SEARCHSTRING FILE1 FILE2 ...
318
+*/
319
+void test_snippet_cmd(void){
320
+ Search *p;
321
+ int i;
322
+ Blob x;
323
+ Blob snip;
324
+ int score;
325
+ char *zDoc;
326
+ int flg = 0;
327
+ char *zBegin = (char*)find_option("begin",0,1);
328
+ char *zEnd = (char*)find_option("end",0,1);
329
+ char *zGap = (char*)find_option("gap",0,1);
330
+ if( find_option("html",0,0)!=0 ) flg |= SRCHFLG_HTML;
331
+ if( find_option("score",0,0)!=0 ) flg |= SRCHFLG_SCORE;
332
+ if( find_option("static",0,0)!=0 ) flg |= SRCHFLG_STATIC;
333
+ verify_all_options();
334
+ if( g.argc<4 ) usage("SEARCHSTRING FILE1...");
335
+ if( zBegin==0 ) zBegin = "[[";
336
+ if( zEnd==0 ) zEnd = "]]";
337
+ if( zGap==0 ) zGap = " ... ";
338
+ p = search_init(g.argv[2], zBegin, zEnd, zGap, flg);
339
+ for(i=3; i<g.argc; i++){
340
+ blob_read_from_file(&x, g.argv[i]);
341
+ zDoc = blob_str(&x);
342
+ score = search_score(p, 1, (const char**)&zDoc, &snip);
343
+ fossil_print("%s: %d\n", g.argv[i], score);
344
+ blob_reset(&x);
345
+ if( score ){
346
+ fossil_print("%.78c\n%s\n%.78c\n\n", '=', blob_str(&snip), '=');
347
+ blob_reset(&snip);
348
+ }
349
+ }
350
+}
351
+
352
+/*
353
+** An SQL function to initialize the global search pattern:
354
+**
355
+** search_init(PATTERN,BEGIN,END,GAP,FLAGS)
356
+**
357
+** All arguments are optional.
358
+*/
359
+static void search_init_sqlfunc(
360
+ sqlite3_context *context,
361
+ int argc,
362
+ sqlite3_value **argv
363
+){
364
+ const char *zPattern = 0;
365
+ const char *zBegin = "<b>";
366
+ const char *zEnd = "</b>";
367
+ const char *zGap = " ... ";
368
+ unsigned int flg = SRCHFLG_HTML;
369
+ switch( argc ){
370
+ default:
371
+ flg = (unsigned int)sqlite3_value_int(argv[4]);
372
+ case 4:
373
+ zGap = (const char*)sqlite3_value_text(argv[3]);
374
+ case 3:
375
+ zEnd = (const char*)sqlite3_value_text(argv[2]);
376
+ case 2:
377
+ zBegin = (const char*)sqlite3_value_text(argv[1]);
378
+ case 1:
379
+ zPattern = (const char*)sqlite3_value_text(argv[0]);
380
+ }
381
+ if( zPattern && zPattern[0] ){
382
+ search_init(zPattern, zBegin, zEnd, zGap, flg | SRCHFLG_STATIC);
383
+ }else{
384
+ search_end(&gSearch);
385
+ }
386
+}
152387
153388
/*
154389
** This is an SQLite function that scores its input using
155
-** a pre-computed pattern.
390
+** the pattern from the previous call to search_init().
156391
*/
157392
static void search_score_sqlfunc(
158393
sqlite3_context *context,
159394
int argc,
160395
sqlite3_value **argv
161396
){
162
- Search *p = (Search*)sqlite3_user_data(context);
397
+ int isSnippet = sqlite3_user_data(context)!=0;
163398
const char **azDoc;
164399
int score;
165400
int i;
401
+ Blob snip;
166402
403
+ if( gSearch.nTerm==0 ) return;
167404
azDoc = fossil_malloc( sizeof(const char*)*(argc+1) );
168405
for(i=0; i<argc; i++) azDoc[i] = (const char*)sqlite3_value_text(argv[i]);
169
- score = search_score(p, argc, azDoc);
170
- fossil_free(azDoc);
171
- sqlite3_result_int(context, score);
406
+ score = search_score(&gSearch, argc, azDoc, isSnippet ? &snip : 0);
407
+ fossil_free((void *)azDoc);
408
+ if( isSnippet ){
409
+ if( score ){
410
+ sqlite3_result_text(context, blob_materialize(&snip), -1, fossil_free);
411
+ }
412
+ }else{
413
+ sqlite3_result_int(context, score);
414
+ }
415
+}
416
+
417
+/*
418
+** This is an SQLite function that computes the searchable text.
419
+** It is a wrapper around the search_stext() routine. See the
420
+** search_stext() routine for further detail.
421
+*/
422
+static void search_stext_sqlfunc(
423
+ sqlite3_context *context,
424
+ int argc,
425
+ sqlite3_value **argv
426
+){
427
+ Blob txt;
428
+ const char *zType = (const char*)sqlite3_value_text(argv[0]);
429
+ const char *zArg1 = (const char*)sqlite3_value_text(argv[1]);
430
+ const char *zArg2 = (const char*)sqlite3_value_text(argv[2]);
431
+ search_stext(zType[0], zArg1, zArg2, &txt);
432
+ sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
433
+}
434
+
435
+/*
436
+** Encode a string for use as a query parameter in a URL
437
+*/
438
+static void search_urlencode_sqlfunc(
439
+ sqlite3_context *context,
440
+ int argc,
441
+ sqlite3_value **argv
442
+){
443
+ char *z = mprintf("%T",sqlite3_value_text(argv[0]));
444
+ sqlite3_result_text(context, z, -1, fossil_free);
172445
}
173446
174447
/*
175448
** Register the "score()" SQL function to score its input text
176449
** using the given Search object. Once this function is registered,
177450
** do not delete the Search object.
178451
*/
179
-void search_sql_setup(Search *p){
180
- sqlite3_create_function(g.db, "score", -1, SQLITE_UTF8, p,
452
+void search_sql_setup(sqlite3 *db){
453
+ sqlite3_create_function(db, "score", -1, SQLITE_UTF8, 0,
454
+ search_score_sqlfunc, 0, 0);
455
+ sqlite3_create_function(db, "snippet", -1, SQLITE_UTF8, &gSearch,
181456
search_score_sqlfunc, 0, 0);
457
+ sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
458
+ search_init_sqlfunc, 0, 0);
459
+ sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
460
+ search_stext_sqlfunc, 0, 0);
461
+ sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
462
+ search_urlencode_sqlfunc, 0, 0);
182463
}
183464
184465
/*
185466
** Testing the search function.
186467
**
@@ -198,11 +479,10 @@
198479
** of entries returned. The -width option can be
199480
** used to set the output width used when printing
200481
** matches.
201482
*/
202483
void search_cmd(void){
203
- Search *p;
204484
Blob pattern;
205485
int i;
206486
Blob sql = empty_blob;
207487
Stmt q;
208488
int iBest;
@@ -227,13 +507,13 @@
227507
if( g.argc<2 ) return;
228508
blob_init(&pattern, g.argv[2], -1);
229509
for(i=3; i<g.argc; i++){
230510
blob_appendf(&pattern, " %s", g.argv[i]);
231511
}
232
- p = search_init(blob_str(&pattern));
512
+ (void)search_init(blob_str(&pattern),"*","*","...",SRCHFLG_STATIC);
233513
blob_reset(&pattern);
234
- search_sql_setup(p);
514
+ search_sql_setup(g.db);
235515
236516
db_multi_exec(
237517
"CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
238518
"CREATE INDEX srch_idx1 ON srch(x);"
239519
"INSERT INTO srch(rid,uuid,date,comment,x)"
@@ -255,5 +535,263 @@
255535
db_prepare(&q, "%s", blob_sql_text(&sql));
256536
blob_reset(&sql);
257537
print_timeline(&q, nLimit, width, 0);
258538
db_finalize(&q);
259539
}
540
+
541
+/*
542
+** WEBPAGE: /search
543
+**
544
+** This is an EXPERIMENTAL page for doing search across a repository.
545
+**
546
+** The current implementation does a full text search over embedded
547
+** documentation files on the tip of the "trunk" branch. Only files
548
+** ending in ".wiki", ".md", ".html", and ".txt" are searched.
549
+**
550
+** The entire text is scanned. There is no full-text index. This is
551
+** experimental. We may change to using a full-text index depending
552
+** on performance.
553
+**
554
+** Other pending enhancements:
555
+** * Search tickets
556
+** * Search wiki
557
+*/
558
+void search_page(void){
559
+ const char *zPattern = PD("s","");
560
+ Stmt q;
561
+ const char *zSrchEnable = "dwc";
562
+
563
+ login_check_credentials();
564
+ if( !g.perm.Read ){ login_needed(); return; }
565
+ style_header("Search");
566
+ @ <form method="GET" action="search"><center>
567
+ @ <input type="text" name="s" size="40" value="%h(zPattern)">
568
+ @ <input type="submit" value="Search">
569
+ @ </center></form>
570
+ while( fossil_isspace(zPattern[0]) ) zPattern++;
571
+ if( zPattern[0] ){
572
+ search_sql_setup(g.db);
573
+ add_content_sql_commands(g.db);
574
+ search_init(zPattern, "<b>", "</b>", " ... ",
575
+ SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
576
+ db_multi_exec(
577
+ "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
578
+ "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
579
+ );
580
+ if( strchr(zSrchEnable, 'd') ){
581
+ db_multi_exec(
582
+ "INSERT INTO x(label,url,date,snip)"
583
+ " SELECT printf('Document: %%s',foci.filename),"
584
+ " printf('%R/doc/trunk/%%s',foci.filename),"
585
+ " (SELECT datetime(event.mtime) FROM event"
586
+ " WHERE objid=symbolic_name_to_rid('trunk')),"
587
+ " snippet(stext('d',blob.rid,foci.filename))"
588
+ " FROM foci CROSS JOIN blob"
589
+ " WHERE checkinID=symbolic_name_to_rid('trunk')"
590
+ " AND blob.uuid=foci.uuid"
591
+ " AND (filename GLOB '*.wiki' OR"
592
+ " filename GLOB '*.md' OR"
593
+ " filename GLOB '*.txt' OR"
594
+ " filename GLOB '*.html');"
595
+ );
596
+ }
597
+ if( strchr(zSrchEnable, 'w') ){
598
+ db_multi_exec(
599
+ "WITH wiki(name,rid,mtime) AS ("
600
+ " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
601
+ " FROM tag, tagxref"
602
+ " WHERE tag.tagname GLOB 'wiki-*'"
603
+ " AND tagxref.tagid=tag.tagid"
604
+ " GROUP BY 1"
605
+ ")"
606
+ "INSERT INTO x(label,url,date,snip)"
607
+ " SELECT printf('Wiki: %%s',name),"
608
+ " printf('%R/wiki?name=%%s',urlencode(name)),"
609
+ " datetime(mtime),"
610
+ " snippet(stext('w',rid,name))"
611
+ " FROM wiki;"
612
+ );
613
+ }
614
+ if( strchr(zSrchEnable, 'c') ){
615
+ db_multi_exec(
616
+ "WITH ckin(uuid,rid,mtime) AS ("
617
+ " SELECT blob.uuid, event.objid, event.mtime"
618
+ " FROM event, blob"
619
+ " WHERE event.type='ci'"
620
+ " AND blob.rid=event.objid"
621
+ ")"
622
+ "INSERT INTO x(label,url,date,snip)"
623
+ " SELECT printf('Check-in [%%.10s] on %%s',uuid,datetime(mtime)),"
624
+ " printf('%R/timeline?c=%%s&n=8&y=ci',uuid),"
625
+ " datetime(mtime),"
626
+ " snippet(stext('c',rid,NULL))"
627
+ " FROM ckin;"
628
+ );
629
+ }
630
+ db_prepare(&q, "SELECT url, substr(snip,9), label"
631
+ " FROM x WHERE snip IS NOT NULL"
632
+ " ORDER BY substr(snip,1,9) DESC, date DESC;");
633
+ @ <ol>
634
+ while( db_step(&q)==SQLITE_ROW ){
635
+ const char *zUrl = db_column_text(&q, 0);
636
+ const char *zSnippet = db_column_text(&q, 1);
637
+ const char *zLabel = db_column_text(&q, 2);
638
+ @ <li><p>%s(href("%s",zUrl))%h(zLabel)</a><br>%s(zSnippet)</li>
639
+ }
640
+ db_finalize(&q);
641
+ @ </ol>
642
+ }
643
+ style_footer();
644
+}
645
+
646
+
647
+/*
648
+** This is a helper function for search_stext(). Writing into pOut
649
+** the search text obtained from pIn according to zMimetype.
650
+*/
651
+static void get_stext_by_mimetype(
652
+ Blob *pIn,
653
+ const char *zMimetype,
654
+ Blob *pOut
655
+){
656
+ Blob html, title;
657
+ blob_init(&html, 0, 0);
658
+ blob_init(&title, 0, 0);
659
+ if( zMimetype==0 ) zMimetype = "text/plain";
660
+ if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){
661
+ wiki_convert(pIn, &html, 0);
662
+ html_to_plaintext(blob_str(&html), pOut);
663
+ }else if( fossil_strcmp(zMimetype,"text/x-markdown")==0 ){
664
+ markdown_to_html(pIn, &title, &html);
665
+ html_to_plaintext(blob_str(&html), pOut);
666
+ }else if( fossil_strcmp(zMimetype,"text/html")==0 ){
667
+ html_to_plaintext(blob_str(pIn), pOut);
668
+ }else{
669
+ *pOut = *pIn;
670
+ blob_init(pIn, 0, 0);
671
+ }
672
+ blob_reset(&html);
673
+ blob_reset(&title);
674
+}
675
+
676
+/*
677
+** Return "search text" - a reduced version of a document appropriate for
678
+** full text search and/or for constructing a search result snippet.
679
+**
680
+** cType: d Embedded documentation
681
+** s Source code listing
682
+** w Wiki page
683
+** c Check-in comment
684
+** t Ticket text
685
+** e Event/Blog text
686
+** k Diff of a wiki
687
+** f Diff of a checkin
688
+**
689
+** zArg1, zArg2: Description of the document, depending on cType.
690
+*/
691
+void search_stext(
692
+ char cType, /* Type of document */
693
+ const char *zArg1, /* First parameter */
694
+ const char *zArg2, /* Second parameter */
695
+ Blob *pOut /* OUT: Initialize to the search text */
696
+){
697
+ blob_init(pOut, 0, 0);
698
+ switch( cType ){
699
+ case 'd': /* Doc. zArg1: RID of the file. zArg2: Filename */
700
+ case 's': { /* Source. zArg1: RID of the file. zArg2: Filename */
701
+ int rid = atoi(zArg1);
702
+ Blob doc;
703
+ content_get(rid, &doc);
704
+ blob_to_utf8_no_bom(&doc, 0);
705
+ get_stext_by_mimetype(&doc, mimetype_from_name(zArg2), pOut);
706
+ blob_reset(&doc);
707
+ break;
708
+ }
709
+ case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
710
+ int rid = atoi(zArg1);
711
+ Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
712
+ Blob wiki;
713
+ if( pWiki==0 ) break;
714
+ blob_init(&wiki, pWiki->zWiki, -1);
715
+ get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
716
+ pOut);
717
+ blob_reset(&wiki);
718
+ manifest_destroy(pWiki);
719
+ break;
720
+ }
721
+ case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
722
+ int rid = atoi(zArg1);
723
+ static Stmt q;
724
+ db_static_prepare(&q,
725
+ "SELECT coalesce(ecomment,comment)"
726
+ " ||' (user: '||coalesce(euser,user,'?')"
727
+ " ||', tags: '||"
728
+ " (SELECT group_concat(substr(tag.tagname,5),',')"
729
+ " FROM tag, tagxref"
730
+ " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
731
+ " AND tagxref.rid=event.objid AND tagxref.tagtype>0)"
732
+ " ||')'"
733
+ " FROM event WHERE objid=:x AND type='ci'");
734
+ db_bind_int(&q, ":x", rid);
735
+ if( db_step(&q)==SQLITE_ROW ){
736
+ db_column_blob(&q, 0, pOut);
737
+ blob_append(pOut, "\n", 1);
738
+ }
739
+ db_reset(&q);
740
+ break;
741
+ }
742
+ }
743
+}
744
+
745
+/*
746
+** The arguments cType,zArg1,zArg2 define an object that can be searched
747
+** for. Return a URL (relative to the root of the Fossil project) that
748
+** will jump to that document.
749
+**
750
+** Space to hold the returned string is obtained from mprintf() and should
751
+** be freed by the caller using fossil_free() or the equivalent.
752
+*/
753
+char *search_url(
754
+ char cType, /* Type of document */
755
+ const char *zArg1, /* First parameter */
756
+ const char *zArg2 /* Second parameter */
757
+){
758
+ char *zUrl = 0;
759
+ switch( cType ){
760
+ case 'd': { /* Doc. zArg1: RID of the file. zArg2: Filename */
761
+ case 's': /* Source. zArg1: RID of the file. zArg2: Filename */
762
+ zUrl = db_text(0,
763
+ "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
764
+ " FROM mlink, blob"
765
+ " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
766
+ zArg2, atoi(zArg1));
767
+ break;
768
+ }
769
+ case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
770
+ char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
771
+ zUrl = mprintf("/wiki?id=%z&name=%t", zId, zArg2);
772
+ break;
773
+ }
774
+ case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
775
+ char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
776
+ zUrl = mprintf("/info/%z", zId);
777
+ break;
778
+ }
779
+ }
780
+ return zUrl;
781
+}
782
+
783
+/*
784
+** COMMAND: test-search-stext
785
+**
786
+** Usage: fossil test-search-stext TYPE ARG1 ARG2
787
+*/
788
+void test_search_stext(void){
789
+ Blob out;
790
+ char *zUrl;
791
+ db_find_and_open_repository(0,0);
792
+ if( g.argc!=5 ) usage("TYPE ARG1 ARG2");
793
+ search_stext(g.argv[2][0], g.argv[3], g.argv[4], &out);
794
+ zUrl = search_url(g.argv[2][0], g.argv[3], g.argv[4]);
795
+ fossil_print("%s\n%z\n",blob_str(&out),zUrl);
796
+ blob_reset(&out);
797
+}
260798
--- src/search.c
+++ src/search.c
@@ -26,54 +26,42 @@
26 #include "config.h"
27 #include "search.h"
28 #include <assert.h>
29
30 #if INTERFACE
 
 
 
 
31 /*
32 ** A compiled search pattern
33 */
34 struct Search {
35 int nTerm; /* Number of search terms */
36 struct srchTerm { /* For each search term */
37 char *z; /* Text */
38 int n; /* length */
39 } a[8];
 
 
 
 
 
 
40 };
 
 
 
 
 
41 #endif
42
43 /*
44 ** Compile a search pattern
45 */
46 Search *search_init(const char *zPattern){
47 int nPattern = strlen(zPattern);
48 Search *p;
49 char *z;
50 int i;
51
52 p = fossil_malloc( nPattern + sizeof(*p) + 1);
53 z = (char*)&p[1];
54 memcpy(z, zPattern, nPattern+1);
55 memset(p, 0, sizeof(*p));
56 while( *z && p->nTerm<sizeof(p->a)/sizeof(p->a[0]) ){
57 while( !fossil_isalnum(*z) && *z ){ z++; }
58 if( *z==0 ) break;
59 p->a[p->nTerm].z = z;
60 for(i=1; fossil_isalnum(z[i]) || z[i]=='_'; i++){}
61 p->a[p->nTerm].n = i;
62 z += i;
63 p->nTerm++;
64 }
65 return p;
66 }
67
68
69 /*
70 ** Destroy a search context.
71 */
72 void search_end(Search *p){
73 free(p);
74 }
75
76 /*
77 ** Theses characters constitute a word boundary
78 */
79 static const char isBoundary[] = {
@@ -92,95 +80,388 @@
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
98 /*
99 ** Compare a search pattern against an input string and return a score.
 
 
100 **
101 ** Scoring:
102 ** * All terms must match at least once or the score is zero
103 ** * 10 bonus points if the first occurrence is an exact match
104 ** * 1 additional point for each subsequent match of the same word
105 ** * Extra points of two consecutive words of the pattern are consecutive
106 ** in the document
107 */
108 int search_score(Search *p, int nDoc, const char **azDoc){
109 int iPrev = 999;
110 int score = 10;
111 int iBonus = 0;
112 int i, j, k;
113 const char *zDoc;
114 unsigned char seen[8];
115
116 memset(seen, 0, sizeof(seen));
117 for(k=0; k<nDoc; k++){
118 zDoc = azDoc[k];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119 if( zDoc==0 ) continue;
 
120 for(i=0; zDoc[i]; i++){
121 char c = zDoc[i];
122 if( isBoundary[c&0xff] ) continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123 for(j=0; j<p->nTerm; j++){
124 int n = p->a[j].n;
125 if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
126 score += 1;
127 if( !seen[j] ){
128 if( isBoundary[zDoc[i+n]&0xff] ) score += 10;
129 seen[j] = 1;
130 }
131 if( j==iPrev+1 ){
132 score += iBonus;
133 }
134 i += n-1;
135 iPrev = j;
136 iBonus = 50;
 
 
 
137 break;
138 }
139 }
140 iBonus /= 2;
141 while( !isBoundary[zDoc[i]&0xff] ){ i++; }
142 }
143 }
144
145 /* Every term must be seen or else the score is zero */
146 for(j=0; j<p->nTerm; j++){
147 if( !seen[j] ) return 0;
148 }
149
150 return score;
151 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
153 /*
154 ** This is an SQLite function that scores its input using
155 ** a pre-computed pattern.
156 */
157 static void search_score_sqlfunc(
158 sqlite3_context *context,
159 int argc,
160 sqlite3_value **argv
161 ){
162 Search *p = (Search*)sqlite3_user_data(context);
163 const char **azDoc;
164 int score;
165 int i;
 
166
 
167 azDoc = fossil_malloc( sizeof(const char*)*(argc+1) );
168 for(i=0; i<argc; i++) azDoc[i] = (const char*)sqlite3_value_text(argv[i]);
169 score = search_score(p, argc, azDoc);
170 fossil_free(azDoc);
171 sqlite3_result_int(context, score);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172 }
173
174 /*
175 ** Register the "score()" SQL function to score its input text
176 ** using the given Search object. Once this function is registered,
177 ** do not delete the Search object.
178 */
179 void search_sql_setup(Search *p){
180 sqlite3_create_function(g.db, "score", -1, SQLITE_UTF8, p,
 
 
181 search_score_sqlfunc, 0, 0);
 
 
 
 
 
 
182 }
183
184 /*
185 ** Testing the search function.
186 **
@@ -198,11 +479,10 @@
198 ** of entries returned. The -width option can be
199 ** used to set the output width used when printing
200 ** matches.
201 */
202 void search_cmd(void){
203 Search *p;
204 Blob pattern;
205 int i;
206 Blob sql = empty_blob;
207 Stmt q;
208 int iBest;
@@ -227,13 +507,13 @@
227 if( g.argc<2 ) return;
228 blob_init(&pattern, g.argv[2], -1);
229 for(i=3; i<g.argc; i++){
230 blob_appendf(&pattern, " %s", g.argv[i]);
231 }
232 p = search_init(blob_str(&pattern));
233 blob_reset(&pattern);
234 search_sql_setup(p);
235
236 db_multi_exec(
237 "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
238 "CREATE INDEX srch_idx1 ON srch(x);"
239 "INSERT INTO srch(rid,uuid,date,comment,x)"
@@ -255,5 +535,263 @@
255 db_prepare(&q, "%s", blob_sql_text(&sql));
256 blob_reset(&sql);
257 print_timeline(&q, nLimit, width, 0);
258 db_finalize(&q);
259 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
--- src/search.c
+++ src/search.c
@@ -26,54 +26,42 @@
26 #include "config.h"
27 #include "search.h"
28 #include <assert.h>
29
30 #if INTERFACE
31
32 /* Maximum number of search terms */
33 #define SEARCH_MAX_TERM 8
34
35 /*
36 ** A compiled search pattern
37 */
38 struct Search {
39 int nTerm; /* Number of search terms */
40 struct srchTerm { /* For each search term */
41 char *z; /* Text */
42 int n; /* length */
43 } a[SEARCH_MAX_TERM];
44 /* Snippet controls */
45 char *zPattern; /* The search pattern */
46 char *zMarkBegin; /* Start of a match */
47 char *zMarkEnd; /* End of a match */
48 char *zMarkGap; /* A gap between two matches */
49 unsigned fSrchFlg; /* Flags */
50 };
51
52 #define SRCHFLG_HTML 0x01 /* Escape snippet text for HTML */
53 #define SRCHFLG_SCORE 0x02 /* Prepend the score to each snippet */
54 #define SRCHFLG_STATIC 0x04 /* The static gSearch object */
55
56 #endif
57
58 /*
59 ** There is a single global Search object:
60 */
61 static Search gSearch;
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
64 /*
65 ** Theses characters constitute a word boundary
66 */
67 static const char isBoundary[] = {
@@ -92,95 +80,388 @@
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84 };
85 #define ISALNUM(x) (!isBoundary[(x)&0xff])
86
87
88 /*
89 ** Destroy a search context.
90 */
91 void search_end(Search *p){
92 if( p ){
93 fossil_free(p->zPattern);
94 fossil_free(p->zMarkBegin);
95 fossil_free(p->zMarkEnd);
96 fossil_free(p->zMarkGap);
97 memset(p, 0, sizeof(*p));
98 if( p!=&gSearch ) fossil_free(p);
99 }
100 }
101
102 /*
103 ** Compile a search pattern
104 */
105 Search *search_init(
106 const char *zPattern, /* The search pattern */
107 const char *zMarkBegin, /* Start of a match */
108 const char *zMarkEnd, /* End of a match */
109 const char *zMarkGap, /* A gap between two matches */
110 unsigned fSrchFlg /* Flags */
111 ){
112 Search *p;
113 char *z;
114 int i;
115
116 if( fSrchFlg & SRCHFLG_STATIC ){
117 p = &gSearch;
118 search_end(p);
119 }else{
120 p = fossil_malloc(sizeof(*p));
121 memset(p, 0, sizeof(*p));
122 }
123 p->zPattern = z = mprintf("%s", zPattern);
124 p->zMarkBegin = mprintf("%s", zMarkBegin);
125 p->zMarkEnd = mprintf("%s", zMarkEnd);
126 p->zMarkGap = mprintf("%s", zMarkGap);
127 p->fSrchFlg = fSrchFlg;
128 while( *z && p->nTerm<SEARCH_MAX_TERM ){
129 while( *z && !ISALNUM(*z) ){ z++; }
130 if( *z==0 ) break;
131 p->a[p->nTerm].z = z;
132 for(i=1; ISALNUM(z[i]); i++){}
133 p->a[p->nTerm].n = i;
134 z += i;
135 p->nTerm++;
136 }
137 return p;
138 }
139
140
141 /*
142 ** Append n bytes of text to snippet zTxt. Encode the text appropriately.
143 */
144 static void snippet_text_append(
145 Search *p, /* The search context */
146 Blob *pSnip, /* Append to this snippet */
147 const char *zTxt, /* Text to append */
148 int n /* How many bytes to append */
149 ){
150 if( n>0 ){
151 if( p->fSrchFlg & SRCHFLG_HTML ){
152 blob_appendf(pSnip, "%#h", n, zTxt);
153 }else{
154 blob_append(pSnip, zTxt, n);
155 }
156 }
157 }
158
159 /*
160 ** Compare a search pattern against one or more input strings which
161 ** collectively comprise a document. Return a match score. Optionally
162 ** also return a "snippet".
163 **
164 ** Scoring:
165 ** * All terms must match at least once or the score is zero
166 ** * One point for each matching term
167 ** * Extra points if consecutive words of the pattern are consecutive
 
168 ** in the document
169 */
170 static int search_score(
171 Search *p, /* Search pattern and flags */
172 int nDoc, /* Number of strings in this document */
173 const char **azDoc, /* Text of each string */
174 Blob *pSnip /* If not NULL: Write a snippet here */
175 ){
176 int score; /* Final score */
177 int i; /* Offset into current document */
178 int ii; /* Loop counter */
179 int j; /* Loop over search terms */
180 int k; /* Loop over prior terms */
181 int iWord = 0; /* Current word number */
182 int iDoc; /* Current document number */
183 int wantGap = 0; /* True if a zMarkGap is wanted */
184 const char *zDoc; /* Current document text */
185 const int CTX = 50; /* Amount of snippet context */
186 int anMatch[SEARCH_MAX_TERM]; /* Number of terms in best match */
187 int aiBestDoc[SEARCH_MAX_TERM]; /* Document containing best match */
188 int aiBestOfst[SEARCH_MAX_TERM]; /* Byte offset to start of best match */
189 int aiLastDoc[SEARCH_MAX_TERM]; /* Document containing most recent match */
190 int aiLastOfst[SEARCH_MAX_TERM]; /* Byte offset to the most recent match */
191 int aiWordIdx[SEARCH_MAX_TERM]; /* Word index of most recent match */
192
193 memset(anMatch, 0, sizeof(anMatch));
194 memset(aiWordIdx, 0xff, sizeof(aiWordIdx));
195 for(iDoc=0; iDoc<nDoc; iDoc++){
196 zDoc = azDoc[iDoc];
197 if( zDoc==0 ) continue;
198 iWord++;
199 for(i=0; zDoc[i]; i++){
200 if( !ISALNUM(zDoc[i]) ) continue;
201 iWord++;
202 for(j=0; j<p->nTerm; j++){
203 int n = p->a[j].n;
204 if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0
205 && (!ISALNUM(zDoc[i+n]) || p->a[j].z[n]=='*')
206 ){
207 aiWordIdx[j] = iWord;
208 aiLastDoc[j] = iDoc;
209 aiLastOfst[j] = i;
210 for(k=1; j-k>=0 && anMatch[j-k] && aiWordIdx[j-k]==iWord-k; k++){}
211 for(ii=0; ii<k; ii++){
212 if( anMatch[j-ii]<k ){
213 anMatch[j-ii] = k;
214 aiBestDoc[j-ii] = aiLastDoc[j-ii];
215 aiBestOfst[j-ii] = aiLastOfst[j-ii];
216 }
217 }
218 break;
219 }
220 }
221 while( ISALNUM(zDoc[i]) ){ i++; }
222 }
223 }
224
225 /* Finished search all documents.
226 ** Every term must be seen or else the score is zero
227 */
228 score = 1;
229 for(j=0; j<p->nTerm; j++) score *= anMatch[j];
230 if( score==0 || pSnip==0 ) return score;
231
232
233 /* Prepare a snippet that describes the matching text.
234 */
235 blob_init(pSnip, 0, 0);
236 if( p->fSrchFlg & SRCHFLG_SCORE ) blob_appendf(pSnip, "%08x", score);
237
238 while(1){
239 int iOfst;
240 int iTail;
241 int iBest;
242 for(ii=0; ii<p->nTerm && anMatch[ii]==0; ii++){}
243 if( ii>=p->nTerm ) break; /* This is where the loop exits */
244 iBest = ii;
245 iDoc = aiBestDoc[ii];
246 iOfst = aiBestOfst[ii];
247 for(; ii<p->nTerm; ii++){
248 if( anMatch[ii]==0 ) continue;
249 if( aiBestDoc[ii]>iDoc ) continue;
250 if( aiBestOfst[ii]>iOfst ) continue;
251 iDoc = aiBestDoc[ii];
252 iOfst = aiBestOfst[ii];
253 iBest = ii;
254 }
255 iTail = iOfst + p->a[iBest].n;
256 anMatch[iBest] = 0;
257 for(ii=0; ii<p->nTerm; ii++){
258 if( anMatch[ii]==0 ) continue;
259 if( aiBestDoc[ii]!=iDoc ) continue;
260 if( aiBestOfst[ii]<=iTail+CTX*2 ){
261 if( iTail<aiBestOfst[ii]+p->a[ii].n ){
262 iTail = aiBestOfst[ii]+p->a[ii].n;
263 }
264 anMatch[ii] = 0;
265 ii = -1;
266 continue;
267 }
268 }
269 zDoc = azDoc[iDoc];
270 iOfst -= CTX;
271 if( iOfst<0 ) iOfst = 0;
272 while( iOfst>0 && ISALNUM(zDoc[iOfst-1]) ) iOfst--;
273 while( zDoc[iOfst] && !ISALNUM(zDoc[iOfst]) ) iOfst++;
274 for(ii=0; ii<CTX && zDoc[iTail]; ii++, iTail++){}
275 while( ISALNUM(zDoc[iTail]) ) iTail++;
276 if( iOfst>0 || wantGap ) blob_append(pSnip, p->zMarkGap, -1);
277 wantGap = zDoc[iTail]!=0;
278 zDoc += iOfst;
279 iTail -= iOfst;
280
281 /* Add a snippet segment using characters iOfst..iOfst+iTail from zDoc */
282 for(i=0; i<iTail; i++){
283 if( !ISALNUM(zDoc[i]) ) continue;
284 for(j=0; j<p->nTerm; j++){
285 int n = p->a[j].n;
286 if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0
287 && (!ISALNUM(zDoc[i+n]) || p->a[j].z[n]=='*')
288 ){
289 snippet_text_append(p, pSnip, zDoc, i);
290 zDoc += i;
291 iTail -= i;
292 blob_append(pSnip, p->zMarkBegin, -1);
293 if( p->a[j].z[n]=='*' ){
294 while( ISALNUM(zDoc[n]) ) n++;
295 }
296 snippet_text_append(p, pSnip, zDoc, n);
297 zDoc += n;
298 iTail -= n;
299 blob_append(pSnip, p->zMarkEnd, -1);
300 i = -1;
301 break;
302 } /* end-if */
303 } /* end for(j) */
304 if( j<p->nTerm ){
305 while( ISALNUM(zDoc[i]) && i<iTail ){ i++; }
306 }
307 } /* end for(i) */
308 snippet_text_append(p, pSnip, zDoc, iTail);
309 }
310 if( wantGap ) blob_append(pSnip, p->zMarkGap, -1);
 
 
 
311 return score;
312 }
313
314 /*
315 ** COMMAND: test-snippet
316 **
317 ** Usage: fossil test-snippet SEARCHSTRING FILE1 FILE2 ...
318 */
319 void test_snippet_cmd(void){
320 Search *p;
321 int i;
322 Blob x;
323 Blob snip;
324 int score;
325 char *zDoc;
326 int flg = 0;
327 char *zBegin = (char*)find_option("begin",0,1);
328 char *zEnd = (char*)find_option("end",0,1);
329 char *zGap = (char*)find_option("gap",0,1);
330 if( find_option("html",0,0)!=0 ) flg |= SRCHFLG_HTML;
331 if( find_option("score",0,0)!=0 ) flg |= SRCHFLG_SCORE;
332 if( find_option("static",0,0)!=0 ) flg |= SRCHFLG_STATIC;
333 verify_all_options();
334 if( g.argc<4 ) usage("SEARCHSTRING FILE1...");
335 if( zBegin==0 ) zBegin = "[[";
336 if( zEnd==0 ) zEnd = "]]";
337 if( zGap==0 ) zGap = " ... ";
338 p = search_init(g.argv[2], zBegin, zEnd, zGap, flg);
339 for(i=3; i<g.argc; i++){
340 blob_read_from_file(&x, g.argv[i]);
341 zDoc = blob_str(&x);
342 score = search_score(p, 1, (const char**)&zDoc, &snip);
343 fossil_print("%s: %d\n", g.argv[i], score);
344 blob_reset(&x);
345 if( score ){
346 fossil_print("%.78c\n%s\n%.78c\n\n", '=', blob_str(&snip), '=');
347 blob_reset(&snip);
348 }
349 }
350 }
351
352 /*
353 ** An SQL function to initialize the global search pattern:
354 **
355 ** search_init(PATTERN,BEGIN,END,GAP,FLAGS)
356 **
357 ** All arguments are optional.
358 */
359 static void search_init_sqlfunc(
360 sqlite3_context *context,
361 int argc,
362 sqlite3_value **argv
363 ){
364 const char *zPattern = 0;
365 const char *zBegin = "<b>";
366 const char *zEnd = "</b>";
367 const char *zGap = " ... ";
368 unsigned int flg = SRCHFLG_HTML;
369 switch( argc ){
370 default:
371 flg = (unsigned int)sqlite3_value_int(argv[4]);
372 case 4:
373 zGap = (const char*)sqlite3_value_text(argv[3]);
374 case 3:
375 zEnd = (const char*)sqlite3_value_text(argv[2]);
376 case 2:
377 zBegin = (const char*)sqlite3_value_text(argv[1]);
378 case 1:
379 zPattern = (const char*)sqlite3_value_text(argv[0]);
380 }
381 if( zPattern && zPattern[0] ){
382 search_init(zPattern, zBegin, zEnd, zGap, flg | SRCHFLG_STATIC);
383 }else{
384 search_end(&gSearch);
385 }
386 }
387
388 /*
389 ** This is an SQLite function that scores its input using
390 ** the pattern from the previous call to search_init().
391 */
392 static void search_score_sqlfunc(
393 sqlite3_context *context,
394 int argc,
395 sqlite3_value **argv
396 ){
397 int isSnippet = sqlite3_user_data(context)!=0;
398 const char **azDoc;
399 int score;
400 int i;
401 Blob snip;
402
403 if( gSearch.nTerm==0 ) return;
404 azDoc = fossil_malloc( sizeof(const char*)*(argc+1) );
405 for(i=0; i<argc; i++) azDoc[i] = (const char*)sqlite3_value_text(argv[i]);
406 score = search_score(&gSearch, argc, azDoc, isSnippet ? &snip : 0);
407 fossil_free((void *)azDoc);
408 if( isSnippet ){
409 if( score ){
410 sqlite3_result_text(context, blob_materialize(&snip), -1, fossil_free);
411 }
412 }else{
413 sqlite3_result_int(context, score);
414 }
415 }
416
417 /*
418 ** This is an SQLite function that computes the searchable text.
419 ** It is a wrapper around the search_stext() routine. See the
420 ** search_stext() routine for further detail.
421 */
422 static void search_stext_sqlfunc(
423 sqlite3_context *context,
424 int argc,
425 sqlite3_value **argv
426 ){
427 Blob txt;
428 const char *zType = (const char*)sqlite3_value_text(argv[0]);
429 const char *zArg1 = (const char*)sqlite3_value_text(argv[1]);
430 const char *zArg2 = (const char*)sqlite3_value_text(argv[2]);
431 search_stext(zType[0], zArg1, zArg2, &txt);
432 sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
433 }
434
435 /*
436 ** Encode a string for use as a query parameter in a URL
437 */
438 static void search_urlencode_sqlfunc(
439 sqlite3_context *context,
440 int argc,
441 sqlite3_value **argv
442 ){
443 char *z = mprintf("%T",sqlite3_value_text(argv[0]));
444 sqlite3_result_text(context, z, -1, fossil_free);
445 }
446
447 /*
448 ** Register the "score()" SQL function to score its input text
449 ** using the given Search object. Once this function is registered,
450 ** do not delete the Search object.
451 */
452 void search_sql_setup(sqlite3 *db){
453 sqlite3_create_function(db, "score", -1, SQLITE_UTF8, 0,
454 search_score_sqlfunc, 0, 0);
455 sqlite3_create_function(db, "snippet", -1, SQLITE_UTF8, &gSearch,
456 search_score_sqlfunc, 0, 0);
457 sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
458 search_init_sqlfunc, 0, 0);
459 sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
460 search_stext_sqlfunc, 0, 0);
461 sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
462 search_urlencode_sqlfunc, 0, 0);
463 }
464
465 /*
466 ** Testing the search function.
467 **
@@ -198,11 +479,10 @@
479 ** of entries returned. The -width option can be
480 ** used to set the output width used when printing
481 ** matches.
482 */
483 void search_cmd(void){
 
484 Blob pattern;
485 int i;
486 Blob sql = empty_blob;
487 Stmt q;
488 int iBest;
@@ -227,13 +507,13 @@
507 if( g.argc<2 ) return;
508 blob_init(&pattern, g.argv[2], -1);
509 for(i=3; i<g.argc; i++){
510 blob_appendf(&pattern, " %s", g.argv[i]);
511 }
512 (void)search_init(blob_str(&pattern),"*","*","...",SRCHFLG_STATIC);
513 blob_reset(&pattern);
514 search_sql_setup(g.db);
515
516 db_multi_exec(
517 "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
518 "CREATE INDEX srch_idx1 ON srch(x);"
519 "INSERT INTO srch(rid,uuid,date,comment,x)"
@@ -255,5 +535,263 @@
535 db_prepare(&q, "%s", blob_sql_text(&sql));
536 blob_reset(&sql);
537 print_timeline(&q, nLimit, width, 0);
538 db_finalize(&q);
539 }
540
541 /*
542 ** WEBPAGE: /search
543 **
544 ** This is an EXPERIMENTAL page for doing search across a repository.
545 **
546 ** The current implementation does a full text search over embedded
547 ** documentation files on the tip of the "trunk" branch. Only files
548 ** ending in ".wiki", ".md", ".html", and ".txt" are searched.
549 **
550 ** The entire text is scanned. There is no full-text index. This is
551 ** experimental. We may change to using a full-text index depending
552 ** on performance.
553 **
554 ** Other pending enhancements:
555 ** * Search tickets
556 ** * Search wiki
557 */
558 void search_page(void){
559 const char *zPattern = PD("s","");
560 Stmt q;
561 const char *zSrchEnable = "dwc";
562
563 login_check_credentials();
564 if( !g.perm.Read ){ login_needed(); return; }
565 style_header("Search");
566 @ <form method="GET" action="search"><center>
567 @ <input type="text" name="s" size="40" value="%h(zPattern)">
568 @ <input type="submit" value="Search">
569 @ </center></form>
570 while( fossil_isspace(zPattern[0]) ) zPattern++;
571 if( zPattern[0] ){
572 search_sql_setup(g.db);
573 add_content_sql_commands(g.db);
574 search_init(zPattern, "<b>", "</b>", " ... ",
575 SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
576 db_multi_exec(
577 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
578 "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
579 );
580 if( strchr(zSrchEnable, 'd') ){
581 db_multi_exec(
582 "INSERT INTO x(label,url,date,snip)"
583 " SELECT printf('Document: %%s',foci.filename),"
584 " printf('%R/doc/trunk/%%s',foci.filename),"
585 " (SELECT datetime(event.mtime) FROM event"
586 " WHERE objid=symbolic_name_to_rid('trunk')),"
587 " snippet(stext('d',blob.rid,foci.filename))"
588 " FROM foci CROSS JOIN blob"
589 " WHERE checkinID=symbolic_name_to_rid('trunk')"
590 " AND blob.uuid=foci.uuid"
591 " AND (filename GLOB '*.wiki' OR"
592 " filename GLOB '*.md' OR"
593 " filename GLOB '*.txt' OR"
594 " filename GLOB '*.html');"
595 );
596 }
597 if( strchr(zSrchEnable, 'w') ){
598 db_multi_exec(
599 "WITH wiki(name,rid,mtime) AS ("
600 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
601 " FROM tag, tagxref"
602 " WHERE tag.tagname GLOB 'wiki-*'"
603 " AND tagxref.tagid=tag.tagid"
604 " GROUP BY 1"
605 ")"
606 "INSERT INTO x(label,url,date,snip)"
607 " SELECT printf('Wiki: %%s',name),"
608 " printf('%R/wiki?name=%%s',urlencode(name)),"
609 " datetime(mtime),"
610 " snippet(stext('w',rid,name))"
611 " FROM wiki;"
612 );
613 }
614 if( strchr(zSrchEnable, 'c') ){
615 db_multi_exec(
616 "WITH ckin(uuid,rid,mtime) AS ("
617 " SELECT blob.uuid, event.objid, event.mtime"
618 " FROM event, blob"
619 " WHERE event.type='ci'"
620 " AND blob.rid=event.objid"
621 ")"
622 "INSERT INTO x(label,url,date,snip)"
623 " SELECT printf('Check-in [%%.10s] on %%s',uuid,datetime(mtime)),"
624 " printf('%R/timeline?c=%%s&n=8&y=ci',uuid),"
625 " datetime(mtime),"
626 " snippet(stext('c',rid,NULL))"
627 " FROM ckin;"
628 );
629 }
630 db_prepare(&q, "SELECT url, substr(snip,9), label"
631 " FROM x WHERE snip IS NOT NULL"
632 " ORDER BY substr(snip,1,9) DESC, date DESC;");
633 @ <ol>
634 while( db_step(&q)==SQLITE_ROW ){
635 const char *zUrl = db_column_text(&q, 0);
636 const char *zSnippet = db_column_text(&q, 1);
637 const char *zLabel = db_column_text(&q, 2);
638 @ <li><p>%s(href("%s",zUrl))%h(zLabel)</a><br>%s(zSnippet)</li>
639 }
640 db_finalize(&q);
641 @ </ol>
642 }
643 style_footer();
644 }
645
646
647 /*
648 ** This is a helper function for search_stext(). Writing into pOut
649 ** the search text obtained from pIn according to zMimetype.
650 */
651 static void get_stext_by_mimetype(
652 Blob *pIn,
653 const char *zMimetype,
654 Blob *pOut
655 ){
656 Blob html, title;
657 blob_init(&html, 0, 0);
658 blob_init(&title, 0, 0);
659 if( zMimetype==0 ) zMimetype = "text/plain";
660 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){
661 wiki_convert(pIn, &html, 0);
662 html_to_plaintext(blob_str(&html), pOut);
663 }else if( fossil_strcmp(zMimetype,"text/x-markdown")==0 ){
664 markdown_to_html(pIn, &title, &html);
665 html_to_plaintext(blob_str(&html), pOut);
666 }else if( fossil_strcmp(zMimetype,"text/html")==0 ){
667 html_to_plaintext(blob_str(pIn), pOut);
668 }else{
669 *pOut = *pIn;
670 blob_init(pIn, 0, 0);
671 }
672 blob_reset(&html);
673 blob_reset(&title);
674 }
675
676 /*
677 ** Return "search text" - a reduced version of a document appropriate for
678 ** full text search and/or for constructing a search result snippet.
679 **
680 ** cType: d Embedded documentation
681 ** s Source code listing
682 ** w Wiki page
683 ** c Check-in comment
684 ** t Ticket text
685 ** e Event/Blog text
686 ** k Diff of a wiki
687 ** f Diff of a checkin
688 **
689 ** zArg1, zArg2: Description of the document, depending on cType.
690 */
691 void search_stext(
692 char cType, /* Type of document */
693 const char *zArg1, /* First parameter */
694 const char *zArg2, /* Second parameter */
695 Blob *pOut /* OUT: Initialize to the search text */
696 ){
697 blob_init(pOut, 0, 0);
698 switch( cType ){
699 case 'd': /* Doc. zArg1: RID of the file. zArg2: Filename */
700 case 's': { /* Source. zArg1: RID of the file. zArg2: Filename */
701 int rid = atoi(zArg1);
702 Blob doc;
703 content_get(rid, &doc);
704 blob_to_utf8_no_bom(&doc, 0);
705 get_stext_by_mimetype(&doc, mimetype_from_name(zArg2), pOut);
706 blob_reset(&doc);
707 break;
708 }
709 case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
710 int rid = atoi(zArg1);
711 Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
712 Blob wiki;
713 if( pWiki==0 ) break;
714 blob_init(&wiki, pWiki->zWiki, -1);
715 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
716 pOut);
717 blob_reset(&wiki);
718 manifest_destroy(pWiki);
719 break;
720 }
721 case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
722 int rid = atoi(zArg1);
723 static Stmt q;
724 db_static_prepare(&q,
725 "SELECT coalesce(ecomment,comment)"
726 " ||' (user: '||coalesce(euser,user,'?')"
727 " ||', tags: '||"
728 " (SELECT group_concat(substr(tag.tagname,5),',')"
729 " FROM tag, tagxref"
730 " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
731 " AND tagxref.rid=event.objid AND tagxref.tagtype>0)"
732 " ||')'"
733 " FROM event WHERE objid=:x AND type='ci'");
734 db_bind_int(&q, ":x", rid);
735 if( db_step(&q)==SQLITE_ROW ){
736 db_column_blob(&q, 0, pOut);
737 blob_append(pOut, "\n", 1);
738 }
739 db_reset(&q);
740 break;
741 }
742 }
743 }
744
745 /*
746 ** The arguments cType,zArg1,zArg2 define an object that can be searched
747 ** for. Return a URL (relative to the root of the Fossil project) that
748 ** will jump to that document.
749 **
750 ** Space to hold the returned string is obtained from mprintf() and should
751 ** be freed by the caller using fossil_free() or the equivalent.
752 */
753 char *search_url(
754 char cType, /* Type of document */
755 const char *zArg1, /* First parameter */
756 const char *zArg2 /* Second parameter */
757 ){
758 char *zUrl = 0;
759 switch( cType ){
760 case 'd': { /* Doc. zArg1: RID of the file. zArg2: Filename */
761 case 's': /* Source. zArg1: RID of the file. zArg2: Filename */
762 zUrl = db_text(0,
763 "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
764 " FROM mlink, blob"
765 " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
766 zArg2, atoi(zArg1));
767 break;
768 }
769 case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
770 char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
771 zUrl = mprintf("/wiki?id=%z&name=%t", zId, zArg2);
772 break;
773 }
774 case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
775 char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
776 zUrl = mprintf("/info/%z", zId);
777 break;
778 }
779 }
780 return zUrl;
781 }
782
783 /*
784 ** COMMAND: test-search-stext
785 **
786 ** Usage: fossil test-search-stext TYPE ARG1 ARG2
787 */
788 void test_search_stext(void){
789 Blob out;
790 char *zUrl;
791 db_find_and_open_repository(0,0);
792 if( g.argc!=5 ) usage("TYPE ARG1 ARG2");
793 search_stext(g.argv[2][0], g.argv[3], g.argv[4], &out);
794 zUrl = search_url(g.argv[2][0], g.argv[3], g.argv[4]);
795 fossil_print("%s\n%z\n",blob_str(&out),zUrl);
796 blob_reset(&out);
797 }
798
+62 -27
--- src/setup.c
+++ src/setup.c
@@ -151,11 +151,11 @@
151151
"SELECT uid, login, cap, info, 1 FROM user"
152152
" WHERE login IN ('anonymous','nobody','developer','reader') "
153153
" UNION ALL "
154154
"SELECT uid, login, cap, info, 2 FROM user"
155155
" WHERE login NOT IN ('anonymous','nobody','developer','reader') "
156
- "ORDER BY 5, 2"
156
+ "ORDER BY 5, 2 COLLATE nocase"
157157
);
158158
while( db_step(&s)==SQLITE_ROW ){
159159
int iLevel = db_column_int(&s, 4);
160160
const char *zCap = db_column_text(&s, 2);
161161
const char *zLogin = db_column_text(&s, 1);
@@ -813,17 +813,13 @@
813813
@ <ul>
814814
@ <li><p>
815815
@ No login is required for user <span class="usertype">nobody</span>. The
816816
@ capabilities of the <span class="usertype">nobody</span> user are
817817
@ inherited by all users, regardless of whether or not they are logged in.
818
- @ To disable universal access to the repository, make sure no user named
819
- @ <span class="usertype">nobody</span> exists or that the
818
+ @ To disable universal access to the repository, make sure that the
820819
@ <span class="usertype">nobody</span> user has no capabilities
821820
@ enabled. The password for <span class="usertype">nobody</span> is ignored.
822
- @ To avoid problems with spiders overloading the server, it is recommended
823
- @ that the <span class="capability">h</span> (Hyperlinks) capability be
824
- @ turned off for the <span class="usertype">nobody</span> user.
825821
@ </p></li>
826822
@
827823
@ <li><p>
828824
@ Login is required for user <span class="usertype">anonymous</span> but the
829825
@ password is displayed on the login screen beside the password entry box
@@ -995,11 +991,11 @@
995991
login_insert_csrf_secret();
996992
@ <hr />
997993
onoff_attribute("Redirect to HTTPS on the Login page",
998994
"redirect-to-https", "redirhttps", 0, 0);
999995
@ <p>When selected, force the use of HTTPS for the Login page.
1000
- @ <p>Details: When enabled, this option causes the $secureurl TH1
996
+ @ <p>Details: When enabled, this option causes the $secureurl TH1
1001997
@ variable is set to an "https:" variant of $baseurl. Otherwise,
1002998
@ $secureurl is just an alias for $baseurl. Also when enabled, the
1003999
@ Login page redirects to https if accessed via http.
10041000
@ <hr />
10051001
onoff_attribute("Require password for local access",
@@ -1525,24 +1521,26 @@
15251521
login_needed();
15261522
}
15271523
db_begin_transaction();
15281524
if( P("clear")!=0 ){
15291525
db_multi_exec("DELETE FROM config WHERE name='css'");
1530
- cgi_replace_parameter("css", zDefaultCSS);
1526
+ cgi_replace_parameter("css", builtin_text("skins/default/css.txt"));
15311527
db_end_transaction(0);
15321528
cgi_redirect("setup_editcss");
15331529
}
15341530
if( P("submit")!=0 ){
1535
- textarea_attribute(0, 0, 0, "css", "css", zDefaultCSS, 0);
1531
+ textarea_attribute(0, 0, 0, "css", "css",
1532
+ builtin_text("skins/default/css.txt"), 0);
15361533
db_end_transaction(0);
15371534
cgi_redirect("setup_editcss");
15381535
}
15391536
style_header("Edit CSS");
15401537
@ <form action="%s(g.zTop)/setup_editcss" method="post"><div>
15411538
login_insert_csrf_secret();
15421539
@ Edit the CSS below:<br />
1543
- textarea_attribute("", 35, 80, "css", "css", zDefaultCSS, 0);
1540
+ textarea_attribute("", 35, 80, "css", "css",
1541
+ builtin_text("skins/default/css.txt"), 0);
15441542
@ <br />
15451543
@ <input type="submit" name="submit" value="Apply Changes" />
15461544
@ <input type="submit" name="clear" value="Revert To Default" />
15471545
@ </div></form>
15481546
@ <p><span class="note">Note:</span> Press your browser Reload button after
@@ -1568,15 +1566,17 @@
15681566
login_needed();
15691567
}
15701568
db_begin_transaction();
15711569
if( P("clear")!=0 ){
15721570
db_multi_exec("DELETE FROM config WHERE name='header'");
1573
- cgi_replace_parameter("header", zDefaultHeader);
1571
+ cgi_replace_parameter("header", builtin_text("skins/default/header.txt"));
15741572
}else if( P("submit")!=0 ){
1575
- textarea_attribute(0, 0, 0, "header", "header", zDefaultHeader, 0);
1573
+ textarea_attribute(0, 0, 0, "header", "header",
1574
+ builtin_text("skins/default/header.txt"), 0);
15761575
}else if( P("fixbase")!=0 ){
1577
- const char *z = db_get("header", (char*)zDefaultHeader);
1576
+ const char *z = db_get("header",
1577
+ (char*)builtin_text("skins/default/header.txt"));
15781578
char *zHead = strstr(z, "<head>");
15791579
if( strstr(z, "<base href=")==0 && zHead!=0 ){
15801580
char *zNew;
15811581
char *zTail = &zHead[6];
15821582
while( fossil_isspace(zTail[0]) ) zTail++;
@@ -1598,14 +1598,15 @@
15981598
@ <tt>&lt;head&gt;</tt> in the header!
15991599
@ <input type="submit" name="fixbase" value="Add &lt;base&gt; Now"></p>
16001600
}
16011601
16021602
login_insert_csrf_secret();
1603
- @ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
1603
+ @ <p>Edit HTML text with embedded TH1 (a Tcl dialect) that will be used to
16041604
@ generate the beginning of every page through start of the main
16051605
@ menu.</p>
1606
- textarea_attribute("", 35, 80, "header", "header", zDefaultHeader, 0);
1606
+ textarea_attribute("", 35, 80, "header", "header",
1607
+ builtin_text("skins/default/header.txt"), 0);
16071608
@ <br />
16081609
@ <input type="submit" name="submit" value="Apply Changes" />
16091610
@ <input type="submit" name="clear" value="Revert To Default" />
16101611
@ </div></form>
16111612
@ <hr />
@@ -1612,11 +1613,11 @@
16121613
@ The default header is shown below for reference. Other examples
16131614
@ of headers can be seen on the <a href="setup_skin">skins page</a>.
16141615
@ See also the <a href="setup_editcss">CSS</a> and
16151616
@ <a href="setup_footer">footer</a> editing screens.
16161617
@ <blockquote><pre>
1617
- @ %h(zDefaultHeader)
1618
+ @ %h(builtin_text("skins/default/header.txt"))
16181619
@ </pre></blockquote>
16191620
style_footer();
16201621
db_end_transaction(0);
16211622
}
16221623
@@ -1629,19 +1630,20 @@
16291630
login_needed();
16301631
}
16311632
db_begin_transaction();
16321633
if( P("clear")!=0 ){
16331634
db_multi_exec("DELETE FROM config WHERE name='footer'");
1634
- cgi_replace_parameter("footer", zDefaultFooter);
1635
+ cgi_replace_parameter("footer", builtin_text("skins/default/footer.txt"));
16351636
}
16361637
16371638
style_header("Edit Page Footer");
16381639
@ <form action="%s(g.zTop)/setup_footer" method="post"><div>
16391640
login_insert_csrf_secret();
1640
- @ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
1641
+ @ <p>Edit HTML text with embedded TH1 (a Tcl dialect) that will be used to
16411642
@ generate the end of every page.</p>
1642
- textarea_attribute("", 20, 80, "footer", "footer", zDefaultFooter, 0);
1643
+ textarea_attribute("", 20, 80, "footer", "footer",
1644
+ builtin_text("skins/default/footer.txt"), 0);
16431645
@ <br />
16441646
@ <input type="submit" name="submit" value="Apply Changes" />
16451647
@ <input type="submit" name="clear" value="Revert To Default" />
16461648
@ </div></form>
16471649
@ <hr />
@@ -1648,11 +1650,11 @@
16481650
@ The default footer is shown below for reference. Other examples
16491651
@ of footers can be seen on the <a href="setup_skin">skins page</a>.
16501652
@ See also the <a href="setup_editcss">CSS</a> and
16511653
@ <a href="setup_header">header</a> editing screens.
16521654
@ <blockquote><pre>
1653
- @ %h(zDefaultFooter)
1655
+ @ %h(builtin_text("skins/default/footer.txt"))
16541656
@ </pre></blockquote>
16551657
style_footer();
16561658
db_end_transaction(0);
16571659
}
16581660
@@ -1715,13 +1717,15 @@
17151717
}
17161718
17171719
style_header("Edit Ad Unit");
17181720
@ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
17191721
login_insert_csrf_secret();
1720
- @ <p>Edit HTML text for an ad unit that will be inserted after the
1721
- @ menu bar and above the content of every page.</p>
1722
- textarea_attribute("", 20, 80, "adunit", "adunit", "", 0);
1722
+ @ <b>Banner Ad-Unit:</b><br />
1723
+ textarea_attribute("", 6, 80, "adunit", "adunit", "", 0);
1724
+ @ <br />
1725
+ @ <b>Right-Column Ad-Unit:</b><br />
1726
+ textarea_attribute("", 6, 80, "adunit-right", "adright", "", 0);
17231727
@ <br />
17241728
onoff_attribute("Omit ads to administrator",
17251729
"adunit-omit-if-admin", "oia", 0, 0);
17261730
@ <br />
17271731
onoff_attribute("Omit ads to logged-in users",
@@ -1728,10 +1732,41 @@
17281732
"adunit-omit-if-user", "oiu", 0, 0);
17291733
@ <br />
17301734
@ <input type="submit" name="submit" value="Apply Changes" />
17311735
@ <input type="submit" name="clear" value="Delete Ad-Unit" />
17321736
@ </div></form>
1737
+ @ <hr />
1738
+ @ <b>Ad-Unit Notes:</b><ul>
1739
+ @ <li>Leave both Ad-Units blank to disable all advertising.
1740
+ @ <li>The "Banner Ad-Unit" is used for wide pages.
1741
+ @ <li>The "Right-Column Ad-Unit" is used on pages with tall, narrow content.
1742
+ @ <li>If the "Right-Column Ad-Unit" is blank, the "Banner Ad-Unit" is used on all pages.
1743
+ @ <li>Suggested <a href="setup_editcss">CSS</a> changes:
1744
+ @ <blockquote><pre>
1745
+ @ div.adunit_banner {
1746
+ @ margin: auto;
1747
+ @ width: 100%;
1748
+ @ }
1749
+ @ div.adunit_right {
1750
+ @ float: right;
1751
+ @ }
1752
+ @ div.adunit_right_container {
1753
+ @ min-height: <i>height-of-right-column-ad-unit</i>;
1754
+ @ }
1755
+ @ </pre></blockquote>
1756
+ @ <li>For a place-holder Ad-Unit for testing, Copy/Paste the following
1757
+ @ with appropriate adjustments to "width:" and "height:".
1758
+ @ <blockquote><pre>
1759
+ @ &lt;div style='
1760
+ @ margin: 0 auto;
1761
+ @ width: 600px;
1762
+ @ height: 90px;
1763
+ @ border: 1px solid #f11;
1764
+ @ background-color: #fcc;
1765
+ @ '&gt;Demo Ad&lt;/div&gt;
1766
+ @ </pre></blockquote>
1767
+ @ </li>
17331768
style_footer();
17341769
db_end_transaction(0);
17351770
}
17361771
17371772
/*
@@ -2103,14 +2138,14 @@
21032138
@ <th>User</th>
21042139
@ <th>Page</th>
21052140
@ <th width="60%%">Message</th>
21062141
@ </thead><tbody>
21072142
while( SQLITE_ROW == db_step(&stLog) ){
2108
- char const * zTime = db_column_text(&stLog, 0);
2109
- char const * zUser = db_column_text(&stLog, 1);
2110
- char const * zPage = db_column_text(&stLog, 2);
2111
- char const * zMessage = db_column_text(&stLog, 3);
2143
+ const char *zTime = db_column_text(&stLog, 0);
2144
+ const char *zUser = db_column_text(&stLog, 1);
2145
+ const char *zPage = db_column_text(&stLog, 2);
2146
+ const char *zMessage = db_column_text(&stLog, 3);
21122147
@ <tr class="row%d(counter++%2)">
21132148
@ <td class="adminTime">%s(zTime)</td>
21142149
@ <td>%s(zUser)</td>
21152150
@ <td>%s(zPage)</td>
21162151
@ <td>%h(zMessage)</td>
21172152
--- src/setup.c
+++ src/setup.c
@@ -151,11 +151,11 @@
151 "SELECT uid, login, cap, info, 1 FROM user"
152 " WHERE login IN ('anonymous','nobody','developer','reader') "
153 " UNION ALL "
154 "SELECT uid, login, cap, info, 2 FROM user"
155 " WHERE login NOT IN ('anonymous','nobody','developer','reader') "
156 "ORDER BY 5, 2"
157 );
158 while( db_step(&s)==SQLITE_ROW ){
159 int iLevel = db_column_int(&s, 4);
160 const char *zCap = db_column_text(&s, 2);
161 const char *zLogin = db_column_text(&s, 1);
@@ -813,17 +813,13 @@
813 @ <ul>
814 @ <li><p>
815 @ No login is required for user <span class="usertype">nobody</span>. The
816 @ capabilities of the <span class="usertype">nobody</span> user are
817 @ inherited by all users, regardless of whether or not they are logged in.
818 @ To disable universal access to the repository, make sure no user named
819 @ <span class="usertype">nobody</span> exists or that the
820 @ <span class="usertype">nobody</span> user has no capabilities
821 @ enabled. The password for <span class="usertype">nobody</span> is ignored.
822 @ To avoid problems with spiders overloading the server, it is recommended
823 @ that the <span class="capability">h</span> (Hyperlinks) capability be
824 @ turned off for the <span class="usertype">nobody</span> user.
825 @ </p></li>
826 @
827 @ <li><p>
828 @ Login is required for user <span class="usertype">anonymous</span> but the
829 @ password is displayed on the login screen beside the password entry box
@@ -995,11 +991,11 @@
995 login_insert_csrf_secret();
996 @ <hr />
997 onoff_attribute("Redirect to HTTPS on the Login page",
998 "redirect-to-https", "redirhttps", 0, 0);
999 @ <p>When selected, force the use of HTTPS for the Login page.
1000 @ <p>Details: When enabled, this option causes the $secureurl TH1
1001 @ variable is set to an "https:" variant of $baseurl. Otherwise,
1002 @ $secureurl is just an alias for $baseurl. Also when enabled, the
1003 @ Login page redirects to https if accessed via http.
1004 @ <hr />
1005 onoff_attribute("Require password for local access",
@@ -1525,24 +1521,26 @@
1525 login_needed();
1526 }
1527 db_begin_transaction();
1528 if( P("clear")!=0 ){
1529 db_multi_exec("DELETE FROM config WHERE name='css'");
1530 cgi_replace_parameter("css", zDefaultCSS);
1531 db_end_transaction(0);
1532 cgi_redirect("setup_editcss");
1533 }
1534 if( P("submit")!=0 ){
1535 textarea_attribute(0, 0, 0, "css", "css", zDefaultCSS, 0);
 
1536 db_end_transaction(0);
1537 cgi_redirect("setup_editcss");
1538 }
1539 style_header("Edit CSS");
1540 @ <form action="%s(g.zTop)/setup_editcss" method="post"><div>
1541 login_insert_csrf_secret();
1542 @ Edit the CSS below:<br />
1543 textarea_attribute("", 35, 80, "css", "css", zDefaultCSS, 0);
 
1544 @ <br />
1545 @ <input type="submit" name="submit" value="Apply Changes" />
1546 @ <input type="submit" name="clear" value="Revert To Default" />
1547 @ </div></form>
1548 @ <p><span class="note">Note:</span> Press your browser Reload button after
@@ -1568,15 +1566,17 @@
1568 login_needed();
1569 }
1570 db_begin_transaction();
1571 if( P("clear")!=0 ){
1572 db_multi_exec("DELETE FROM config WHERE name='header'");
1573 cgi_replace_parameter("header", zDefaultHeader);
1574 }else if( P("submit")!=0 ){
1575 textarea_attribute(0, 0, 0, "header", "header", zDefaultHeader, 0);
 
1576 }else if( P("fixbase")!=0 ){
1577 const char *z = db_get("header", (char*)zDefaultHeader);
 
1578 char *zHead = strstr(z, "<head>");
1579 if( strstr(z, "<base href=")==0 && zHead!=0 ){
1580 char *zNew;
1581 char *zTail = &zHead[6];
1582 while( fossil_isspace(zTail[0]) ) zTail++;
@@ -1598,14 +1598,15 @@
1598 @ <tt>&lt;head&gt;</tt> in the header!
1599 @ <input type="submit" name="fixbase" value="Add &lt;base&gt; Now"></p>
1600 }
1601
1602 login_insert_csrf_secret();
1603 @ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
1604 @ generate the beginning of every page through start of the main
1605 @ menu.</p>
1606 textarea_attribute("", 35, 80, "header", "header", zDefaultHeader, 0);
 
1607 @ <br />
1608 @ <input type="submit" name="submit" value="Apply Changes" />
1609 @ <input type="submit" name="clear" value="Revert To Default" />
1610 @ </div></form>
1611 @ <hr />
@@ -1612,11 +1613,11 @@
1612 @ The default header is shown below for reference. Other examples
1613 @ of headers can be seen on the <a href="setup_skin">skins page</a>.
1614 @ See also the <a href="setup_editcss">CSS</a> and
1615 @ <a href="setup_footer">footer</a> editing screens.
1616 @ <blockquote><pre>
1617 @ %h(zDefaultHeader)
1618 @ </pre></blockquote>
1619 style_footer();
1620 db_end_transaction(0);
1621 }
1622
@@ -1629,19 +1630,20 @@
1629 login_needed();
1630 }
1631 db_begin_transaction();
1632 if( P("clear")!=0 ){
1633 db_multi_exec("DELETE FROM config WHERE name='footer'");
1634 cgi_replace_parameter("footer", zDefaultFooter);
1635 }
1636
1637 style_header("Edit Page Footer");
1638 @ <form action="%s(g.zTop)/setup_footer" method="post"><div>
1639 login_insert_csrf_secret();
1640 @ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
1641 @ generate the end of every page.</p>
1642 textarea_attribute("", 20, 80, "footer", "footer", zDefaultFooter, 0);
 
1643 @ <br />
1644 @ <input type="submit" name="submit" value="Apply Changes" />
1645 @ <input type="submit" name="clear" value="Revert To Default" />
1646 @ </div></form>
1647 @ <hr />
@@ -1648,11 +1650,11 @@
1648 @ The default footer is shown below for reference. Other examples
1649 @ of footers can be seen on the <a href="setup_skin">skins page</a>.
1650 @ See also the <a href="setup_editcss">CSS</a> and
1651 @ <a href="setup_header">header</a> editing screens.
1652 @ <blockquote><pre>
1653 @ %h(zDefaultFooter)
1654 @ </pre></blockquote>
1655 style_footer();
1656 db_end_transaction(0);
1657 }
1658
@@ -1715,13 +1717,15 @@
1715 }
1716
1717 style_header("Edit Ad Unit");
1718 @ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
1719 login_insert_csrf_secret();
1720 @ <p>Edit HTML text for an ad unit that will be inserted after the
1721 @ menu bar and above the content of every page.</p>
1722 textarea_attribute("", 20, 80, "adunit", "adunit", "", 0);
 
 
1723 @ <br />
1724 onoff_attribute("Omit ads to administrator",
1725 "adunit-omit-if-admin", "oia", 0, 0);
1726 @ <br />
1727 onoff_attribute("Omit ads to logged-in users",
@@ -1728,10 +1732,41 @@
1728 "adunit-omit-if-user", "oiu", 0, 0);
1729 @ <br />
1730 @ <input type="submit" name="submit" value="Apply Changes" />
1731 @ <input type="submit" name="clear" value="Delete Ad-Unit" />
1732 @ </div></form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1733 style_footer();
1734 db_end_transaction(0);
1735 }
1736
1737 /*
@@ -2103,14 +2138,14 @@
2103 @ <th>User</th>
2104 @ <th>Page</th>
2105 @ <th width="60%%">Message</th>
2106 @ </thead><tbody>
2107 while( SQLITE_ROW == db_step(&stLog) ){
2108 char const * zTime = db_column_text(&stLog, 0);
2109 char const * zUser = db_column_text(&stLog, 1);
2110 char const * zPage = db_column_text(&stLog, 2);
2111 char const * zMessage = db_column_text(&stLog, 3);
2112 @ <tr class="row%d(counter++%2)">
2113 @ <td class="adminTime">%s(zTime)</td>
2114 @ <td>%s(zUser)</td>
2115 @ <td>%s(zPage)</td>
2116 @ <td>%h(zMessage)</td>
2117
--- src/setup.c
+++ src/setup.c
@@ -151,11 +151,11 @@
151 "SELECT uid, login, cap, info, 1 FROM user"
152 " WHERE login IN ('anonymous','nobody','developer','reader') "
153 " UNION ALL "
154 "SELECT uid, login, cap, info, 2 FROM user"
155 " WHERE login NOT IN ('anonymous','nobody','developer','reader') "
156 "ORDER BY 5, 2 COLLATE nocase"
157 );
158 while( db_step(&s)==SQLITE_ROW ){
159 int iLevel = db_column_int(&s, 4);
160 const char *zCap = db_column_text(&s, 2);
161 const char *zLogin = db_column_text(&s, 1);
@@ -813,17 +813,13 @@
813 @ <ul>
814 @ <li><p>
815 @ No login is required for user <span class="usertype">nobody</span>. The
816 @ capabilities of the <span class="usertype">nobody</span> user are
817 @ inherited by all users, regardless of whether or not they are logged in.
818 @ To disable universal access to the repository, make sure that the
 
819 @ <span class="usertype">nobody</span> user has no capabilities
820 @ enabled. The password for <span class="usertype">nobody</span> is ignored.
 
 
 
821 @ </p></li>
822 @
823 @ <li><p>
824 @ Login is required for user <span class="usertype">anonymous</span> but the
825 @ password is displayed on the login screen beside the password entry box
@@ -995,11 +991,11 @@
991 login_insert_csrf_secret();
992 @ <hr />
993 onoff_attribute("Redirect to HTTPS on the Login page",
994 "redirect-to-https", "redirhttps", 0, 0);
995 @ <p>When selected, force the use of HTTPS for the Login page.
996 @ <p>Details: When enabled, this option causes the $secureurl TH1
997 @ variable is set to an "https:" variant of $baseurl. Otherwise,
998 @ $secureurl is just an alias for $baseurl. Also when enabled, the
999 @ Login page redirects to https if accessed via http.
1000 @ <hr />
1001 onoff_attribute("Require password for local access",
@@ -1525,24 +1521,26 @@
1521 login_needed();
1522 }
1523 db_begin_transaction();
1524 if( P("clear")!=0 ){
1525 db_multi_exec("DELETE FROM config WHERE name='css'");
1526 cgi_replace_parameter("css", builtin_text("skins/default/css.txt"));
1527 db_end_transaction(0);
1528 cgi_redirect("setup_editcss");
1529 }
1530 if( P("submit")!=0 ){
1531 textarea_attribute(0, 0, 0, "css", "css",
1532 builtin_text("skins/default/css.txt"), 0);
1533 db_end_transaction(0);
1534 cgi_redirect("setup_editcss");
1535 }
1536 style_header("Edit CSS");
1537 @ <form action="%s(g.zTop)/setup_editcss" method="post"><div>
1538 login_insert_csrf_secret();
1539 @ Edit the CSS below:<br />
1540 textarea_attribute("", 35, 80, "css", "css",
1541 builtin_text("skins/default/css.txt"), 0);
1542 @ <br />
1543 @ <input type="submit" name="submit" value="Apply Changes" />
1544 @ <input type="submit" name="clear" value="Revert To Default" />
1545 @ </div></form>
1546 @ <p><span class="note">Note:</span> Press your browser Reload button after
@@ -1568,15 +1566,17 @@
1566 login_needed();
1567 }
1568 db_begin_transaction();
1569 if( P("clear")!=0 ){
1570 db_multi_exec("DELETE FROM config WHERE name='header'");
1571 cgi_replace_parameter("header", builtin_text("skins/default/header.txt"));
1572 }else if( P("submit")!=0 ){
1573 textarea_attribute(0, 0, 0, "header", "header",
1574 builtin_text("skins/default/header.txt"), 0);
1575 }else if( P("fixbase")!=0 ){
1576 const char *z = db_get("header",
1577 (char*)builtin_text("skins/default/header.txt"));
1578 char *zHead = strstr(z, "<head>");
1579 if( strstr(z, "<base href=")==0 && zHead!=0 ){
1580 char *zNew;
1581 char *zTail = &zHead[6];
1582 while( fossil_isspace(zTail[0]) ) zTail++;
@@ -1598,14 +1598,15 @@
1598 @ <tt>&lt;head&gt;</tt> in the header!
1599 @ <input type="submit" name="fixbase" value="Add &lt;base&gt; Now"></p>
1600 }
1601
1602 login_insert_csrf_secret();
1603 @ <p>Edit HTML text with embedded TH1 (a Tcl dialect) that will be used to
1604 @ generate the beginning of every page through start of the main
1605 @ menu.</p>
1606 textarea_attribute("", 35, 80, "header", "header",
1607 builtin_text("skins/default/header.txt"), 0);
1608 @ <br />
1609 @ <input type="submit" name="submit" value="Apply Changes" />
1610 @ <input type="submit" name="clear" value="Revert To Default" />
1611 @ </div></form>
1612 @ <hr />
@@ -1612,11 +1613,11 @@
1613 @ The default header is shown below for reference. Other examples
1614 @ of headers can be seen on the <a href="setup_skin">skins page</a>.
1615 @ See also the <a href="setup_editcss">CSS</a> and
1616 @ <a href="setup_footer">footer</a> editing screens.
1617 @ <blockquote><pre>
1618 @ %h(builtin_text("skins/default/header.txt"))
1619 @ </pre></blockquote>
1620 style_footer();
1621 db_end_transaction(0);
1622 }
1623
@@ -1629,19 +1630,20 @@
1630 login_needed();
1631 }
1632 db_begin_transaction();
1633 if( P("clear")!=0 ){
1634 db_multi_exec("DELETE FROM config WHERE name='footer'");
1635 cgi_replace_parameter("footer", builtin_text("skins/default/footer.txt"));
1636 }
1637
1638 style_header("Edit Page Footer");
1639 @ <form action="%s(g.zTop)/setup_footer" method="post"><div>
1640 login_insert_csrf_secret();
1641 @ <p>Edit HTML text with embedded TH1 (a Tcl dialect) that will be used to
1642 @ generate the end of every page.</p>
1643 textarea_attribute("", 20, 80, "footer", "footer",
1644 builtin_text("skins/default/footer.txt"), 0);
1645 @ <br />
1646 @ <input type="submit" name="submit" value="Apply Changes" />
1647 @ <input type="submit" name="clear" value="Revert To Default" />
1648 @ </div></form>
1649 @ <hr />
@@ -1648,11 +1650,11 @@
1650 @ The default footer is shown below for reference. Other examples
1651 @ of footers can be seen on the <a href="setup_skin">skins page</a>.
1652 @ See also the <a href="setup_editcss">CSS</a> and
1653 @ <a href="setup_header">header</a> editing screens.
1654 @ <blockquote><pre>
1655 @ %h(builtin_text("skins/default/footer.txt"))
1656 @ </pre></blockquote>
1657 style_footer();
1658 db_end_transaction(0);
1659 }
1660
@@ -1715,13 +1717,15 @@
1717 }
1718
1719 style_header("Edit Ad Unit");
1720 @ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
1721 login_insert_csrf_secret();
1722 @ <b>Banner Ad-Unit:</b><br />
1723 textarea_attribute("", 6, 80, "adunit", "adunit", "", 0);
1724 @ <br />
1725 @ <b>Right-Column Ad-Unit:</b><br />
1726 textarea_attribute("", 6, 80, "adunit-right", "adright", "", 0);
1727 @ <br />
1728 onoff_attribute("Omit ads to administrator",
1729 "adunit-omit-if-admin", "oia", 0, 0);
1730 @ <br />
1731 onoff_attribute("Omit ads to logged-in users",
@@ -1728,10 +1732,41 @@
1732 "adunit-omit-if-user", "oiu", 0, 0);
1733 @ <br />
1734 @ <input type="submit" name="submit" value="Apply Changes" />
1735 @ <input type="submit" name="clear" value="Delete Ad-Unit" />
1736 @ </div></form>
1737 @ <hr />
1738 @ <b>Ad-Unit Notes:</b><ul>
1739 @ <li>Leave both Ad-Units blank to disable all advertising.
1740 @ <li>The "Banner Ad-Unit" is used for wide pages.
1741 @ <li>The "Right-Column Ad-Unit" is used on pages with tall, narrow content.
1742 @ <li>If the "Right-Column Ad-Unit" is blank, the "Banner Ad-Unit" is used on all pages.
1743 @ <li>Suggested <a href="setup_editcss">CSS</a> changes:
1744 @ <blockquote><pre>
1745 @ div.adunit_banner {
1746 @ margin: auto;
1747 @ width: 100%;
1748 @ }
1749 @ div.adunit_right {
1750 @ float: right;
1751 @ }
1752 @ div.adunit_right_container {
1753 @ min-height: <i>height-of-right-column-ad-unit</i>;
1754 @ }
1755 @ </pre></blockquote>
1756 @ <li>For a place-holder Ad-Unit for testing, Copy/Paste the following
1757 @ with appropriate adjustments to "width:" and "height:".
1758 @ <blockquote><pre>
1759 @ &lt;div style='
1760 @ margin: 0 auto;
1761 @ width: 600px;
1762 @ height: 90px;
1763 @ border: 1px solid #f11;
1764 @ background-color: #fcc;
1765 @ '&gt;Demo Ad&lt;/div&gt;
1766 @ </pre></blockquote>
1767 @ </li>
1768 style_footer();
1769 db_end_transaction(0);
1770 }
1771
1772 /*
@@ -2103,14 +2138,14 @@
2138 @ <th>User</th>
2139 @ <th>Page</th>
2140 @ <th width="60%%">Message</th>
2141 @ </thead><tbody>
2142 while( SQLITE_ROW == db_step(&stLog) ){
2143 const char *zTime = db_column_text(&stLog, 0);
2144 const char *zUser = db_column_text(&stLog, 1);
2145 const char *zPage = db_column_text(&stLog, 2);
2146 const char *zMessage = db_column_text(&stLog, 3);
2147 @ <tr class="row%d(counter++%2)">
2148 @ <td class="adminTime">%s(zTime)</td>
2149 @ <td>%s(zUser)</td>
2150 @ <td>%s(zPage)</td>
2151 @ <td>%h(zMessage)</td>
2152
+7 -7
--- src/sha1.c
+++ src/sha1.c
@@ -64,11 +64,11 @@
6464
^block[(i+2)&15]^block[i&15],1))
6565
6666
/*
6767
* (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
6868
*
69
- * Rl0() for little-endian and Rb0() for big-endian. Endianness is
69
+ * Rl0() for little-endian and Rb0() for big-endian. Endianness is
7070
* determined at run-time.
7171
*/
7272
#define Rl0(v,w,x,y,z,i) \
7373
z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
7474
#define Rb0(v,w,x,y,z,i) \
@@ -217,11 +217,11 @@
217217
** "unsigned char digest[20]" in the calling function. The SHA1
218218
** digest is stored in the first 20 bytes. zBuf should
219219
** be "char zBuf[41]".
220220
*/
221221
static void DigestToBase16(unsigned char *digest, char *zBuf){
222
- static char const zEncode[] = "0123456789abcdef";
222
+ static const char zEncode[] = "0123456789abcdef";
223223
int ix;
224224
225225
for(ix=0; ix<20; ix++){
226226
*zBuf++ = zEncode[(*digest>>4)&0xf];
227227
*zBuf++ = zEncode[*digest++ & 0xf];
@@ -258,11 +258,11 @@
258258
sha1sum_step_text(blob_buffer(p), blob_size(p));
259259
}
260260
261261
/*
262262
** Finish the incremental SHA1 checksum. Store the result in blob pOut
263
-** if pOut!=0. Also return a pointer to the result.
263
+** if pOut!=0. Also return a pointer to the result.
264264
**
265265
** This resets the incremental checksum preparing for the next round
266266
** of computation. The return pointer points to a static buffer that
267267
** is overwritten by subsequent calls to this function.
268268
*/
@@ -295,11 +295,11 @@
295295
296296
if( file_wd_islink(zFilename) ){
297297
/* Instead of file content, return sha1 of link destination path */
298298
Blob destinationPath;
299299
int rc;
300
-
300
+
301301
blob_read_link(&destinationPath, zFilename);
302302
rc = sha1sum_blob(&destinationPath, pCksum);
303303
blob_reset(&destinationPath);
304304
return rc;
305305
}
@@ -363,11 +363,11 @@
363363
return mprintf("%s", zDigest);
364364
}
365365
366366
/*
367367
** Convert a cleartext password for a specific user into a SHA1 hash.
368
-**
368
+**
369369
** The algorithm here is:
370370
**
371371
** SHA1( project-code + "/" + login + "/" + password )
372372
**
373373
** In words: The users login name and password are appended to the
@@ -375,11 +375,11 @@
375375
**
376376
** The result of this function is the shared secret used by a client
377377
** to authenticate to a server for the sync protocol. It is also the
378378
** value stored in the USER.PW field of the database. By mixing in the
379379
** login name and the project id with the hash, different shared secrets
380
-** are obtained even if two users select the same password, or if a
380
+** are obtained even if two users select the same password, or if a
381381
** single user selects the same password for multiple projects.
382382
*/
383383
char *sha1_shared_secret(
384384
const char *zPw, /* The password to encrypt */
385385
const char *zLogin, /* Username */
@@ -457,11 +457,11 @@
457457
*/
458458
void sha1sum_test(void){
459459
int i;
460460
Blob in;
461461
Blob cksum;
462
-
462
+
463463
for(i=2; i<g.argc; i++){
464464
blob_init(&cksum, "************** not found ***************", -1);
465465
if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
466466
blob_read_from_channel(&in, stdin, -1);
467467
sha1sum_blob(&in, &cksum);
468468
--- src/sha1.c
+++ src/sha1.c
@@ -64,11 +64,11 @@
64 ^block[(i+2)&15]^block[i&15],1))
65
66 /*
67 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
68 *
69 * Rl0() for little-endian and Rb0() for big-endian. Endianness is
70 * determined at run-time.
71 */
72 #define Rl0(v,w,x,y,z,i) \
73 z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
74 #define Rb0(v,w,x,y,z,i) \
@@ -217,11 +217,11 @@
217 ** "unsigned char digest[20]" in the calling function. The SHA1
218 ** digest is stored in the first 20 bytes. zBuf should
219 ** be "char zBuf[41]".
220 */
221 static void DigestToBase16(unsigned char *digest, char *zBuf){
222 static char const zEncode[] = "0123456789abcdef";
223 int ix;
224
225 for(ix=0; ix<20; ix++){
226 *zBuf++ = zEncode[(*digest>>4)&0xf];
227 *zBuf++ = zEncode[*digest++ & 0xf];
@@ -258,11 +258,11 @@
258 sha1sum_step_text(blob_buffer(p), blob_size(p));
259 }
260
261 /*
262 ** Finish the incremental SHA1 checksum. Store the result in blob pOut
263 ** if pOut!=0. Also return a pointer to the result.
264 **
265 ** This resets the incremental checksum preparing for the next round
266 ** of computation. The return pointer points to a static buffer that
267 ** is overwritten by subsequent calls to this function.
268 */
@@ -295,11 +295,11 @@
295
296 if( file_wd_islink(zFilename) ){
297 /* Instead of file content, return sha1 of link destination path */
298 Blob destinationPath;
299 int rc;
300
301 blob_read_link(&destinationPath, zFilename);
302 rc = sha1sum_blob(&destinationPath, pCksum);
303 blob_reset(&destinationPath);
304 return rc;
305 }
@@ -363,11 +363,11 @@
363 return mprintf("%s", zDigest);
364 }
365
366 /*
367 ** Convert a cleartext password for a specific user into a SHA1 hash.
368 **
369 ** The algorithm here is:
370 **
371 ** SHA1( project-code + "/" + login + "/" + password )
372 **
373 ** In words: The users login name and password are appended to the
@@ -375,11 +375,11 @@
375 **
376 ** The result of this function is the shared secret used by a client
377 ** to authenticate to a server for the sync protocol. It is also the
378 ** value stored in the USER.PW field of the database. By mixing in the
379 ** login name and the project id with the hash, different shared secrets
380 ** are obtained even if two users select the same password, or if a
381 ** single user selects the same password for multiple projects.
382 */
383 char *sha1_shared_secret(
384 const char *zPw, /* The password to encrypt */
385 const char *zLogin, /* Username */
@@ -457,11 +457,11 @@
457 */
458 void sha1sum_test(void){
459 int i;
460 Blob in;
461 Blob cksum;
462
463 for(i=2; i<g.argc; i++){
464 blob_init(&cksum, "************** not found ***************", -1);
465 if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
466 blob_read_from_channel(&in, stdin, -1);
467 sha1sum_blob(&in, &cksum);
468
--- src/sha1.c
+++ src/sha1.c
@@ -64,11 +64,11 @@
64 ^block[(i+2)&15]^block[i&15],1))
65
66 /*
67 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
68 *
69 * Rl0() for little-endian and Rb0() for big-endian. Endianness is
70 * determined at run-time.
71 */
72 #define Rl0(v,w,x,y,z,i) \
73 z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
74 #define Rb0(v,w,x,y,z,i) \
@@ -217,11 +217,11 @@
217 ** "unsigned char digest[20]" in the calling function. The SHA1
218 ** digest is stored in the first 20 bytes. zBuf should
219 ** be "char zBuf[41]".
220 */
221 static void DigestToBase16(unsigned char *digest, char *zBuf){
222 static const char zEncode[] = "0123456789abcdef";
223 int ix;
224
225 for(ix=0; ix<20; ix++){
226 *zBuf++ = zEncode[(*digest>>4)&0xf];
227 *zBuf++ = zEncode[*digest++ & 0xf];
@@ -258,11 +258,11 @@
258 sha1sum_step_text(blob_buffer(p), blob_size(p));
259 }
260
261 /*
262 ** Finish the incremental SHA1 checksum. Store the result in blob pOut
263 ** if pOut!=0. Also return a pointer to the result.
264 **
265 ** This resets the incremental checksum preparing for the next round
266 ** of computation. The return pointer points to a static buffer that
267 ** is overwritten by subsequent calls to this function.
268 */
@@ -295,11 +295,11 @@
295
296 if( file_wd_islink(zFilename) ){
297 /* Instead of file content, return sha1 of link destination path */
298 Blob destinationPath;
299 int rc;
300
301 blob_read_link(&destinationPath, zFilename);
302 rc = sha1sum_blob(&destinationPath, pCksum);
303 blob_reset(&destinationPath);
304 return rc;
305 }
@@ -363,11 +363,11 @@
363 return mprintf("%s", zDigest);
364 }
365
366 /*
367 ** Convert a cleartext password for a specific user into a SHA1 hash.
368 **
369 ** The algorithm here is:
370 **
371 ** SHA1( project-code + "/" + login + "/" + password )
372 **
373 ** In words: The users login name and password are appended to the
@@ -375,11 +375,11 @@
375 **
376 ** The result of this function is the shared secret used by a client
377 ** to authenticate to a server for the sync protocol. It is also the
378 ** value stored in the USER.PW field of the database. By mixing in the
379 ** login name and the project id with the hash, different shared secrets
380 ** are obtained even if two users select the same password, or if a
381 ** single user selects the same password for multiple projects.
382 */
383 char *sha1_shared_secret(
384 const char *zPw, /* The password to encrypt */
385 const char *zLogin, /* Username */
@@ -457,11 +457,11 @@
457 */
458 void sha1sum_test(void){
459 int i;
460 Blob in;
461 Blob cksum;
462
463 for(i=2; i<g.argc; i++){
464 blob_init(&cksum, "************** not found ***************", -1);
465 if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
466 blob_read_from_channel(&in, stdin, -1);
467 sha1sum_blob(&in, &cksum);
468
+300 -139
--- src/shell.c
+++ src/shell.c
@@ -15,10 +15,17 @@
1515
#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
1616
/* This needs to come before any includes for MSVC compiler */
1717
#define _CRT_SECURE_NO_WARNINGS
1818
#endif
1919
20
+/*
21
+** If requested, include the SQLite compiler options file for MSVC.
22
+*/
23
+#if defined(INCLUDE_MSVC_H)
24
+#include "msvc.h"
25
+#endif
26
+
2027
/*
2128
** Enable large-file support for fopen() and friends on unix.
2229
*/
2330
#ifndef SQLITE_DISABLE_LFS
2431
# define _LARGE_FILE 1
@@ -46,21 +53,20 @@
4653
# endif
4754
# include <unistd.h>
4855
# include <sys/types.h>
4956
#endif
5057
51
-#if defined(HAVE_READLINE) && HAVE_READLINE!=0
58
+#if HAVE_READLINE
5259
# include <readline/readline.h>
5360
# include <readline/history.h>
54
-#else
55
-# undef HAVE_READLINE
5661
#endif
57
-#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
62
+#if HAVE_EDITLINE
63
+# undef HAVE_READLINE
5864
# define HAVE_READLINE 1
5965
# include <editline/readline.h>
6066
#endif
61
-#if !defined(HAVE_READLINE)
67
+#if !HAVE_READLINE
6268
# define add_history(X)
6369
# define read_history(X)
6470
# define write_history(X)
6571
# define stifle_history(X)
6672
#endif
@@ -97,10 +103,30 @@
97103
98104
/* ctype macros that work with signed characters */
99105
#define IsSpace(X) isspace((unsigned char)X)
100106
#define IsDigit(X) isdigit((unsigned char)X)
101107
#define ToLower(X) (char)tolower((unsigned char)X)
108
+
109
+/* On Windows, we normally run with output mode of TEXT so that \n characters
110
+** are automatically translated into \r\n. However, this behavior needs
111
+** to be disabled in some cases (ex: when generating CSV output and when
112
+** rendering quoted strings that contain \n characters). The following
113
+** routines take care of that.
114
+*/
115
+#if defined(_WIN32) || defined(WIN32)
116
+static void setBinaryMode(FILE *out){
117
+ fflush(out);
118
+ _setmode(_fileno(out), _O_BINARY);
119
+}
120
+static void setTextMode(FILE *out){
121
+ fflush(out);
122
+ _setmode(_fileno(out), _O_TEXT);
123
+}
124
+#else
125
+# define setBinaryMode(X)
126
+# define setTextMode(X)
127
+#endif
102128
103129
104130
/* True if the timer is enabled */
105131
static int enableTimer = 0;
106132
@@ -423,11 +449,11 @@
423449
char *zResult;
424450
if( in!=0 ){
425451
zResult = local_getline(zPrior, in);
426452
}else{
427453
zPrompt = isContinuation ? continuePrompt : mainPrompt;
428
-#if defined(HAVE_READLINE)
454
+#if HAVE_READLINE
429455
free(zPrior);
430456
zResult = readline(zPrompt);
431457
if( zResult && *zResult ) add_history(zResult);
432458
#else
433459
printf("%s", zPrompt);
@@ -469,15 +495,15 @@
469495
int mode; /* An output mode setting */
470496
int writableSchema; /* True if PRAGMA writable_schema=ON */
471497
int showHeader; /* True to show column names in List or Column mode */
472498
unsigned shellFlgs; /* Various flags */
473499
char *zDestTable; /* Name of destination table when MODE_Insert */
474
- char separator[20]; /* Separator character for MODE_List */
475
- char newline[20]; /* Record separator in MODE_Csv */
500
+ char colSeparator[20]; /* Column separator character for several modes */
501
+ char rowSeparator[20]; /* Row separator character for MODE_Ascii */
476502
int colWidth[100]; /* Requested width of each column when in column mode*/
477503
int actualWidth[100]; /* Actual width of each column */
478
- char nullvalue[20]; /* The text to print when a NULL comes back from
504
+ char nullValue[20]; /* The text to print when a NULL comes back from
479505
** the database */
480506
SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
481507
char outfile[FILENAME_MAX]; /* Filename for *out */
482508
const char *zDbFilename; /* name of the database file */
483509
char *zFreeOnClose; /* Filename to free when closing */
@@ -506,10 +532,11 @@
506532
#define MODE_Html 4 /* Generate an XHTML table */
507533
#define MODE_Insert 5 /* Generate SQL "insert" statements */
508534
#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
509535
#define MODE_Csv 7 /* Quote strings, numbers are plain */
510536
#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
537
+#define MODE_Ascii 9 /* Use ASCII unit and record separators (0x1F/0x1E) */
511538
512539
static const char *modeDescr[] = {
513540
"line",
514541
"column",
515542
"list",
@@ -517,12 +544,26 @@
517544
"html",
518545
"insert",
519546
"tcl",
520547
"csv",
521548
"explain",
549
+ "ascii",
522550
};
523551
552
+/*
553
+** These are the column/row/line separators used by the various
554
+** import/export modes.
555
+*/
556
+#define SEP_Column "|"
557
+#define SEP_Row "\n"
558
+#define SEP_Tab "\t"
559
+#define SEP_Space " "
560
+#define SEP_Comma ","
561
+#define SEP_CrLf "\r\n"
562
+#define SEP_Unit "\x1F"
563
+#define SEP_Record "\x1E"
564
+
524565
/*
525566
** Number of elements in an array
526567
*/
527568
#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
528569
@@ -561,10 +602,11 @@
561602
** Output the given string as a quoted string using SQL quoting conventions.
562603
*/
563604
static void output_quoted_string(FILE *out, const char *z){
564605
int i;
565606
int nSingle = 0;
607
+ setBinaryMode(out);
566608
for(i=0; z[i]; i++){
567609
if( z[i]=='\'' ) nSingle++;
568610
}
569611
if( nSingle==0 ){
570612
fprintf(out,"'%s'",z);
@@ -583,10 +625,11 @@
583625
break;
584626
}
585627
}
586628
fprintf(out,"'");
587629
}
630
+ setTextMode(out);
588631
}
589632
590633
/*
591634
** Output the given string as a quoted according to C or TCL quoting rules.
592635
*/
@@ -675,26 +718,26 @@
675718
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
676719
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
677720
};
678721
679722
/*
680
-** Output a single term of CSV. Actually, p->separator is used for
681
-** the separator, which may or may not be a comma. p->nullvalue is
723
+** Output a single term of CSV. Actually, p->colSeparator is used for
724
+** the separator, which may or may not be a comma. p->nullValue is
682725
** the null value. Strings are quoted if necessary. The separator
683726
** is only issued if bSep is true.
684727
*/
685728
static void output_csv(ShellState *p, const char *z, int bSep){
686729
FILE *out = p->out;
687730
if( z==0 ){
688
- fprintf(out,"%s",p->nullvalue);
731
+ fprintf(out,"%s",p->nullValue);
689732
}else{
690733
int i;
691
- int nSep = strlen30(p->separator);
734
+ int nSep = strlen30(p->colSeparator);
692735
for(i=0; z[i]; i++){
693736
if( needCsvQuote[((unsigned char*)z)[i]]
694
- || (z[i]==p->separator[0] &&
695
- (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
737
+ || (z[i]==p->colSeparator[0] &&
738
+ (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
696739
i = 0;
697740
break;
698741
}
699742
}
700743
if( i==0 ){
@@ -707,11 +750,11 @@
707750
}else{
708751
fprintf(out, "%s", z);
709752
}
710753
}
711754
if( bSep ){
712
- fprintf(p->out, "%s", p->separator);
755
+ fprintf(p->out, "%s", p->colSeparator);
713756
}
714757
}
715758
716759
#ifdef SIGINT
717760
/*
@@ -745,14 +788,14 @@
745788
if( azArg==0 ) break;
746789
for(i=0; i<nArg; i++){
747790
int len = strlen30(azCol[i] ? azCol[i] : "");
748791
if( len>w ) w = len;
749792
}
750
- if( p->cnt++>0 ) fprintf(p->out,"\n");
793
+ if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
751794
for(i=0; i<nArg; i++){
752
- fprintf(p->out,"%*s = %s\n", w, azCol[i],
753
- azArg[i] ? azArg[i] : p->nullvalue);
795
+ fprintf(p->out,"%*s = %s%s", w, azCol[i],
796
+ azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
754797
}
755798
break;
756799
}
757800
case MODE_Explain:
758801
case MODE_Column: {
@@ -765,21 +808,23 @@
765808
w = 0;
766809
}
767810
if( w==0 ){
768811
w = strlen30(azCol[i] ? azCol[i] : "");
769812
if( w<10 ) w = 10;
770
- n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
813
+ n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
771814
if( w<n ) w = n;
772815
}
773816
if( i<ArraySize(p->actualWidth) ){
774817
p->actualWidth[i] = w;
775818
}
776819
if( p->showHeader ){
777820
if( w<0 ){
778
- fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": " ");
821
+ fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
822
+ i==nArg-1 ? p->rowSeparator : " ");
779823
}else{
780
- fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
824
+ fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
825
+ i==nArg-1 ? p->rowSeparator : " ");
781826
}
782827
}
783828
}
784829
if( p->showHeader ){
785830
for(i=0; i<nArg; i++){
@@ -790,11 +835,11 @@
790835
}else{
791836
w = 10;
792837
}
793838
fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
794839
"----------------------------------------------------------",
795
- i==nArg-1 ? "\n": " ");
840
+ i==nArg-1 ? p->rowSeparator : " ");
796841
}
797842
}
798843
}
799844
if( azArg==0 ) break;
800845
for(i=0; i<nArg; i++){
@@ -813,36 +858,39 @@
813858
}
814859
p->iIndent++;
815860
}
816861
if( w<0 ){
817862
fprintf(p->out,"%*.*s%s",-w,-w,
818
- azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
863
+ azArg[i] ? azArg[i] : p->nullValue,
864
+ i==nArg-1 ? p->rowSeparator : " ");
819865
}else{
820866
fprintf(p->out,"%-*.*s%s",w,w,
821
- azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
867
+ azArg[i] ? azArg[i] : p->nullValue,
868
+ i==nArg-1 ? p->rowSeparator : " ");
822869
}
823870
}
824871
break;
825872
}
826873
case MODE_Semi:
827874
case MODE_List: {
828875
if( p->cnt++==0 && p->showHeader ){
829876
for(i=0; i<nArg; i++){
830
- fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
877
+ fprintf(p->out,"%s%s",azCol[i],
878
+ i==nArg-1 ? p->rowSeparator : p->colSeparator);
831879
}
832880
}
833881
if( azArg==0 ) break;
834882
for(i=0; i<nArg; i++){
835883
char *z = azArg[i];
836
- if( z==0 ) z = p->nullvalue;
884
+ if( z==0 ) z = p->nullValue;
837885
fprintf(p->out, "%s", z);
838886
if( i<nArg-1 ){
839
- fprintf(p->out, "%s", p->separator);
887
+ fprintf(p->out, "%s", p->colSeparator);
840888
}else if( p->mode==MODE_Semi ){
841
- fprintf(p->out, ";\n");
889
+ fprintf(p->out, ";%s", p->rowSeparator);
842890
}else{
843
- fprintf(p->out, "\n");
891
+ fprintf(p->out, "%s", p->rowSeparator);
844892
}
845893
}
846894
break;
847895
}
848896
case MODE_Html: {
@@ -857,53 +905,47 @@
857905
}
858906
if( azArg==0 ) break;
859907
fprintf(p->out,"<TR>");
860908
for(i=0; i<nArg; i++){
861909
fprintf(p->out,"<TD>");
862
- output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
910
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
863911
fprintf(p->out,"</TD>\n");
864912
}
865913
fprintf(p->out,"</TR>\n");
866914
break;
867915
}
868916
case MODE_Tcl: {
869917
if( p->cnt++==0 && p->showHeader ){
870918
for(i=0; i<nArg; i++){
871919
output_c_string(p->out,azCol[i] ? azCol[i] : "");
872
- if(i<nArg-1) fprintf(p->out, "%s", p->separator);
920
+ if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
873921
}
874
- fprintf(p->out,"\n");
922
+ fprintf(p->out, "%s", p->rowSeparator);
875923
}
876924
if( azArg==0 ) break;
877925
for(i=0; i<nArg; i++){
878
- output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
879
- if(i<nArg-1) fprintf(p->out, "%s", p->separator);
926
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
927
+ if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
880928
}
881
- fprintf(p->out,"\n");
929
+ fprintf(p->out, "%s", p->rowSeparator);
882930
break;
883931
}
884932
case MODE_Csv: {
885
-#if defined(WIN32) || defined(_WIN32)
886
- fflush(p->out);
887
- _setmode(_fileno(p->out), _O_BINARY);
888
-#endif
933
+ setBinaryMode(p->out);
889934
if( p->cnt++==0 && p->showHeader ){
890935
for(i=0; i<nArg; i++){
891936
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
892937
}
893
- fprintf(p->out,"%s",p->newline);
938
+ fprintf(p->out, "%s", p->rowSeparator);
894939
}
895940
if( nArg>0 ){
896941
for(i=0; i<nArg; i++){
897942
output_csv(p, azArg[i], i<nArg-1);
898943
}
899
- fprintf(p->out,"%s",p->newline);
944
+ fprintf(p->out, "%s", p->rowSeparator);
900945
}
901
-#if defined(WIN32) || defined(_WIN32)
902
- fflush(p->out);
903
- _setmode(_fileno(p->out), _O_TEXT);
904
-#endif
946
+ setTextMode(p->out);
905947
break;
906948
}
907949
case MODE_Insert: {
908950
p->cnt++;
909951
if( azArg==0 ) break;
@@ -930,10 +972,26 @@
930972
output_quoted_string(p->out, azArg[i]);
931973
}
932974
}
933975
fprintf(p->out,");\n");
934976
break;
977
+ }
978
+ case MODE_Ascii: {
979
+ if( p->cnt++==0 && p->showHeader ){
980
+ for(i=0; i<nArg; i++){
981
+ if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
982
+ fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
983
+ }
984
+ fprintf(p->out, "%s", p->rowSeparator);
985
+ }
986
+ if( azArg==0 ) break;
987
+ for(i=0; i<nArg; i++){
988
+ if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
989
+ fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
990
+ }
991
+ fprintf(p->out, "%s", p->rowSeparator);
992
+ break;
935993
}
936994
}
937995
return 0;
938996
}
939997
@@ -1428,10 +1486,21 @@
14281486
}
14291487
}
14301488
sqlite3_finalize(pExplain);
14311489
sqlite3_free(zEQP);
14321490
}
1491
+
1492
+#if USE_SYSTEM_SQLITE+0==1
1493
+ /* Output TESTCTRL_EXPLAIN text of requested */
1494
+ if( pArg && pArg->mode==MODE_Explain && sqlite3_libversion_number()<3008007 ){
1495
+ const char *zExplain = 0;
1496
+ sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
1497
+ if( zExplain && zExplain[0] ){
1498
+ fprintf(pArg->out, "%s", zExplain);
1499
+ }
1500
+ }
1501
+#endif
14331502
14341503
/* If the shell is currently in ".explain" mode, gather the extra
14351504
** data required to add indents to the output.*/
14361505
if( pArg && pArg->mode==MODE_Explain ){
14371506
explain_data_prepare(pArg, pStmt);
@@ -1696,16 +1765,17 @@
16961765
#ifndef SQLITE_OMIT_LOAD_EXTENSION
16971766
".load FILE ?ENTRY? Load an extension library\n"
16981767
#endif
16991768
".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
17001769
".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
1770
+ " ascii Columns/rows delimited by 0x1F and 0x1E\n"
17011771
" csv Comma-separated values\n"
17021772
" column Left-aligned columns. (See .width)\n"
17031773
" html HTML <table> code\n"
17041774
" insert SQL insert statements for TABLE\n"
17051775
" line One value per line\n"
1706
- " list Values delimited by .separator string\n"
1776
+ " list Values delimited by .separator strings\n"
17071777
" tabs Tab-separated values\n"
17081778
" tcl TCL list elements\n"
17091779
".nullvalue STRING Use STRING in place of NULL values\n"
17101780
".once FILENAME Output for the next SQL command only to FILENAME\n"
17111781
".open ?FILENAME? Close existing database and reopen FILENAME\n"
@@ -1718,12 +1788,12 @@
17181788
".save FILE Write in-memory database into FILE\n"
17191789
".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
17201790
".schema ?TABLE? Show the CREATE statements\n"
17211791
" If TABLE specified, only show tables matching\n"
17221792
" LIKE pattern TABLE.\n"
1723
- ".separator STRING ?NL? Change separator used by output mode and .import\n"
1724
- " NL is the end-of-line mark for CSV\n"
1793
+ ".separator COL ?ROW? Change the column separator and optionally the row\n"
1794
+ " separator for both the output mode and .import\n"
17251795
".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
17261796
".show Show the current values for various settings\n"
17271797
".stats on|off Turn stats on or off\n"
17281798
".system CMD ARGS... Run CMD ARGS... in a system shell\n"
17291799
".tables ?TABLE? List names of tables\n"
@@ -2000,26 +2070,27 @@
20002070
static int nCall = 0;
20012071
nCall++;
20022072
}
20032073
20042074
/*
2005
-** An object used to read a CSV file
2075
+** An object used to read a CSV and other files for import.
20062076
*/
2007
-typedef struct CSVReader CSVReader;
2008
-struct CSVReader {
2077
+typedef struct ImportCtx ImportCtx;
2078
+struct ImportCtx {
20092079
const char *zFile; /* Name of the input file */
20102080
FILE *in; /* Read the CSV text from this input stream */
20112081
char *z; /* Accumulated text for a field */
20122082
int n; /* Number of bytes in z */
20132083
int nAlloc; /* Space allocated for z[] */
20142084
int nLine; /* Current line number */
20152085
int cTerm; /* Character that terminated the most recent field */
2016
- int cSeparator; /* The separator character. (Usually ",") */
2086
+ int cColSep; /* The column separator character. (Usually ",") */
2087
+ int cRowSep; /* The row separator character. (Usually "\n") */
20172088
};
20182089
20192090
/* Append a single byte to z[] */
2020
-static void csv_append_char(CSVReader *p, int c){
2091
+static void import_append_char(ImportCtx *p, int c){
20212092
if( p->n+1>=p->nAlloc ){
20222093
p->nAlloc += p->nAlloc + 100;
20232094
p->z = sqlite3_realloc(p->z, p->nAlloc);
20242095
if( p->z==0 ){
20252096
fprintf(stderr, "out of memory\n");
@@ -2033,41 +2104,44 @@
20332104
** with the option of having a separator other than ",".
20342105
**
20352106
** + Input comes from p->in.
20362107
** + Store results in p->z of length p->n. Space to hold p->z comes
20372108
** from sqlite3_malloc().
2038
-** + Use p->cSep as the separator. The default is ",".
2109
+** + Use p->cSep as the column separator. The default is ",".
2110
+** + Use p->rSep as the row separator. The default is "\n".
20392111
** + Keep track of the line number in p->nLine.
20402112
** + Store the character that terminates the field in p->cTerm. Store
20412113
** EOF on end-of-file.
20422114
** + Report syntax errors on stderr
20432115
*/
2044
-static char *csv_read_one_field(CSVReader *p){
2045
- int c, pc, ppc;
2046
- int cSep = p->cSeparator;
2116
+static char *csv_read_one_field(ImportCtx *p){
2117
+ int c;
2118
+ int cSep = p->cColSep;
2119
+ int rSep = p->cRowSep;
20472120
p->n = 0;
20482121
c = fgetc(p->in);
20492122
if( c==EOF || seenInterrupt ){
20502123
p->cTerm = EOF;
20512124
return 0;
20522125
}
20532126
if( c=='"' ){
2127
+ int pc, ppc;
20542128
int startLine = p->nLine;
20552129
int cQuote = c;
20562130
pc = ppc = 0;
20572131
while( 1 ){
20582132
c = fgetc(p->in);
2059
- if( c=='\n' ) p->nLine++;
2133
+ if( c==rSep ) p->nLine++;
20602134
if( c==cQuote ){
20612135
if( pc==cQuote ){
20622136
pc = 0;
20632137
continue;
20642138
}
20652139
}
20662140
if( (c==cSep && pc==cQuote)
2067
- || (c=='\n' && pc==cQuote)
2068
- || (c=='\n' && pc=='\r' && ppc==cQuote)
2141
+ || (c==rSep && pc==cQuote)
2142
+ || (c==rSep && pc=='\r' && ppc==cQuote)
20692143
|| (c==EOF && pc==cQuote)
20702144
){
20712145
do{ p->n--; }while( p->z[p->n]!=cQuote );
20722146
p->cTerm = c;
20732147
break;
@@ -2077,31 +2151,65 @@
20772151
p->zFile, p->nLine, cQuote);
20782152
}
20792153
if( c==EOF ){
20802154
fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
20812155
p->zFile, startLine, cQuote);
2082
- p->cTerm = EOF;
2156
+ p->cTerm = c;
20832157
break;
20842158
}
2085
- csv_append_char(p, c);
2159
+ import_append_char(p, c);
20862160
ppc = pc;
20872161
pc = c;
20882162
}
20892163
}else{
2090
- while( c!=EOF && c!=cSep && c!='\n' ){
2091
- csv_append_char(p, c);
2164
+ while( c!=EOF && c!=cSep && c!=rSep ){
2165
+ import_append_char(p, c);
20922166
c = fgetc(p->in);
20932167
}
2094
- if( c=='\n' ){
2168
+ if( c==rSep ){
20952169
p->nLine++;
20962170
if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
20972171
}
20982172
p->cTerm = c;
20992173
}
21002174
if( p->z ) p->z[p->n] = 0;
21012175
return p->z;
21022176
}
2177
+
2178
+/* Read a single field of ASCII delimited text.
2179
+**
2180
+** + Input comes from p->in.
2181
+** + Store results in p->z of length p->n. Space to hold p->z comes
2182
+** from sqlite3_malloc().
2183
+** + Use p->cSep as the column separator. The default is "\x1F".
2184
+** + Use p->rSep as the row separator. The default is "\x1E".
2185
+** + Keep track of the row number in p->nLine.
2186
+** + Store the character that terminates the field in p->cTerm. Store
2187
+** EOF on end-of-file.
2188
+** + Report syntax errors on stderr
2189
+*/
2190
+static char *ascii_read_one_field(ImportCtx *p){
2191
+ int c;
2192
+ int cSep = p->cColSep;
2193
+ int rSep = p->cRowSep;
2194
+ p->n = 0;
2195
+ c = fgetc(p->in);
2196
+ if( c==EOF || seenInterrupt ){
2197
+ p->cTerm = EOF;
2198
+ return 0;
2199
+ }
2200
+ while( c!=EOF && c!=cSep && c!=rSep ){
2201
+ import_append_char(p, c);
2202
+ c = fgetc(p->in);
2203
+ }
2204
+ if( c==rSep ){
2205
+ p->nLine++;
2206
+ }
2207
+ p->cTerm = c;
2208
+ if( p->z ) p->z[p->n] = 0;
2209
+ return p->z;
2210
+}
21032211
21042212
/*
21052213
** Try to transfer data for table zTable. If an error is seen while
21062214
** moving forward, try to go backwards. The backwards movement won't
21072215
** work for WITHOUT ROWID tables.
@@ -2653,100 +2761,125 @@
26532761
sqlite3_stmt *pStmt = NULL; /* A statement */
26542762
int nCol; /* Number of columns in the table */
26552763
int nByte; /* Number of bytes in an SQL string */
26562764
int i, j; /* Loop counters */
26572765
int needCommit; /* True to COMMIT or ROLLBACK at end */
2658
- int nSep; /* Number of bytes in p->separator[] */
2766
+ int nSep; /* Number of bytes in p->colSeparator[] */
26592767
char *zSql; /* An SQL statement */
2660
- CSVReader sCsv; /* Reader context */
2768
+ ImportCtx sCtx; /* Reader context */
2769
+ char *(*xRead)(ImportCtx*); /* Procedure to read one value */
26612770
int (*xCloser)(FILE*); /* Procedure to close th3 connection */
26622771
26632772
if( nArg!=3 ){
26642773
fprintf(stderr, "Usage: .import FILE TABLE\n");
26652774
goto meta_command_exit;
26662775
}
26672776
zFile = azArg[1];
26682777
zTable = azArg[2];
26692778
seenInterrupt = 0;
2670
- memset(&sCsv, 0, sizeof(sCsv));
2779
+ memset(&sCtx, 0, sizeof(sCtx));
26712780
open_db(p, 0);
2672
- nSep = strlen30(p->separator);
2781
+ nSep = strlen30(p->colSeparator);
2782
+ if( nSep==0 ){
2783
+ fprintf(stderr, "Error: non-null column separator required for import\n");
2784
+ return 1;
2785
+ }
2786
+ if( nSep>1 ){
2787
+ fprintf(stderr, "Error: multi-character column separators not allowed"
2788
+ " for import\n");
2789
+ return 1;
2790
+ }
2791
+ nSep = strlen30(p->rowSeparator);
26732792
if( nSep==0 ){
2674
- fprintf(stderr, "Error: non-null separator required for import\n");
2793
+ fprintf(stderr, "Error: non-null row separator required for import\n");
26752794
return 1;
2795
+ }
2796
+ if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
2797
+ /* When importing CSV (only), if the row separator is set to the
2798
+ ** default output row separator, change it to the default input
2799
+ ** row separator. This avoids having to maintain different input
2800
+ ** and output row separators. */
2801
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
2802
+ nSep = strlen30(p->rowSeparator);
26762803
}
26772804
if( nSep>1 ){
2678
- fprintf(stderr, "Error: multi-character separators not allowed"
2805
+ fprintf(stderr, "Error: multi-character row separators not allowed"
26792806
" for import\n");
26802807
return 1;
26812808
}
2682
- sCsv.zFile = zFile;
2683
- sCsv.nLine = 1;
2684
- if( sCsv.zFile[0]=='|' ){
2685
- sCsv.in = popen(sCsv.zFile+1, "r");
2686
- sCsv.zFile = "<pipe>";
2809
+ sCtx.zFile = zFile;
2810
+ sCtx.nLine = 1;
2811
+ if( sCtx.zFile[0]=='|' ){
2812
+ sCtx.in = popen(sCtx.zFile+1, "r");
2813
+ sCtx.zFile = "<pipe>";
26872814
xCloser = pclose;
26882815
}else{
2689
- sCsv.in = fopen(sCsv.zFile, "rb");
2816
+ sCtx.in = fopen(sCtx.zFile, "rb");
26902817
xCloser = fclose;
26912818
}
2692
- if( sCsv.in==0 ){
2819
+ if( p->mode==MODE_Ascii ){
2820
+ xRead = ascii_read_one_field;
2821
+ }else{
2822
+ xRead = csv_read_one_field;
2823
+ }
2824
+ if( sCtx.in==0 ){
26932825
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
26942826
return 1;
26952827
}
2696
- sCsv.cSeparator = p->separator[0];
2828
+ sCtx.cColSep = p->colSeparator[0];
2829
+ sCtx.cRowSep = p->rowSeparator[0];
26972830
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
26982831
if( zSql==0 ){
26992832
fprintf(stderr, "Error: out of memory\n");
2700
- xCloser(sCsv.in);
2833
+ xCloser(sCtx.in);
27012834
return 1;
27022835
}
27032836
nByte = strlen30(zSql);
27042837
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2705
- csv_append_char(&sCsv, 0); /* To ensure sCsv.z is allocated */
2838
+ import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
27062839
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
27072840
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
27082841
char cSep = '(';
2709
- while( csv_read_one_field(&sCsv) ){
2710
- zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z);
2842
+ while( xRead(&sCtx) ){
2843
+ zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z);
27112844
cSep = ',';
2712
- if( sCsv.cTerm!=sCsv.cSeparator ) break;
2845
+ if( sCtx.cTerm!=sCtx.cColSep ) break;
27132846
}
27142847
if( cSep=='(' ){
27152848
sqlite3_free(zCreate);
2716
- sqlite3_free(sCsv.z);
2717
- xCloser(sCsv.in);
2718
- fprintf(stderr,"%s: empty file\n", sCsv.zFile);
2849
+ sqlite3_free(sCtx.z);
2850
+ xCloser(sCtx.in);
2851
+ fprintf(stderr,"%s: empty file\n", sCtx.zFile);
27192852
return 1;
27202853
}
27212854
zCreate = sqlite3_mprintf("%z\n)", zCreate);
27222855
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
27232856
sqlite3_free(zCreate);
27242857
if( rc ){
27252858
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
27262859
sqlite3_errmsg(db));
2727
- sqlite3_free(sCsv.z);
2728
- xCloser(sCsv.in);
2860
+ sqlite3_free(sCtx.z);
2861
+ xCloser(sCtx.in);
27292862
return 1;
27302863
}
27312864
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27322865
}
27332866
sqlite3_free(zSql);
27342867
if( rc ){
27352868
if (pStmt) sqlite3_finalize(pStmt);
27362869
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
2737
- xCloser(sCsv.in);
2870
+ xCloser(sCtx.in);
27382871
return 1;
27392872
}
27402873
nCol = sqlite3_column_count(pStmt);
27412874
sqlite3_finalize(pStmt);
27422875
pStmt = 0;
27432876
if( nCol==0 ) return 0; /* no columns, no error */
27442877
zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
27452878
if( zSql==0 ){
27462879
fprintf(stderr, "Error: out of memory\n");
2747
- xCloser(sCsv.in);
2880
+ xCloser(sCtx.in);
27482881
return 1;
27492882
}
27502883
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
27512884
j = strlen30(zSql);
27522885
for(i=1; i<nCol; i++){
@@ -2758,50 +2891,60 @@
27582891
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27592892
sqlite3_free(zSql);
27602893
if( rc ){
27612894
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
27622895
if (pStmt) sqlite3_finalize(pStmt);
2763
- xCloser(sCsv.in);
2896
+ xCloser(sCtx.in);
27642897
return 1;
27652898
}
27662899
needCommit = sqlite3_get_autocommit(db);
27672900
if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
27682901
do{
2769
- int startLine = sCsv.nLine;
2902
+ int startLine = sCtx.nLine;
27702903
for(i=0; i<nCol; i++){
2771
- char *z = csv_read_one_field(&sCsv);
2904
+ char *z = xRead(&sCtx);
2905
+ /*
2906
+ ** Did we reach end-of-file before finding any columns?
2907
+ ** If so, stop instead of NULL filling the remaining columns.
2908
+ */
27722909
if( z==0 && i==0 ) break;
2910
+ /*
2911
+ ** Did we reach end-of-file OR end-of-line before finding any
2912
+ ** columns in ASCII mode? If so, stop instead of NULL filling
2913
+ ** the remaining columns.
2914
+ */
2915
+ if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
27732916
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
2774
- if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
2917
+ if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
27752918
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
27762919
"filling the rest with NULL\n",
2777
- sCsv.zFile, startLine, nCol, i+1);
2920
+ sCtx.zFile, startLine, nCol, i+1);
27782921
i++;
27792922
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
27802923
}
27812924
}
2782
- if( sCsv.cTerm==sCsv.cSeparator ){
2925
+ if( sCtx.cTerm==sCtx.cColSep ){
27832926
do{
2784
- csv_read_one_field(&sCsv);
2927
+ xRead(&sCtx);
27852928
i++;
2786
- }while( sCsv.cTerm==sCsv.cSeparator );
2929
+ }while( sCtx.cTerm==sCtx.cColSep );
27872930
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
27882931
"extras ignored\n",
2789
- sCsv.zFile, startLine, nCol, i);
2932
+ sCtx.zFile, startLine, nCol, i);
27902933
}
27912934
if( i>=nCol ){
27922935
sqlite3_step(pStmt);
27932936
rc = sqlite3_reset(pStmt);
27942937
if( rc!=SQLITE_OK ){
2795
- fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine,
2938
+ fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
27962939
sqlite3_errmsg(db));
27972940
}
27982941
}
2799
- }while( sCsv.cTerm!=EOF );
2942
+ }while( sCtx.cTerm!=EOF );
28002943
2801
- xCloser(sCsv.in);
2802
- sqlite3_free(sCsv.z);
2944
+ xCloser(sCtx.in);
2945
+ sqlite3_free(sCtx.z);
28032946
sqlite3_finalize(pStmt);
28042947
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
28052948
}else
28062949
28072950
if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
@@ -2915,32 +3058,36 @@
29153058
p->mode = MODE_List;
29163059
}else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
29173060
p->mode = MODE_Html;
29183061
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
29193062
p->mode = MODE_Tcl;
2920
- sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
3063
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
29213064
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
29223065
p->mode = MODE_Csv;
2923
- sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
2924
- sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");
3066
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
3067
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
29253068
}else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
29263069
p->mode = MODE_List;
2927
- sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
3070
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
29283071
}else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
29293072
p->mode = MODE_Insert;
29303073
set_table_name(p, nArg>=3 ? azArg[2] : "table");
3074
+ }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
3075
+ p->mode = MODE_Ascii;
3076
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
3077
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
29313078
}else {
29323079
fprintf(stderr,"Error: mode should be one of: "
2933
- "column csv html insert line list tabs tcl\n");
3080
+ "ascii column csv html insert line list tabs tcl\n");
29343081
rc = 1;
29353082
}
29363083
}else
29373084
29383085
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
29393086
if( nArg==2 ){
2940
- sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
2941
- "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
3087
+ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
3088
+ "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
29423089
}else{
29433090
fprintf(stderr, "Usage: .nullvalue STRING\n");
29443091
rc = 1;
29453092
}
29463093
}else
@@ -3191,11 +3338,11 @@
31913338
31923339
31933340
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
31943341
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
31953342
extern int sqlite3SelectTrace;
3196
- sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
3343
+ sqlite3SelectTrace = integerValue(azArg[1]);
31973344
}else
31983345
#endif
31993346
32003347
32013348
#ifdef SQLITE_DEBUG
@@ -3221,18 +3368,20 @@
32213368
}else
32223369
#endif
32233370
32243371
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
32253372
if( nArg<2 || nArg>3 ){
3226
- fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
3373
+ fprintf(stderr, "Usage: .separator COL ?ROW?\n");
32273374
rc = 1;
32283375
}
32293376
if( nArg>=2 ){
3230
- sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);
3377
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
3378
+ "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
32313379
}
32323380
if( nArg>=3 ){
3233
- sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);
3381
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
3382
+ "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
32343383
}
32353384
}else
32363385
32373386
if( c=='s'
32383387
&& (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
@@ -3259,27 +3408,28 @@
32593408
if( nArg!=1 ){
32603409
fprintf(stderr, "Usage: .show\n");
32613410
rc = 1;
32623411
goto meta_command_exit;
32633412
}
3264
- fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
3265
- fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
3413
+ fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
3414
+ fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
32663415
fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
3267
- fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
3268
- fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
3269
- fprintf(p->out,"%9.9s: ", "nullvalue");
3270
- output_c_string(p->out, p->nullvalue);
3416
+ fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
3417
+ fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
3418
+ fprintf(p->out,"%12.12s: ", "nullvalue");
3419
+ output_c_string(p->out, p->nullValue);
32713420
fprintf(p->out, "\n");
3272
- fprintf(p->out,"%9.9s: %s\n","output",
3421
+ fprintf(p->out,"%12.12s: %s\n","output",
32733422
strlen30(p->outfile) ? p->outfile : "stdout");
3274
- fprintf(p->out,"%9.9s: ", "separator");
3275
- output_c_string(p->out, p->separator);
3276
- fprintf(p->out," ");
3277
- output_c_string(p->out, p->newline);
3423
+ fprintf(p->out,"%12.12s: ", "colseparator");
3424
+ output_c_string(p->out, p->colSeparator);
3425
+ fprintf(p->out, "\n");
3426
+ fprintf(p->out,"%12.12s: ", "rowseparator");
3427
+ output_c_string(p->out, p->rowSeparator);
32783428
fprintf(p->out, "\n");
3279
- fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
3280
- fprintf(p->out,"%9.9s: ","width");
3429
+ fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
3430
+ fprintf(p->out,"%12.12s: ","width");
32813431
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
32823432
fprintf(p->out,"%d ",p->colWidth[i]);
32833433
}
32843434
fprintf(p->out,"\n");
32853435
}else
@@ -3394,10 +3544,11 @@
33943544
{ "reserve", SQLITE_TESTCTRL_RESERVE },
33953545
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
33963546
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
33973547
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
33983548
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
3549
+ { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
33993550
};
34003551
int testctrl = -1;
34013552
int rc = 0;
34023553
int i, n;
34033554
open_db(p, 0);
@@ -3460,11 +3611,12 @@
34603611
}
34613612
break;
34623613
34633614
/* sqlite3_test_control(int, int) */
34643615
case SQLITE_TESTCTRL_ASSERT:
3465
- case SQLITE_TESTCTRL_ALWAYS:
3616
+ case SQLITE_TESTCTRL_ALWAYS:
3617
+ case SQLITE_TESTCTRL_NEVER_CORRUPT:
34663618
if( nArg==3 ){
34673619
int opt = booleanValue(azArg[2]);
34683620
rc = sqlite3_test_control(testctrl, opt);
34693621
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
34703622
} else {
@@ -3936,10 +4088,11 @@
39364088
39374089
/*
39384090
** Show available command line options
39394091
*/
39404092
static const char zOptions[] =
4093
+ " -ascii set output mode to 'ascii'\n"
39414094
" -bail stop after hitting an error\n"
39424095
" -batch force batch I/O\n"
39434096
" -column set output mode to 'column'\n"
39444097
" -cmd COMMAND run \"COMMAND\" before reading stdin\n"
39454098
" -csv set output mode to 'csv'\n"
@@ -3957,15 +4110,15 @@
39574110
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
39584111
" -mmap N default mmap size set to N\n"
39594112
#ifdef SQLITE_ENABLE_MULTIPLEX
39604113
" -multiplex enable the multiplexor VFS\n"
39614114
#endif
3962
- " -newline SEP set newline character(s) for CSV\n"
4115
+ " -newline SEP set output row separator. Default: '\\n'\n"
39634116
" -nullvalue TEXT set text string for NULL values. Default ''\n"
39644117
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
39654118
" -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
3966
- " -separator SEP set output field separator. Default: '|'\n"
4119
+ " -separator SEP set output column separator. Default: '|'\n"
39674120
" -stats print memory stats before each finalize\n"
39684121
" -version show SQLite version\n"
39694122
" -vfs NAME use NAME as the default VFS\n"
39704123
#ifdef SQLITE_ENABLE_VFSTRACE
39714124
" -vfstrace enable tracing of all VFS calls\n"
@@ -3988,12 +4141,12 @@
39884141
** Initialize the state information in data
39894142
*/
39904143
static void main_init(ShellState *data) {
39914144
memset(data, 0, sizeof(*data));
39924145
data->mode = MODE_List;
3993
- memcpy(data->separator,"|", 2);
3994
- memcpy(data->newline,"\r\n", 3);
4146
+ memcpy(data->colSeparator,SEP_Column, 2);
4147
+ memcpy(data->rowSeparator,SEP_Row, 2);
39954148
data->showHeader = 0;
39964149
data->shellFlgs = SHFLG_Lookaside;
39974150
sqlite3_config(SQLITE_CONFIG_URI, 1);
39984151
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
39994152
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -4050,10 +4203,12 @@
40504203
fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
40514204
sqlite3_sourceid(), SQLITE_SOURCE_ID);
40524205
exit(1);
40534206
}
40544207
#endif
4208
+ setBinaryMode(stdin);
4209
+ setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
40554210
Argv0 = argv[0];
40564211
main_init(&data);
40574212
stdin_is_interactive = isatty(0);
40584213
40594214
/* Make sure we have a valid signal handler early, before anything
@@ -4228,19 +4383,25 @@
42284383
data.mode = MODE_Line;
42294384
}else if( strcmp(z,"-column")==0 ){
42304385
data.mode = MODE_Column;
42314386
}else if( strcmp(z,"-csv")==0 ){
42324387
data.mode = MODE_Csv;
4233
- memcpy(data.separator,",",2);
4388
+ memcpy(data.colSeparator,",",2);
4389
+ }else if( strcmp(z,"-ascii")==0 ){
4390
+ data.mode = MODE_Ascii;
4391
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
4392
+ SEP_Unit);
4393
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
4394
+ SEP_Record);
42344395
}else if( strcmp(z,"-separator")==0 ){
4235
- sqlite3_snprintf(sizeof(data.separator), data.separator,
4396
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
42364397
"%s",cmdline_option_value(argc,argv,++i));
42374398
}else if( strcmp(z,"-newline")==0 ){
4238
- sqlite3_snprintf(sizeof(data.newline), data.newline,
4399
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
42394400
"%s",cmdline_option_value(argc,argv,++i));
42404401
}else if( strcmp(z,"-nullvalue")==0 ){
4241
- sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
4402
+ sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
42424403
"%s",cmdline_option_value(argc,argv,++i));
42434404
}else if( strcmp(z,"-header")==0 ){
42444405
data.showHeader = 1;
42454406
}else if( strcmp(z,"-noheader")==0 ){
42464407
data.showHeader = 0;
@@ -4356,11 +4517,11 @@
43564517
nHistory = strlen30(zHome) + 20;
43574518
if( (zHistory = malloc(nHistory))!=0 ){
43584519
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
43594520
}
43604521
}
4361
-#if defined(HAVE_READLINE)
4522
+#if HAVE_READLINE
43624523
if( zHistory ) read_history(zHistory);
43634524
#endif
43644525
rc = process_input(&data, 0);
43654526
if( zHistory ){
43664527
stifle_history(100);
43674528
--- src/shell.c
+++ src/shell.c
@@ -15,10 +15,17 @@
15 #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
16 /* This needs to come before any includes for MSVC compiler */
17 #define _CRT_SECURE_NO_WARNINGS
18 #endif
19
 
 
 
 
 
 
 
20 /*
21 ** Enable large-file support for fopen() and friends on unix.
22 */
23 #ifndef SQLITE_DISABLE_LFS
24 # define _LARGE_FILE 1
@@ -46,21 +53,20 @@
46 # endif
47 # include <unistd.h>
48 # include <sys/types.h>
49 #endif
50
51 #if defined(HAVE_READLINE) && HAVE_READLINE!=0
52 # include <readline/readline.h>
53 # include <readline/history.h>
54 #else
55 # undef HAVE_READLINE
56 #endif
57 #if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
 
58 # define HAVE_READLINE 1
59 # include <editline/readline.h>
60 #endif
61 #if !defined(HAVE_READLINE)
62 # define add_history(X)
63 # define read_history(X)
64 # define write_history(X)
65 # define stifle_history(X)
66 #endif
@@ -97,10 +103,30 @@
97
98 /* ctype macros that work with signed characters */
99 #define IsSpace(X) isspace((unsigned char)X)
100 #define IsDigit(X) isdigit((unsigned char)X)
101 #define ToLower(X) (char)tolower((unsigned char)X)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
103
104 /* True if the timer is enabled */
105 static int enableTimer = 0;
106
@@ -423,11 +449,11 @@
423 char *zResult;
424 if( in!=0 ){
425 zResult = local_getline(zPrior, in);
426 }else{
427 zPrompt = isContinuation ? continuePrompt : mainPrompt;
428 #if defined(HAVE_READLINE)
429 free(zPrior);
430 zResult = readline(zPrompt);
431 if( zResult && *zResult ) add_history(zResult);
432 #else
433 printf("%s", zPrompt);
@@ -469,15 +495,15 @@
469 int mode; /* An output mode setting */
470 int writableSchema; /* True if PRAGMA writable_schema=ON */
471 int showHeader; /* True to show column names in List or Column mode */
472 unsigned shellFlgs; /* Various flags */
473 char *zDestTable; /* Name of destination table when MODE_Insert */
474 char separator[20]; /* Separator character for MODE_List */
475 char newline[20]; /* Record separator in MODE_Csv */
476 int colWidth[100]; /* Requested width of each column when in column mode*/
477 int actualWidth[100]; /* Actual width of each column */
478 char nullvalue[20]; /* The text to print when a NULL comes back from
479 ** the database */
480 SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
481 char outfile[FILENAME_MAX]; /* Filename for *out */
482 const char *zDbFilename; /* name of the database file */
483 char *zFreeOnClose; /* Filename to free when closing */
@@ -506,10 +532,11 @@
506 #define MODE_Html 4 /* Generate an XHTML table */
507 #define MODE_Insert 5 /* Generate SQL "insert" statements */
508 #define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
509 #define MODE_Csv 7 /* Quote strings, numbers are plain */
510 #define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
 
511
512 static const char *modeDescr[] = {
513 "line",
514 "column",
515 "list",
@@ -517,12 +544,26 @@
517 "html",
518 "insert",
519 "tcl",
520 "csv",
521 "explain",
 
522 };
523
 
 
 
 
 
 
 
 
 
 
 
 
 
524 /*
525 ** Number of elements in an array
526 */
527 #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
528
@@ -561,10 +602,11 @@
561 ** Output the given string as a quoted string using SQL quoting conventions.
562 */
563 static void output_quoted_string(FILE *out, const char *z){
564 int i;
565 int nSingle = 0;
 
566 for(i=0; z[i]; i++){
567 if( z[i]=='\'' ) nSingle++;
568 }
569 if( nSingle==0 ){
570 fprintf(out,"'%s'",z);
@@ -583,10 +625,11 @@
583 break;
584 }
585 }
586 fprintf(out,"'");
587 }
 
588 }
589
590 /*
591 ** Output the given string as a quoted according to C or TCL quoting rules.
592 */
@@ -675,26 +718,26 @@
675 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
676 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
677 };
678
679 /*
680 ** Output a single term of CSV. Actually, p->separator is used for
681 ** the separator, which may or may not be a comma. p->nullvalue is
682 ** the null value. Strings are quoted if necessary. The separator
683 ** is only issued if bSep is true.
684 */
685 static void output_csv(ShellState *p, const char *z, int bSep){
686 FILE *out = p->out;
687 if( z==0 ){
688 fprintf(out,"%s",p->nullvalue);
689 }else{
690 int i;
691 int nSep = strlen30(p->separator);
692 for(i=0; z[i]; i++){
693 if( needCsvQuote[((unsigned char*)z)[i]]
694 || (z[i]==p->separator[0] &&
695 (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
696 i = 0;
697 break;
698 }
699 }
700 if( i==0 ){
@@ -707,11 +750,11 @@
707 }else{
708 fprintf(out, "%s", z);
709 }
710 }
711 if( bSep ){
712 fprintf(p->out, "%s", p->separator);
713 }
714 }
715
716 #ifdef SIGINT
717 /*
@@ -745,14 +788,14 @@
745 if( azArg==0 ) break;
746 for(i=0; i<nArg; i++){
747 int len = strlen30(azCol[i] ? azCol[i] : "");
748 if( len>w ) w = len;
749 }
750 if( p->cnt++>0 ) fprintf(p->out,"\n");
751 for(i=0; i<nArg; i++){
752 fprintf(p->out,"%*s = %s\n", w, azCol[i],
753 azArg[i] ? azArg[i] : p->nullvalue);
754 }
755 break;
756 }
757 case MODE_Explain:
758 case MODE_Column: {
@@ -765,21 +808,23 @@
765 w = 0;
766 }
767 if( w==0 ){
768 w = strlen30(azCol[i] ? azCol[i] : "");
769 if( w<10 ) w = 10;
770 n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
771 if( w<n ) w = n;
772 }
773 if( i<ArraySize(p->actualWidth) ){
774 p->actualWidth[i] = w;
775 }
776 if( p->showHeader ){
777 if( w<0 ){
778 fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": " ");
 
779 }else{
780 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
 
781 }
782 }
783 }
784 if( p->showHeader ){
785 for(i=0; i<nArg; i++){
@@ -790,11 +835,11 @@
790 }else{
791 w = 10;
792 }
793 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
794 "----------------------------------------------------------",
795 i==nArg-1 ? "\n": " ");
796 }
797 }
798 }
799 if( azArg==0 ) break;
800 for(i=0; i<nArg; i++){
@@ -813,36 +858,39 @@
813 }
814 p->iIndent++;
815 }
816 if( w<0 ){
817 fprintf(p->out,"%*.*s%s",-w,-w,
818 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
 
819 }else{
820 fprintf(p->out,"%-*.*s%s",w,w,
821 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
 
822 }
823 }
824 break;
825 }
826 case MODE_Semi:
827 case MODE_List: {
828 if( p->cnt++==0 && p->showHeader ){
829 for(i=0; i<nArg; i++){
830 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
 
831 }
832 }
833 if( azArg==0 ) break;
834 for(i=0; i<nArg; i++){
835 char *z = azArg[i];
836 if( z==0 ) z = p->nullvalue;
837 fprintf(p->out, "%s", z);
838 if( i<nArg-1 ){
839 fprintf(p->out, "%s", p->separator);
840 }else if( p->mode==MODE_Semi ){
841 fprintf(p->out, ";\n");
842 }else{
843 fprintf(p->out, "\n");
844 }
845 }
846 break;
847 }
848 case MODE_Html: {
@@ -857,53 +905,47 @@
857 }
858 if( azArg==0 ) break;
859 fprintf(p->out,"<TR>");
860 for(i=0; i<nArg; i++){
861 fprintf(p->out,"<TD>");
862 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
863 fprintf(p->out,"</TD>\n");
864 }
865 fprintf(p->out,"</TR>\n");
866 break;
867 }
868 case MODE_Tcl: {
869 if( p->cnt++==0 && p->showHeader ){
870 for(i=0; i<nArg; i++){
871 output_c_string(p->out,azCol[i] ? azCol[i] : "");
872 if(i<nArg-1) fprintf(p->out, "%s", p->separator);
873 }
874 fprintf(p->out,"\n");
875 }
876 if( azArg==0 ) break;
877 for(i=0; i<nArg; i++){
878 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
879 if(i<nArg-1) fprintf(p->out, "%s", p->separator);
880 }
881 fprintf(p->out,"\n");
882 break;
883 }
884 case MODE_Csv: {
885 #if defined(WIN32) || defined(_WIN32)
886 fflush(p->out);
887 _setmode(_fileno(p->out), _O_BINARY);
888 #endif
889 if( p->cnt++==0 && p->showHeader ){
890 for(i=0; i<nArg; i++){
891 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
892 }
893 fprintf(p->out,"%s",p->newline);
894 }
895 if( nArg>0 ){
896 for(i=0; i<nArg; i++){
897 output_csv(p, azArg[i], i<nArg-1);
898 }
899 fprintf(p->out,"%s",p->newline);
900 }
901 #if defined(WIN32) || defined(_WIN32)
902 fflush(p->out);
903 _setmode(_fileno(p->out), _O_TEXT);
904 #endif
905 break;
906 }
907 case MODE_Insert: {
908 p->cnt++;
909 if( azArg==0 ) break;
@@ -930,10 +972,26 @@
930 output_quoted_string(p->out, azArg[i]);
931 }
932 }
933 fprintf(p->out,");\n");
934 break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
935 }
936 }
937 return 0;
938 }
939
@@ -1428,10 +1486,21 @@
1428 }
1429 }
1430 sqlite3_finalize(pExplain);
1431 sqlite3_free(zEQP);
1432 }
 
 
 
 
 
 
 
 
 
 
 
1433
1434 /* If the shell is currently in ".explain" mode, gather the extra
1435 ** data required to add indents to the output.*/
1436 if( pArg && pArg->mode==MODE_Explain ){
1437 explain_data_prepare(pArg, pStmt);
@@ -1696,16 +1765,17 @@
1696 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1697 ".load FILE ?ENTRY? Load an extension library\n"
1698 #endif
1699 ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
1700 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
 
1701 " csv Comma-separated values\n"
1702 " column Left-aligned columns. (See .width)\n"
1703 " html HTML <table> code\n"
1704 " insert SQL insert statements for TABLE\n"
1705 " line One value per line\n"
1706 " list Values delimited by .separator string\n"
1707 " tabs Tab-separated values\n"
1708 " tcl TCL list elements\n"
1709 ".nullvalue STRING Use STRING in place of NULL values\n"
1710 ".once FILENAME Output for the next SQL command only to FILENAME\n"
1711 ".open ?FILENAME? Close existing database and reopen FILENAME\n"
@@ -1718,12 +1788,12 @@
1718 ".save FILE Write in-memory database into FILE\n"
1719 ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
1720 ".schema ?TABLE? Show the CREATE statements\n"
1721 " If TABLE specified, only show tables matching\n"
1722 " LIKE pattern TABLE.\n"
1723 ".separator STRING ?NL? Change separator used by output mode and .import\n"
1724 " NL is the end-of-line mark for CSV\n"
1725 ".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
1726 ".show Show the current values for various settings\n"
1727 ".stats on|off Turn stats on or off\n"
1728 ".system CMD ARGS... Run CMD ARGS... in a system shell\n"
1729 ".tables ?TABLE? List names of tables\n"
@@ -2000,26 +2070,27 @@
2000 static int nCall = 0;
2001 nCall++;
2002 }
2003
2004 /*
2005 ** An object used to read a CSV file
2006 */
2007 typedef struct CSVReader CSVReader;
2008 struct CSVReader {
2009 const char *zFile; /* Name of the input file */
2010 FILE *in; /* Read the CSV text from this input stream */
2011 char *z; /* Accumulated text for a field */
2012 int n; /* Number of bytes in z */
2013 int nAlloc; /* Space allocated for z[] */
2014 int nLine; /* Current line number */
2015 int cTerm; /* Character that terminated the most recent field */
2016 int cSeparator; /* The separator character. (Usually ",") */
 
2017 };
2018
2019 /* Append a single byte to z[] */
2020 static void csv_append_char(CSVReader *p, int c){
2021 if( p->n+1>=p->nAlloc ){
2022 p->nAlloc += p->nAlloc + 100;
2023 p->z = sqlite3_realloc(p->z, p->nAlloc);
2024 if( p->z==0 ){
2025 fprintf(stderr, "out of memory\n");
@@ -2033,41 +2104,44 @@
2033 ** with the option of having a separator other than ",".
2034 **
2035 ** + Input comes from p->in.
2036 ** + Store results in p->z of length p->n. Space to hold p->z comes
2037 ** from sqlite3_malloc().
2038 ** + Use p->cSep as the separator. The default is ",".
 
2039 ** + Keep track of the line number in p->nLine.
2040 ** + Store the character that terminates the field in p->cTerm. Store
2041 ** EOF on end-of-file.
2042 ** + Report syntax errors on stderr
2043 */
2044 static char *csv_read_one_field(CSVReader *p){
2045 int c, pc, ppc;
2046 int cSep = p->cSeparator;
 
2047 p->n = 0;
2048 c = fgetc(p->in);
2049 if( c==EOF || seenInterrupt ){
2050 p->cTerm = EOF;
2051 return 0;
2052 }
2053 if( c=='"' ){
 
2054 int startLine = p->nLine;
2055 int cQuote = c;
2056 pc = ppc = 0;
2057 while( 1 ){
2058 c = fgetc(p->in);
2059 if( c=='\n' ) p->nLine++;
2060 if( c==cQuote ){
2061 if( pc==cQuote ){
2062 pc = 0;
2063 continue;
2064 }
2065 }
2066 if( (c==cSep && pc==cQuote)
2067 || (c=='\n' && pc==cQuote)
2068 || (c=='\n' && pc=='\r' && ppc==cQuote)
2069 || (c==EOF && pc==cQuote)
2070 ){
2071 do{ p->n--; }while( p->z[p->n]!=cQuote );
2072 p->cTerm = c;
2073 break;
@@ -2077,31 +2151,65 @@
2077 p->zFile, p->nLine, cQuote);
2078 }
2079 if( c==EOF ){
2080 fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
2081 p->zFile, startLine, cQuote);
2082 p->cTerm = EOF;
2083 break;
2084 }
2085 csv_append_char(p, c);
2086 ppc = pc;
2087 pc = c;
2088 }
2089 }else{
2090 while( c!=EOF && c!=cSep && c!='\n' ){
2091 csv_append_char(p, c);
2092 c = fgetc(p->in);
2093 }
2094 if( c=='\n' ){
2095 p->nLine++;
2096 if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
2097 }
2098 p->cTerm = c;
2099 }
2100 if( p->z ) p->z[p->n] = 0;
2101 return p->z;
2102 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2103
2104 /*
2105 ** Try to transfer data for table zTable. If an error is seen while
2106 ** moving forward, try to go backwards. The backwards movement won't
2107 ** work for WITHOUT ROWID tables.
@@ -2653,100 +2761,125 @@
2653 sqlite3_stmt *pStmt = NULL; /* A statement */
2654 int nCol; /* Number of columns in the table */
2655 int nByte; /* Number of bytes in an SQL string */
2656 int i, j; /* Loop counters */
2657 int needCommit; /* True to COMMIT or ROLLBACK at end */
2658 int nSep; /* Number of bytes in p->separator[] */
2659 char *zSql; /* An SQL statement */
2660 CSVReader sCsv; /* Reader context */
 
2661 int (*xCloser)(FILE*); /* Procedure to close th3 connection */
2662
2663 if( nArg!=3 ){
2664 fprintf(stderr, "Usage: .import FILE TABLE\n");
2665 goto meta_command_exit;
2666 }
2667 zFile = azArg[1];
2668 zTable = azArg[2];
2669 seenInterrupt = 0;
2670 memset(&sCsv, 0, sizeof(sCsv));
2671 open_db(p, 0);
2672 nSep = strlen30(p->separator);
 
 
 
 
 
 
 
 
 
 
2673 if( nSep==0 ){
2674 fprintf(stderr, "Error: non-null separator required for import\n");
2675 return 1;
 
 
 
 
 
 
 
 
2676 }
2677 if( nSep>1 ){
2678 fprintf(stderr, "Error: multi-character separators not allowed"
2679 " for import\n");
2680 return 1;
2681 }
2682 sCsv.zFile = zFile;
2683 sCsv.nLine = 1;
2684 if( sCsv.zFile[0]=='|' ){
2685 sCsv.in = popen(sCsv.zFile+1, "r");
2686 sCsv.zFile = "<pipe>";
2687 xCloser = pclose;
2688 }else{
2689 sCsv.in = fopen(sCsv.zFile, "rb");
2690 xCloser = fclose;
2691 }
2692 if( sCsv.in==0 ){
 
 
 
 
 
2693 fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
2694 return 1;
2695 }
2696 sCsv.cSeparator = p->separator[0];
 
2697 zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
2698 if( zSql==0 ){
2699 fprintf(stderr, "Error: out of memory\n");
2700 xCloser(sCsv.in);
2701 return 1;
2702 }
2703 nByte = strlen30(zSql);
2704 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2705 csv_append_char(&sCsv, 0); /* To ensure sCsv.z is allocated */
2706 if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
2707 char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
2708 char cSep = '(';
2709 while( csv_read_one_field(&sCsv) ){
2710 zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z);
2711 cSep = ',';
2712 if( sCsv.cTerm!=sCsv.cSeparator ) break;
2713 }
2714 if( cSep=='(' ){
2715 sqlite3_free(zCreate);
2716 sqlite3_free(sCsv.z);
2717 xCloser(sCsv.in);
2718 fprintf(stderr,"%s: empty file\n", sCsv.zFile);
2719 return 1;
2720 }
2721 zCreate = sqlite3_mprintf("%z\n)", zCreate);
2722 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
2723 sqlite3_free(zCreate);
2724 if( rc ){
2725 fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
2726 sqlite3_errmsg(db));
2727 sqlite3_free(sCsv.z);
2728 xCloser(sCsv.in);
2729 return 1;
2730 }
2731 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2732 }
2733 sqlite3_free(zSql);
2734 if( rc ){
2735 if (pStmt) sqlite3_finalize(pStmt);
2736 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
2737 xCloser(sCsv.in);
2738 return 1;
2739 }
2740 nCol = sqlite3_column_count(pStmt);
2741 sqlite3_finalize(pStmt);
2742 pStmt = 0;
2743 if( nCol==0 ) return 0; /* no columns, no error */
2744 zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
2745 if( zSql==0 ){
2746 fprintf(stderr, "Error: out of memory\n");
2747 xCloser(sCsv.in);
2748 return 1;
2749 }
2750 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
2751 j = strlen30(zSql);
2752 for(i=1; i<nCol; i++){
@@ -2758,50 +2891,60 @@
2758 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2759 sqlite3_free(zSql);
2760 if( rc ){
2761 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
2762 if (pStmt) sqlite3_finalize(pStmt);
2763 xCloser(sCsv.in);
2764 return 1;
2765 }
2766 needCommit = sqlite3_get_autocommit(db);
2767 if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
2768 do{
2769 int startLine = sCsv.nLine;
2770 for(i=0; i<nCol; i++){
2771 char *z = csv_read_one_field(&sCsv);
 
 
 
 
2772 if( z==0 && i==0 ) break;
 
 
 
 
 
 
2773 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
2774 if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
2775 fprintf(stderr, "%s:%d: expected %d columns but found %d - "
2776 "filling the rest with NULL\n",
2777 sCsv.zFile, startLine, nCol, i+1);
2778 i++;
2779 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
2780 }
2781 }
2782 if( sCsv.cTerm==sCsv.cSeparator ){
2783 do{
2784 csv_read_one_field(&sCsv);
2785 i++;
2786 }while( sCsv.cTerm==sCsv.cSeparator );
2787 fprintf(stderr, "%s:%d: expected %d columns but found %d - "
2788 "extras ignored\n",
2789 sCsv.zFile, startLine, nCol, i);
2790 }
2791 if( i>=nCol ){
2792 sqlite3_step(pStmt);
2793 rc = sqlite3_reset(pStmt);
2794 if( rc!=SQLITE_OK ){
2795 fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine,
2796 sqlite3_errmsg(db));
2797 }
2798 }
2799 }while( sCsv.cTerm!=EOF );
2800
2801 xCloser(sCsv.in);
2802 sqlite3_free(sCsv.z);
2803 sqlite3_finalize(pStmt);
2804 if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
2805 }else
2806
2807 if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
@@ -2915,32 +3058,36 @@
2915 p->mode = MODE_List;
2916 }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
2917 p->mode = MODE_Html;
2918 }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
2919 p->mode = MODE_Tcl;
2920 sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
2921 }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
2922 p->mode = MODE_Csv;
2923 sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
2924 sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");
2925 }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
2926 p->mode = MODE_List;
2927 sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
2928 }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
2929 p->mode = MODE_Insert;
2930 set_table_name(p, nArg>=3 ? azArg[2] : "table");
 
 
 
 
2931 }else {
2932 fprintf(stderr,"Error: mode should be one of: "
2933 "column csv html insert line list tabs tcl\n");
2934 rc = 1;
2935 }
2936 }else
2937
2938 if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
2939 if( nArg==2 ){
2940 sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
2941 "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
2942 }else{
2943 fprintf(stderr, "Usage: .nullvalue STRING\n");
2944 rc = 1;
2945 }
2946 }else
@@ -3191,11 +3338,11 @@
3191
3192
3193 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
3194 if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
3195 extern int sqlite3SelectTrace;
3196 sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
3197 }else
3198 #endif
3199
3200
3201 #ifdef SQLITE_DEBUG
@@ -3221,18 +3368,20 @@
3221 }else
3222 #endif
3223
3224 if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
3225 if( nArg<2 || nArg>3 ){
3226 fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
3227 rc = 1;
3228 }
3229 if( nArg>=2 ){
3230 sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);
 
3231 }
3232 if( nArg>=3 ){
3233 sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);
 
3234 }
3235 }else
3236
3237 if( c=='s'
3238 && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
@@ -3259,27 +3408,28 @@
3259 if( nArg!=1 ){
3260 fprintf(stderr, "Usage: .show\n");
3261 rc = 1;
3262 goto meta_command_exit;
3263 }
3264 fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
3265 fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
3266 fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
3267 fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
3268 fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
3269 fprintf(p->out,"%9.9s: ", "nullvalue");
3270 output_c_string(p->out, p->nullvalue);
3271 fprintf(p->out, "\n");
3272 fprintf(p->out,"%9.9s: %s\n","output",
3273 strlen30(p->outfile) ? p->outfile : "stdout");
3274 fprintf(p->out,"%9.9s: ", "separator");
3275 output_c_string(p->out, p->separator);
3276 fprintf(p->out," ");
3277 output_c_string(p->out, p->newline);
 
3278 fprintf(p->out, "\n");
3279 fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
3280 fprintf(p->out,"%9.9s: ","width");
3281 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
3282 fprintf(p->out,"%d ",p->colWidth[i]);
3283 }
3284 fprintf(p->out,"\n");
3285 }else
@@ -3394,10 +3544,11 @@
3394 { "reserve", SQLITE_TESTCTRL_RESERVE },
3395 { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
3396 { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
3397 { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
3398 { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
 
3399 };
3400 int testctrl = -1;
3401 int rc = 0;
3402 int i, n;
3403 open_db(p, 0);
@@ -3460,11 +3611,12 @@
3460 }
3461 break;
3462
3463 /* sqlite3_test_control(int, int) */
3464 case SQLITE_TESTCTRL_ASSERT:
3465 case SQLITE_TESTCTRL_ALWAYS:
 
3466 if( nArg==3 ){
3467 int opt = booleanValue(azArg[2]);
3468 rc = sqlite3_test_control(testctrl, opt);
3469 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3470 } else {
@@ -3936,10 +4088,11 @@
3936
3937 /*
3938 ** Show available command line options
3939 */
3940 static const char zOptions[] =
 
3941 " -bail stop after hitting an error\n"
3942 " -batch force batch I/O\n"
3943 " -column set output mode to 'column'\n"
3944 " -cmd COMMAND run \"COMMAND\" before reading stdin\n"
3945 " -csv set output mode to 'csv'\n"
@@ -3957,15 +4110,15 @@
3957 " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
3958 " -mmap N default mmap size set to N\n"
3959 #ifdef SQLITE_ENABLE_MULTIPLEX
3960 " -multiplex enable the multiplexor VFS\n"
3961 #endif
3962 " -newline SEP set newline character(s) for CSV\n"
3963 " -nullvalue TEXT set text string for NULL values. Default ''\n"
3964 " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
3965 " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
3966 " -separator SEP set output field separator. Default: '|'\n"
3967 " -stats print memory stats before each finalize\n"
3968 " -version show SQLite version\n"
3969 " -vfs NAME use NAME as the default VFS\n"
3970 #ifdef SQLITE_ENABLE_VFSTRACE
3971 " -vfstrace enable tracing of all VFS calls\n"
@@ -3988,12 +4141,12 @@
3988 ** Initialize the state information in data
3989 */
3990 static void main_init(ShellState *data) {
3991 memset(data, 0, sizeof(*data));
3992 data->mode = MODE_List;
3993 memcpy(data->separator,"|", 2);
3994 memcpy(data->newline,"\r\n", 3);
3995 data->showHeader = 0;
3996 data->shellFlgs = SHFLG_Lookaside;
3997 sqlite3_config(SQLITE_CONFIG_URI, 1);
3998 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
3999 sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -4050,10 +4203,12 @@
4050 fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
4051 sqlite3_sourceid(), SQLITE_SOURCE_ID);
4052 exit(1);
4053 }
4054 #endif
 
 
4055 Argv0 = argv[0];
4056 main_init(&data);
4057 stdin_is_interactive = isatty(0);
4058
4059 /* Make sure we have a valid signal handler early, before anything
@@ -4228,19 +4383,25 @@
4228 data.mode = MODE_Line;
4229 }else if( strcmp(z,"-column")==0 ){
4230 data.mode = MODE_Column;
4231 }else if( strcmp(z,"-csv")==0 ){
4232 data.mode = MODE_Csv;
4233 memcpy(data.separator,",",2);
 
 
 
 
 
 
4234 }else if( strcmp(z,"-separator")==0 ){
4235 sqlite3_snprintf(sizeof(data.separator), data.separator,
4236 "%s",cmdline_option_value(argc,argv,++i));
4237 }else if( strcmp(z,"-newline")==0 ){
4238 sqlite3_snprintf(sizeof(data.newline), data.newline,
4239 "%s",cmdline_option_value(argc,argv,++i));
4240 }else if( strcmp(z,"-nullvalue")==0 ){
4241 sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
4242 "%s",cmdline_option_value(argc,argv,++i));
4243 }else if( strcmp(z,"-header")==0 ){
4244 data.showHeader = 1;
4245 }else if( strcmp(z,"-noheader")==0 ){
4246 data.showHeader = 0;
@@ -4356,11 +4517,11 @@
4356 nHistory = strlen30(zHome) + 20;
4357 if( (zHistory = malloc(nHistory))!=0 ){
4358 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
4359 }
4360 }
4361 #if defined(HAVE_READLINE)
4362 if( zHistory ) read_history(zHistory);
4363 #endif
4364 rc = process_input(&data, 0);
4365 if( zHistory ){
4366 stifle_history(100);
4367
--- src/shell.c
+++ src/shell.c
@@ -15,10 +15,17 @@
15 #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
16 /* This needs to come before any includes for MSVC compiler */
17 #define _CRT_SECURE_NO_WARNINGS
18 #endif
19
20 /*
21 ** If requested, include the SQLite compiler options file for MSVC.
22 */
23 #if defined(INCLUDE_MSVC_H)
24 #include "msvc.h"
25 #endif
26
27 /*
28 ** Enable large-file support for fopen() and friends on unix.
29 */
30 #ifndef SQLITE_DISABLE_LFS
31 # define _LARGE_FILE 1
@@ -46,21 +53,20 @@
53 # endif
54 # include <unistd.h>
55 # include <sys/types.h>
56 #endif
57
58 #if HAVE_READLINE
59 # include <readline/readline.h>
60 # include <readline/history.h>
 
 
61 #endif
62 #if HAVE_EDITLINE
63 # undef HAVE_READLINE
64 # define HAVE_READLINE 1
65 # include <editline/readline.h>
66 #endif
67 #if !HAVE_READLINE
68 # define add_history(X)
69 # define read_history(X)
70 # define write_history(X)
71 # define stifle_history(X)
72 #endif
@@ -97,10 +103,30 @@
103
104 /* ctype macros that work with signed characters */
105 #define IsSpace(X) isspace((unsigned char)X)
106 #define IsDigit(X) isdigit((unsigned char)X)
107 #define ToLower(X) (char)tolower((unsigned char)X)
108
109 /* On Windows, we normally run with output mode of TEXT so that \n characters
110 ** are automatically translated into \r\n. However, this behavior needs
111 ** to be disabled in some cases (ex: when generating CSV output and when
112 ** rendering quoted strings that contain \n characters). The following
113 ** routines take care of that.
114 */
115 #if defined(_WIN32) || defined(WIN32)
116 static void setBinaryMode(FILE *out){
117 fflush(out);
118 _setmode(_fileno(out), _O_BINARY);
119 }
120 static void setTextMode(FILE *out){
121 fflush(out);
122 _setmode(_fileno(out), _O_TEXT);
123 }
124 #else
125 # define setBinaryMode(X)
126 # define setTextMode(X)
127 #endif
128
129
130 /* True if the timer is enabled */
131 static int enableTimer = 0;
132
@@ -423,11 +449,11 @@
449 char *zResult;
450 if( in!=0 ){
451 zResult = local_getline(zPrior, in);
452 }else{
453 zPrompt = isContinuation ? continuePrompt : mainPrompt;
454 #if HAVE_READLINE
455 free(zPrior);
456 zResult = readline(zPrompt);
457 if( zResult && *zResult ) add_history(zResult);
458 #else
459 printf("%s", zPrompt);
@@ -469,15 +495,15 @@
495 int mode; /* An output mode setting */
496 int writableSchema; /* True if PRAGMA writable_schema=ON */
497 int showHeader; /* True to show column names in List or Column mode */
498 unsigned shellFlgs; /* Various flags */
499 char *zDestTable; /* Name of destination table when MODE_Insert */
500 char colSeparator[20]; /* Column separator character for several modes */
501 char rowSeparator[20]; /* Row separator character for MODE_Ascii */
502 int colWidth[100]; /* Requested width of each column when in column mode*/
503 int actualWidth[100]; /* Actual width of each column */
504 char nullValue[20]; /* The text to print when a NULL comes back from
505 ** the database */
506 SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
507 char outfile[FILENAME_MAX]; /* Filename for *out */
508 const char *zDbFilename; /* name of the database file */
509 char *zFreeOnClose; /* Filename to free when closing */
@@ -506,10 +532,11 @@
532 #define MODE_Html 4 /* Generate an XHTML table */
533 #define MODE_Insert 5 /* Generate SQL "insert" statements */
534 #define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
535 #define MODE_Csv 7 /* Quote strings, numbers are plain */
536 #define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
537 #define MODE_Ascii 9 /* Use ASCII unit and record separators (0x1F/0x1E) */
538
539 static const char *modeDescr[] = {
540 "line",
541 "column",
542 "list",
@@ -517,12 +544,26 @@
544 "html",
545 "insert",
546 "tcl",
547 "csv",
548 "explain",
549 "ascii",
550 };
551
552 /*
553 ** These are the column/row/line separators used by the various
554 ** import/export modes.
555 */
556 #define SEP_Column "|"
557 #define SEP_Row "\n"
558 #define SEP_Tab "\t"
559 #define SEP_Space " "
560 #define SEP_Comma ","
561 #define SEP_CrLf "\r\n"
562 #define SEP_Unit "\x1F"
563 #define SEP_Record "\x1E"
564
565 /*
566 ** Number of elements in an array
567 */
568 #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
569
@@ -561,10 +602,11 @@
602 ** Output the given string as a quoted string using SQL quoting conventions.
603 */
604 static void output_quoted_string(FILE *out, const char *z){
605 int i;
606 int nSingle = 0;
607 setBinaryMode(out);
608 for(i=0; z[i]; i++){
609 if( z[i]=='\'' ) nSingle++;
610 }
611 if( nSingle==0 ){
612 fprintf(out,"'%s'",z);
@@ -583,10 +625,11 @@
625 break;
626 }
627 }
628 fprintf(out,"'");
629 }
630 setTextMode(out);
631 }
632
633 /*
634 ** Output the given string as a quoted according to C or TCL quoting rules.
635 */
@@ -675,26 +718,26 @@
718 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
719 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
720 };
721
722 /*
723 ** Output a single term of CSV. Actually, p->colSeparator is used for
724 ** the separator, which may or may not be a comma. p->nullValue is
725 ** the null value. Strings are quoted if necessary. The separator
726 ** is only issued if bSep is true.
727 */
728 static void output_csv(ShellState *p, const char *z, int bSep){
729 FILE *out = p->out;
730 if( z==0 ){
731 fprintf(out,"%s",p->nullValue);
732 }else{
733 int i;
734 int nSep = strlen30(p->colSeparator);
735 for(i=0; z[i]; i++){
736 if( needCsvQuote[((unsigned char*)z)[i]]
737 || (z[i]==p->colSeparator[0] &&
738 (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
739 i = 0;
740 break;
741 }
742 }
743 if( i==0 ){
@@ -707,11 +750,11 @@
750 }else{
751 fprintf(out, "%s", z);
752 }
753 }
754 if( bSep ){
755 fprintf(p->out, "%s", p->colSeparator);
756 }
757 }
758
759 #ifdef SIGINT
760 /*
@@ -745,14 +788,14 @@
788 if( azArg==0 ) break;
789 for(i=0; i<nArg; i++){
790 int len = strlen30(azCol[i] ? azCol[i] : "");
791 if( len>w ) w = len;
792 }
793 if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
794 for(i=0; i<nArg; i++){
795 fprintf(p->out,"%*s = %s%s", w, azCol[i],
796 azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
797 }
798 break;
799 }
800 case MODE_Explain:
801 case MODE_Column: {
@@ -765,21 +808,23 @@
808 w = 0;
809 }
810 if( w==0 ){
811 w = strlen30(azCol[i] ? azCol[i] : "");
812 if( w<10 ) w = 10;
813 n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
814 if( w<n ) w = n;
815 }
816 if( i<ArraySize(p->actualWidth) ){
817 p->actualWidth[i] = w;
818 }
819 if( p->showHeader ){
820 if( w<0 ){
821 fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
822 i==nArg-1 ? p->rowSeparator : " ");
823 }else{
824 fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
825 i==nArg-1 ? p->rowSeparator : " ");
826 }
827 }
828 }
829 if( p->showHeader ){
830 for(i=0; i<nArg; i++){
@@ -790,11 +835,11 @@
835 }else{
836 w = 10;
837 }
838 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
839 "----------------------------------------------------------",
840 i==nArg-1 ? p->rowSeparator : " ");
841 }
842 }
843 }
844 if( azArg==0 ) break;
845 for(i=0; i<nArg; i++){
@@ -813,36 +858,39 @@
858 }
859 p->iIndent++;
860 }
861 if( w<0 ){
862 fprintf(p->out,"%*.*s%s",-w,-w,
863 azArg[i] ? azArg[i] : p->nullValue,
864 i==nArg-1 ? p->rowSeparator : " ");
865 }else{
866 fprintf(p->out,"%-*.*s%s",w,w,
867 azArg[i] ? azArg[i] : p->nullValue,
868 i==nArg-1 ? p->rowSeparator : " ");
869 }
870 }
871 break;
872 }
873 case MODE_Semi:
874 case MODE_List: {
875 if( p->cnt++==0 && p->showHeader ){
876 for(i=0; i<nArg; i++){
877 fprintf(p->out,"%s%s",azCol[i],
878 i==nArg-1 ? p->rowSeparator : p->colSeparator);
879 }
880 }
881 if( azArg==0 ) break;
882 for(i=0; i<nArg; i++){
883 char *z = azArg[i];
884 if( z==0 ) z = p->nullValue;
885 fprintf(p->out, "%s", z);
886 if( i<nArg-1 ){
887 fprintf(p->out, "%s", p->colSeparator);
888 }else if( p->mode==MODE_Semi ){
889 fprintf(p->out, ";%s", p->rowSeparator);
890 }else{
891 fprintf(p->out, "%s", p->rowSeparator);
892 }
893 }
894 break;
895 }
896 case MODE_Html: {
@@ -857,53 +905,47 @@
905 }
906 if( azArg==0 ) break;
907 fprintf(p->out,"<TR>");
908 for(i=0; i<nArg; i++){
909 fprintf(p->out,"<TD>");
910 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
911 fprintf(p->out,"</TD>\n");
912 }
913 fprintf(p->out,"</TR>\n");
914 break;
915 }
916 case MODE_Tcl: {
917 if( p->cnt++==0 && p->showHeader ){
918 for(i=0; i<nArg; i++){
919 output_c_string(p->out,azCol[i] ? azCol[i] : "");
920 if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
921 }
922 fprintf(p->out, "%s", p->rowSeparator);
923 }
924 if( azArg==0 ) break;
925 for(i=0; i<nArg; i++){
926 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
927 if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
928 }
929 fprintf(p->out, "%s", p->rowSeparator);
930 break;
931 }
932 case MODE_Csv: {
933 setBinaryMode(p->out);
 
 
 
934 if( p->cnt++==0 && p->showHeader ){
935 for(i=0; i<nArg; i++){
936 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
937 }
938 fprintf(p->out, "%s", p->rowSeparator);
939 }
940 if( nArg>0 ){
941 for(i=0; i<nArg; i++){
942 output_csv(p, azArg[i], i<nArg-1);
943 }
944 fprintf(p->out, "%s", p->rowSeparator);
945 }
946 setTextMode(p->out);
 
 
 
947 break;
948 }
949 case MODE_Insert: {
950 p->cnt++;
951 if( azArg==0 ) break;
@@ -930,10 +972,26 @@
972 output_quoted_string(p->out, azArg[i]);
973 }
974 }
975 fprintf(p->out,");\n");
976 break;
977 }
978 case MODE_Ascii: {
979 if( p->cnt++==0 && p->showHeader ){
980 for(i=0; i<nArg; i++){
981 if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
982 fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
983 }
984 fprintf(p->out, "%s", p->rowSeparator);
985 }
986 if( azArg==0 ) break;
987 for(i=0; i<nArg; i++){
988 if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
989 fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
990 }
991 fprintf(p->out, "%s", p->rowSeparator);
992 break;
993 }
994 }
995 return 0;
996 }
997
@@ -1428,10 +1486,21 @@
1486 }
1487 }
1488 sqlite3_finalize(pExplain);
1489 sqlite3_free(zEQP);
1490 }
1491
1492 #if USE_SYSTEM_SQLITE+0==1
1493 /* Output TESTCTRL_EXPLAIN text of requested */
1494 if( pArg && pArg->mode==MODE_Explain && sqlite3_libversion_number()<3008007 ){
1495 const char *zExplain = 0;
1496 sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
1497 if( zExplain && zExplain[0] ){
1498 fprintf(pArg->out, "%s", zExplain);
1499 }
1500 }
1501 #endif
1502
1503 /* If the shell is currently in ".explain" mode, gather the extra
1504 ** data required to add indents to the output.*/
1505 if( pArg && pArg->mode==MODE_Explain ){
1506 explain_data_prepare(pArg, pStmt);
@@ -1696,16 +1765,17 @@
1765 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1766 ".load FILE ?ENTRY? Load an extension library\n"
1767 #endif
1768 ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
1769 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
1770 " ascii Columns/rows delimited by 0x1F and 0x1E\n"
1771 " csv Comma-separated values\n"
1772 " column Left-aligned columns. (See .width)\n"
1773 " html HTML <table> code\n"
1774 " insert SQL insert statements for TABLE\n"
1775 " line One value per line\n"
1776 " list Values delimited by .separator strings\n"
1777 " tabs Tab-separated values\n"
1778 " tcl TCL list elements\n"
1779 ".nullvalue STRING Use STRING in place of NULL values\n"
1780 ".once FILENAME Output for the next SQL command only to FILENAME\n"
1781 ".open ?FILENAME? Close existing database and reopen FILENAME\n"
@@ -1718,12 +1788,12 @@
1788 ".save FILE Write in-memory database into FILE\n"
1789 ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
1790 ".schema ?TABLE? Show the CREATE statements\n"
1791 " If TABLE specified, only show tables matching\n"
1792 " LIKE pattern TABLE.\n"
1793 ".separator COL ?ROW? Change the column separator and optionally the row\n"
1794 " separator for both the output mode and .import\n"
1795 ".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
1796 ".show Show the current values for various settings\n"
1797 ".stats on|off Turn stats on or off\n"
1798 ".system CMD ARGS... Run CMD ARGS... in a system shell\n"
1799 ".tables ?TABLE? List names of tables\n"
@@ -2000,26 +2070,27 @@
2070 static int nCall = 0;
2071 nCall++;
2072 }
2073
2074 /*
2075 ** An object used to read a CSV and other files for import.
2076 */
2077 typedef struct ImportCtx ImportCtx;
2078 struct ImportCtx {
2079 const char *zFile; /* Name of the input file */
2080 FILE *in; /* Read the CSV text from this input stream */
2081 char *z; /* Accumulated text for a field */
2082 int n; /* Number of bytes in z */
2083 int nAlloc; /* Space allocated for z[] */
2084 int nLine; /* Current line number */
2085 int cTerm; /* Character that terminated the most recent field */
2086 int cColSep; /* The column separator character. (Usually ",") */
2087 int cRowSep; /* The row separator character. (Usually "\n") */
2088 };
2089
2090 /* Append a single byte to z[] */
2091 static void import_append_char(ImportCtx *p, int c){
2092 if( p->n+1>=p->nAlloc ){
2093 p->nAlloc += p->nAlloc + 100;
2094 p->z = sqlite3_realloc(p->z, p->nAlloc);
2095 if( p->z==0 ){
2096 fprintf(stderr, "out of memory\n");
@@ -2033,41 +2104,44 @@
2104 ** with the option of having a separator other than ",".
2105 **
2106 ** + Input comes from p->in.
2107 ** + Store results in p->z of length p->n. Space to hold p->z comes
2108 ** from sqlite3_malloc().
2109 ** + Use p->cSep as the column separator. The default is ",".
2110 ** + Use p->rSep as the row separator. The default is "\n".
2111 ** + Keep track of the line number in p->nLine.
2112 ** + Store the character that terminates the field in p->cTerm. Store
2113 ** EOF on end-of-file.
2114 ** + Report syntax errors on stderr
2115 */
2116 static char *csv_read_one_field(ImportCtx *p){
2117 int c;
2118 int cSep = p->cColSep;
2119 int rSep = p->cRowSep;
2120 p->n = 0;
2121 c = fgetc(p->in);
2122 if( c==EOF || seenInterrupt ){
2123 p->cTerm = EOF;
2124 return 0;
2125 }
2126 if( c=='"' ){
2127 int pc, ppc;
2128 int startLine = p->nLine;
2129 int cQuote = c;
2130 pc = ppc = 0;
2131 while( 1 ){
2132 c = fgetc(p->in);
2133 if( c==rSep ) p->nLine++;
2134 if( c==cQuote ){
2135 if( pc==cQuote ){
2136 pc = 0;
2137 continue;
2138 }
2139 }
2140 if( (c==cSep && pc==cQuote)
2141 || (c==rSep && pc==cQuote)
2142 || (c==rSep && pc=='\r' && ppc==cQuote)
2143 || (c==EOF && pc==cQuote)
2144 ){
2145 do{ p->n--; }while( p->z[p->n]!=cQuote );
2146 p->cTerm = c;
2147 break;
@@ -2077,31 +2151,65 @@
2151 p->zFile, p->nLine, cQuote);
2152 }
2153 if( c==EOF ){
2154 fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
2155 p->zFile, startLine, cQuote);
2156 p->cTerm = c;
2157 break;
2158 }
2159 import_append_char(p, c);
2160 ppc = pc;
2161 pc = c;
2162 }
2163 }else{
2164 while( c!=EOF && c!=cSep && c!=rSep ){
2165 import_append_char(p, c);
2166 c = fgetc(p->in);
2167 }
2168 if( c==rSep ){
2169 p->nLine++;
2170 if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
2171 }
2172 p->cTerm = c;
2173 }
2174 if( p->z ) p->z[p->n] = 0;
2175 return p->z;
2176 }
2177
2178 /* Read a single field of ASCII delimited text.
2179 **
2180 ** + Input comes from p->in.
2181 ** + Store results in p->z of length p->n. Space to hold p->z comes
2182 ** from sqlite3_malloc().
2183 ** + Use p->cSep as the column separator. The default is "\x1F".
2184 ** + Use p->rSep as the row separator. The default is "\x1E".
2185 ** + Keep track of the row number in p->nLine.
2186 ** + Store the character that terminates the field in p->cTerm. Store
2187 ** EOF on end-of-file.
2188 ** + Report syntax errors on stderr
2189 */
2190 static char *ascii_read_one_field(ImportCtx *p){
2191 int c;
2192 int cSep = p->cColSep;
2193 int rSep = p->cRowSep;
2194 p->n = 0;
2195 c = fgetc(p->in);
2196 if( c==EOF || seenInterrupt ){
2197 p->cTerm = EOF;
2198 return 0;
2199 }
2200 while( c!=EOF && c!=cSep && c!=rSep ){
2201 import_append_char(p, c);
2202 c = fgetc(p->in);
2203 }
2204 if( c==rSep ){
2205 p->nLine++;
2206 }
2207 p->cTerm = c;
2208 if( p->z ) p->z[p->n] = 0;
2209 return p->z;
2210 }
2211
2212 /*
2213 ** Try to transfer data for table zTable. If an error is seen while
2214 ** moving forward, try to go backwards. The backwards movement won't
2215 ** work for WITHOUT ROWID tables.
@@ -2653,100 +2761,125 @@
2761 sqlite3_stmt *pStmt = NULL; /* A statement */
2762 int nCol; /* Number of columns in the table */
2763 int nByte; /* Number of bytes in an SQL string */
2764 int i, j; /* Loop counters */
2765 int needCommit; /* True to COMMIT or ROLLBACK at end */
2766 int nSep; /* Number of bytes in p->colSeparator[] */
2767 char *zSql; /* An SQL statement */
2768 ImportCtx sCtx; /* Reader context */
2769 char *(*xRead)(ImportCtx*); /* Procedure to read one value */
2770 int (*xCloser)(FILE*); /* Procedure to close th3 connection */
2771
2772 if( nArg!=3 ){
2773 fprintf(stderr, "Usage: .import FILE TABLE\n");
2774 goto meta_command_exit;
2775 }
2776 zFile = azArg[1];
2777 zTable = azArg[2];
2778 seenInterrupt = 0;
2779 memset(&sCtx, 0, sizeof(sCtx));
2780 open_db(p, 0);
2781 nSep = strlen30(p->colSeparator);
2782 if( nSep==0 ){
2783 fprintf(stderr, "Error: non-null column separator required for import\n");
2784 return 1;
2785 }
2786 if( nSep>1 ){
2787 fprintf(stderr, "Error: multi-character column separators not allowed"
2788 " for import\n");
2789 return 1;
2790 }
2791 nSep = strlen30(p->rowSeparator);
2792 if( nSep==0 ){
2793 fprintf(stderr, "Error: non-null row separator required for import\n");
2794 return 1;
2795 }
2796 if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
2797 /* When importing CSV (only), if the row separator is set to the
2798 ** default output row separator, change it to the default input
2799 ** row separator. This avoids having to maintain different input
2800 ** and output row separators. */
2801 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
2802 nSep = strlen30(p->rowSeparator);
2803 }
2804 if( nSep>1 ){
2805 fprintf(stderr, "Error: multi-character row separators not allowed"
2806 " for import\n");
2807 return 1;
2808 }
2809 sCtx.zFile = zFile;
2810 sCtx.nLine = 1;
2811 if( sCtx.zFile[0]=='|' ){
2812 sCtx.in = popen(sCtx.zFile+1, "r");
2813 sCtx.zFile = "<pipe>";
2814 xCloser = pclose;
2815 }else{
2816 sCtx.in = fopen(sCtx.zFile, "rb");
2817 xCloser = fclose;
2818 }
2819 if( p->mode==MODE_Ascii ){
2820 xRead = ascii_read_one_field;
2821 }else{
2822 xRead = csv_read_one_field;
2823 }
2824 if( sCtx.in==0 ){
2825 fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
2826 return 1;
2827 }
2828 sCtx.cColSep = p->colSeparator[0];
2829 sCtx.cRowSep = p->rowSeparator[0];
2830 zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
2831 if( zSql==0 ){
2832 fprintf(stderr, "Error: out of memory\n");
2833 xCloser(sCtx.in);
2834 return 1;
2835 }
2836 nByte = strlen30(zSql);
2837 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2838 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
2839 if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
2840 char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
2841 char cSep = '(';
2842 while( xRead(&sCtx) ){
2843 zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z);
2844 cSep = ',';
2845 if( sCtx.cTerm!=sCtx.cColSep ) break;
2846 }
2847 if( cSep=='(' ){
2848 sqlite3_free(zCreate);
2849 sqlite3_free(sCtx.z);
2850 xCloser(sCtx.in);
2851 fprintf(stderr,"%s: empty file\n", sCtx.zFile);
2852 return 1;
2853 }
2854 zCreate = sqlite3_mprintf("%z\n)", zCreate);
2855 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
2856 sqlite3_free(zCreate);
2857 if( rc ){
2858 fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
2859 sqlite3_errmsg(db));
2860 sqlite3_free(sCtx.z);
2861 xCloser(sCtx.in);
2862 return 1;
2863 }
2864 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2865 }
2866 sqlite3_free(zSql);
2867 if( rc ){
2868 if (pStmt) sqlite3_finalize(pStmt);
2869 fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
2870 xCloser(sCtx.in);
2871 return 1;
2872 }
2873 nCol = sqlite3_column_count(pStmt);
2874 sqlite3_finalize(pStmt);
2875 pStmt = 0;
2876 if( nCol==0 ) return 0; /* no columns, no error */
2877 zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
2878 if( zSql==0 ){
2879 fprintf(stderr, "Error: out of memory\n");
2880 xCloser(sCtx.in);
2881 return 1;
2882 }
2883 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
2884 j = strlen30(zSql);
2885 for(i=1; i<nCol; i++){
@@ -2758,50 +2891,60 @@
2891 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2892 sqlite3_free(zSql);
2893 if( rc ){
2894 fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
2895 if (pStmt) sqlite3_finalize(pStmt);
2896 xCloser(sCtx.in);
2897 return 1;
2898 }
2899 needCommit = sqlite3_get_autocommit(db);
2900 if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
2901 do{
2902 int startLine = sCtx.nLine;
2903 for(i=0; i<nCol; i++){
2904 char *z = xRead(&sCtx);
2905 /*
2906 ** Did we reach end-of-file before finding any columns?
2907 ** If so, stop instead of NULL filling the remaining columns.
2908 */
2909 if( z==0 && i==0 ) break;
2910 /*
2911 ** Did we reach end-of-file OR end-of-line before finding any
2912 ** columns in ASCII mode? If so, stop instead of NULL filling
2913 ** the remaining columns.
2914 */
2915 if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
2916 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
2917 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
2918 fprintf(stderr, "%s:%d: expected %d columns but found %d - "
2919 "filling the rest with NULL\n",
2920 sCtx.zFile, startLine, nCol, i+1);
2921 i++;
2922 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
2923 }
2924 }
2925 if( sCtx.cTerm==sCtx.cColSep ){
2926 do{
2927 xRead(&sCtx);
2928 i++;
2929 }while( sCtx.cTerm==sCtx.cColSep );
2930 fprintf(stderr, "%s:%d: expected %d columns but found %d - "
2931 "extras ignored\n",
2932 sCtx.zFile, startLine, nCol, i);
2933 }
2934 if( i>=nCol ){
2935 sqlite3_step(pStmt);
2936 rc = sqlite3_reset(pStmt);
2937 if( rc!=SQLITE_OK ){
2938 fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
2939 sqlite3_errmsg(db));
2940 }
2941 }
2942 }while( sCtx.cTerm!=EOF );
2943
2944 xCloser(sCtx.in);
2945 sqlite3_free(sCtx.z);
2946 sqlite3_finalize(pStmt);
2947 if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
2948 }else
2949
2950 if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
@@ -2915,32 +3058,36 @@
3058 p->mode = MODE_List;
3059 }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
3060 p->mode = MODE_Html;
3061 }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
3062 p->mode = MODE_Tcl;
3063 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
3064 }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
3065 p->mode = MODE_Csv;
3066 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
3067 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
3068 }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
3069 p->mode = MODE_List;
3070 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
3071 }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
3072 p->mode = MODE_Insert;
3073 set_table_name(p, nArg>=3 ? azArg[2] : "table");
3074 }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
3075 p->mode = MODE_Ascii;
3076 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
3077 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
3078 }else {
3079 fprintf(stderr,"Error: mode should be one of: "
3080 "ascii column csv html insert line list tabs tcl\n");
3081 rc = 1;
3082 }
3083 }else
3084
3085 if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
3086 if( nArg==2 ){
3087 sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
3088 "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
3089 }else{
3090 fprintf(stderr, "Usage: .nullvalue STRING\n");
3091 rc = 1;
3092 }
3093 }else
@@ -3191,11 +3338,11 @@
3338
3339
3340 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
3341 if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
3342 extern int sqlite3SelectTrace;
3343 sqlite3SelectTrace = integerValue(azArg[1]);
3344 }else
3345 #endif
3346
3347
3348 #ifdef SQLITE_DEBUG
@@ -3221,18 +3368,20 @@
3368 }else
3369 #endif
3370
3371 if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
3372 if( nArg<2 || nArg>3 ){
3373 fprintf(stderr, "Usage: .separator COL ?ROW?\n");
3374 rc = 1;
3375 }
3376 if( nArg>=2 ){
3377 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
3378 "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
3379 }
3380 if( nArg>=3 ){
3381 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
3382 "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
3383 }
3384 }else
3385
3386 if( c=='s'
3387 && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
@@ -3259,27 +3408,28 @@
3408 if( nArg!=1 ){
3409 fprintf(stderr, "Usage: .show\n");
3410 rc = 1;
3411 goto meta_command_exit;
3412 }
3413 fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
3414 fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
3415 fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
3416 fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
3417 fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
3418 fprintf(p->out,"%12.12s: ", "nullvalue");
3419 output_c_string(p->out, p->nullValue);
3420 fprintf(p->out, "\n");
3421 fprintf(p->out,"%12.12s: %s\n","output",
3422 strlen30(p->outfile) ? p->outfile : "stdout");
3423 fprintf(p->out,"%12.12s: ", "colseparator");
3424 output_c_string(p->out, p->colSeparator);
3425 fprintf(p->out, "\n");
3426 fprintf(p->out,"%12.12s: ", "rowseparator");
3427 output_c_string(p->out, p->rowSeparator);
3428 fprintf(p->out, "\n");
3429 fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
3430 fprintf(p->out,"%12.12s: ","width");
3431 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
3432 fprintf(p->out,"%d ",p->colWidth[i]);
3433 }
3434 fprintf(p->out,"\n");
3435 }else
@@ -3394,10 +3544,11 @@
3544 { "reserve", SQLITE_TESTCTRL_RESERVE },
3545 { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
3546 { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
3547 { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
3548 { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
3549 { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
3550 };
3551 int testctrl = -1;
3552 int rc = 0;
3553 int i, n;
3554 open_db(p, 0);
@@ -3460,11 +3611,12 @@
3611 }
3612 break;
3613
3614 /* sqlite3_test_control(int, int) */
3615 case SQLITE_TESTCTRL_ASSERT:
3616 case SQLITE_TESTCTRL_ALWAYS:
3617 case SQLITE_TESTCTRL_NEVER_CORRUPT:
3618 if( nArg==3 ){
3619 int opt = booleanValue(azArg[2]);
3620 rc = sqlite3_test_control(testctrl, opt);
3621 fprintf(p->out, "%d (0x%08x)\n", rc, rc);
3622 } else {
@@ -3936,10 +4088,11 @@
4088
4089 /*
4090 ** Show available command line options
4091 */
4092 static const char zOptions[] =
4093 " -ascii set output mode to 'ascii'\n"
4094 " -bail stop after hitting an error\n"
4095 " -batch force batch I/O\n"
4096 " -column set output mode to 'column'\n"
4097 " -cmd COMMAND run \"COMMAND\" before reading stdin\n"
4098 " -csv set output mode to 'csv'\n"
@@ -3957,15 +4110,15 @@
4110 " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
4111 " -mmap N default mmap size set to N\n"
4112 #ifdef SQLITE_ENABLE_MULTIPLEX
4113 " -multiplex enable the multiplexor VFS\n"
4114 #endif
4115 " -newline SEP set output row separator. Default: '\\n'\n"
4116 " -nullvalue TEXT set text string for NULL values. Default ''\n"
4117 " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
4118 " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
4119 " -separator SEP set output column separator. Default: '|'\n"
4120 " -stats print memory stats before each finalize\n"
4121 " -version show SQLite version\n"
4122 " -vfs NAME use NAME as the default VFS\n"
4123 #ifdef SQLITE_ENABLE_VFSTRACE
4124 " -vfstrace enable tracing of all VFS calls\n"
@@ -3988,12 +4141,12 @@
4141 ** Initialize the state information in data
4142 */
4143 static void main_init(ShellState *data) {
4144 memset(data, 0, sizeof(*data));
4145 data->mode = MODE_List;
4146 memcpy(data->colSeparator,SEP_Column, 2);
4147 memcpy(data->rowSeparator,SEP_Row, 2);
4148 data->showHeader = 0;
4149 data->shellFlgs = SHFLG_Lookaside;
4150 sqlite3_config(SQLITE_CONFIG_URI, 1);
4151 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
4152 sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -4050,10 +4203,12 @@
4203 fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
4204 sqlite3_sourceid(), SQLITE_SOURCE_ID);
4205 exit(1);
4206 }
4207 #endif
4208 setBinaryMode(stdin);
4209 setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
4210 Argv0 = argv[0];
4211 main_init(&data);
4212 stdin_is_interactive = isatty(0);
4213
4214 /* Make sure we have a valid signal handler early, before anything
@@ -4228,19 +4383,25 @@
4383 data.mode = MODE_Line;
4384 }else if( strcmp(z,"-column")==0 ){
4385 data.mode = MODE_Column;
4386 }else if( strcmp(z,"-csv")==0 ){
4387 data.mode = MODE_Csv;
4388 memcpy(data.colSeparator,",",2);
4389 }else if( strcmp(z,"-ascii")==0 ){
4390 data.mode = MODE_Ascii;
4391 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
4392 SEP_Unit);
4393 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
4394 SEP_Record);
4395 }else if( strcmp(z,"-separator")==0 ){
4396 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
4397 "%s",cmdline_option_value(argc,argv,++i));
4398 }else if( strcmp(z,"-newline")==0 ){
4399 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
4400 "%s",cmdline_option_value(argc,argv,++i));
4401 }else if( strcmp(z,"-nullvalue")==0 ){
4402 sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
4403 "%s",cmdline_option_value(argc,argv,++i));
4404 }else if( strcmp(z,"-header")==0 ){
4405 data.showHeader = 1;
4406 }else if( strcmp(z,"-noheader")==0 ){
4407 data.showHeader = 0;
@@ -4356,11 +4517,11 @@
4517 nHistory = strlen30(zHome) + 20;
4518 if( (zHistory = malloc(nHistory))!=0 ){
4519 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
4520 }
4521 }
4522 #if HAVE_READLINE
4523 if( zHistory ) read_history(zHistory);
4524 #endif
4525 rc = process_input(&data, 0);
4526 if( zHistory ){
4527 stifle_history(100);
4528
--- src/sitemap.c
+++ src/sitemap.c
@@ -27,10 +27,11 @@
2727
** Show an incomplete list of web pages offered by the Fossil web engine.
2828
*/
2929
void sitemap_page(void){
3030
login_check_credentials();
3131
style_header("Site Map");
32
+ style_adunit_config(ADUNIT_RIGHT_OK);
3233
@ <p>
3334
@ The following links are just a few of the many web-pages available for
3435
@ this Fossil repository:
3536
@ </p>
3637
@
3738
--- src/sitemap.c
+++ src/sitemap.c
@@ -27,10 +27,11 @@
27 ** Show an incomplete list of web pages offered by the Fossil web engine.
28 */
29 void sitemap_page(void){
30 login_check_credentials();
31 style_header("Site Map");
 
32 @ <p>
33 @ The following links are just a few of the many web-pages available for
34 @ this Fossil repository:
35 @ </p>
36 @
37
--- src/sitemap.c
+++ src/sitemap.c
@@ -27,10 +27,11 @@
27 ** Show an incomplete list of web pages offered by the Fossil web engine.
28 */
29 void sitemap_page(void){
30 login_check_credentials();
31 style_header("Site Map");
32 style_adunit_config(ADUNIT_RIGHT_OK);
33 @ <p>
34 @ The following links are just a few of the many web-pages available for
35 @ this Fossil repository:
36 @ </p>
37 @
38
+196 -1310
--- src/skins.c
+++ src/skins.c
@@ -19,1255 +19,38 @@
1919
*/
2020
#include "config.h"
2121
#include <assert.h>
2222
#include "skins.h"
2323
24
-/* @-comment: ## */
25
-/*
26
-** A black-and-white theme with the project title in a bar across the top
27
-** and no logo image.
28
-*/
29
-static const char zBuiltinSkin1[] =
30
-@ REPLACE INTO config(name,mtime,value)
31
-@ VALUES('css',now(),'/* General settings for the entire page */
32
-@ body {
33
-@ margin: 0ex 1ex;
34
-@ padding: 0px;
35
-@ background-color: white;
36
-@ font-family: sans-serif;
37
-@ }
38
-@
39
-@ /* The project logo in the upper left-hand corner of each page */
40
-@ div.logo {
41
-@ display: table-row;
42
-@ text-align: center;
43
-@ /* vertical-align: bottom;*/
44
-@ font-size: 2em;
45
-@ font-weight: bold;
46
-@ background-color: #707070;
47
-@ color: #ffffff;
48
-@ min-width: 200px;
49
-@ white-space: nowrap;
50
-@ }
51
-@
52
-@ /* The page title centered at the top of each page */
53
-@ div.title {
54
-@ display: table-cell;
55
-@ font-size: 1.5em;
56
-@ font-weight: bold;
57
-@ text-align: center;
58
-@ padding: 0 0 0 10px;
59
-@ color: #404040;
60
-@ vertical-align: bottom;
61
-@ width: 100%;
62
-@ }
63
-@
64
-@ /* The login status message in the top right-hand corner */
65
-@ div.status {
66
-@ display: table-cell;
67
-@ text-align: right;
68
-@ vertical-align: bottom;
69
-@ color: #404040;
70
-@ font-size: 0.8em;
71
-@ font-weight: bold;
72
-@ min-width: 200px;
73
-@ white-space: nowrap;
74
-@ }
75
-@
76
-@ /* The header across the top of the page */
77
-@ div.header {
78
-@ display: table;
79
-@ width: 100%;
80
-@ }
81
-@
82
-@ /* The main menu bar that appears at the top of the page beneath
83
-@ ** the header */
84
-@ div.mainmenu {
85
-@ padding: 5px 10px 5px 10px;
86
-@ font-size: 0.9em;
87
-@ font-weight: bold;
88
-@ text-align: center;
89
-@ letter-spacing: 1px;
90
-@ background-color: #404040;
91
-@ color: white;
92
-@ }
93
-@
94
-@ /* The submenu bar that *sometimes* appears below the main menu */
95
-@ div.submenu, div.sectionmenu {
96
-@ padding: 3px 10px 3px 0px;
97
-@ font-size: 0.9em;
98
-@ text-align: center;
99
-@ background-color: #606060;
100
-@ color: white;
101
-@ }
102
-@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
103
-@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
104
-@ padding: 3px 10px 3px 10px;
105
-@ color: white;
106
-@ text-decoration: none;
107
-@ }
108
-@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
109
-@ color: #404040;
110
-@ background-color: white;
111
-@ }
112
-@
113
-@ /* All page content from the bottom of the menu or submenu down to
114
-@ ** the footer */
115
-@ div.content {
116
-@ padding: 0ex 0ex 0ex 0ex;
117
-@ }
118
-@ /* Hyperlink colors */
119
-@ div.content a { color: #604000; }
120
-@ div.content a:link { color: #604000;}
121
-@ div.content a:visited { color: #600000; }
122
-@
123
-@ /* <verbatim> blocks */
124
-@ pre.verbatim {
125
-@ background-color: #ffffff;
126
-@ padding: 0.5em;
127
-@ white-space: pre-wrap;
128
-@ }
129
-@
130
-@ /* Some pages have section dividers */
131
-@ div.section {
132
-@ margin-bottom: 0px;
133
-@ margin-top: 1em;
134
-@ padding: 1px 1px 1px 1px;
135
-@ font-size: 1.2em;
136
-@ font-weight: bold;
137
-@ background-color: #404040;
138
-@ color: white;
139
-@ white-space: nowrap;
140
-@ }
141
-@
142
-@ /* The "Date" that occurs on the left hand side of timelines */
143
-@ div.divider {
144
-@ background: #a0a0a0;
145
-@ border: 2px #505050 solid;
146
-@ font-size: 1em; font-weight: normal;
147
-@ padding: .25em;
148
-@ margin: .2em 0 .2em 0;
149
-@ float: left;
150
-@ clear: left;
151
-@ white-space: nowrap;
152
-@ }
153
-@
154
-@ /* The footer at the very bottom of the page */
155
-@ div.footer {
156
-@ font-size: 0.8em;
157
-@ margin-top: 12px;
158
-@ padding: 5px 10px 5px 10px;
159
-@ text-align: right;
160
-@ background-color: #404040;
161
-@ color: white;
162
-@ }
163
-@
164
-@ /* The label/value pairs on (for example) the vinfo page */
165
-@ table.label-value th {
166
-@ vertical-align: top;
167
-@ text-align: right;
168
-@ padding: 0.2ex 2ex;
169
-@ }');
170
-@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
171
-@ <head>
172
-@ <base href="$baseurl/$current_page" />
173
-@ <title>$<project_name>: $<title></title>
174
-@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
175
-@ href="$home/timeline.rss">
176
-@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
177
-@ media="screen">
178
-@ </head>
179
-@ <body>
180
-@ <div class="header">
181
-@ <div class="title"><small>$<project_name></small><br />$<title></div>
182
-@ <div class="status"><th1>
183
-@ if {[info exists login]} {
184
-@ puts "Logged in as $login"
185
-@ } else {
186
-@ puts "Not logged in"
187
-@ }
188
-@ </th1></div>
189
-@ </div>
190
-@ <div class="mainmenu">
191
-@ <th1>
192
-@ html "<a href=''$home$index_page''>Home</a>\n"
193
-@ if {[anycap jor]} {
194
-@ html "<a href=''$home/timeline''>Timeline</a>\n"
195
-@ }
196
-@ if {[hascap oh]} {
197
-@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
198
-@ }
199
-@ if {[hascap o]} {
200
-@ html "<a href=''$home/brlist''>Branches</a>\n"
201
-@ html "<a href=''$home/taglist''>Tags</a>\n"
202
-@ }
203
-@ if {[hascap r]} {
204
-@ html "<a href=''$home/reportlist''>Tickets</a>\n"
205
-@ }
206
-@ if {[hascap j]} {
207
-@ html "<a href=''$home/wiki''>Wiki</a>\n"
208
-@ }
209
-@ if {[hascap s]} {
210
-@ html "<a href=''$home/setup''>Admin</a>\n"
211
-@ } elseif {[hascap a]} {
212
-@ html "<a href=''$home/setup_ulist''>Users</a>\n"
213
-@ }
214
-@ if {[info exists login]} {
215
-@ html "<a href=''$home/login''>Logout</a>\n"
216
-@ } else {
217
-@ html "<a href=''$home/login''>Login</a>\n"
218
-@ }
219
-@ </th1></div>
220
-@ ');
221
-@ REPLACE INTO config(name,mtime,value)
222
-@ VALUES('footer',now(),'<div class="footer">
223
-@ Fossil version $manifest_version $manifest_date
224
-@ </div>
225
-@ </body></html>
226
-@ ');
227
-;
228
-
229
-/*
230
-** A tan theme with the project title above the user identification
231
-** and no logo image.
232
-*/
233
-static const char zBuiltinSkin2[] =
234
-@ REPLACE INTO config(name,mtime,value)
235
-@ VALUES('css',now(),'/* General settings for the entire page */
236
-@ body {
237
-@ margin: 0ex 0ex;
238
-@ padding: 0px;
239
-@ background-color: #fef3bc;
240
-@ font-family: sans-serif;
241
-@ }
242
-@
243
-@ /* The project logo in the upper left-hand corner of each page */
244
-@ div.logo {
245
-@ display: inline;
246
-@ text-align: center;
247
-@ vertical-align: bottom;
248
-@ font-weight: bold;
249
-@ font-size: 2.5em;
250
-@ color: #a09048;
251
-@ white-space: nowrap;
252
-@ }
253
-@
254
-@ /* The page title centered at the top of each page */
255
-@ div.title {
256
-@ display: table-cell;
257
-@ font-size: 2em;
258
-@ font-weight: bold;
259
-@ text-align: left;
260
-@ padding: 0 0 0 5px;
261
-@ color: #a09048;
262
-@ vertical-align: bottom;
263
-@ width: 100%;
264
-@ }
265
-@
266
-@ /* The login status message in the top right-hand corner */
267
-@ div.status {
268
-@ display: table-cell;
269
-@ text-align: right;
270
-@ vertical-align: bottom;
271
-@ color: #a09048;
272
-@ padding: 5px 5px 0 0;
273
-@ font-size: 0.8em;
274
-@ font-weight: bold;
275
-@ white-space: nowrap;
276
-@ }
277
-@
278
-@ /* The header across the top of the page */
279
-@ div.header {
280
-@ display: table;
281
-@ width: 100%;
282
-@ }
283
-@
284
-@ /* The main menu bar that appears at the top of the page beneath
285
-@ ** the header */
286
-@ div.mainmenu {
287
-@ padding: 5px 10px 5px 10px;
288
-@ font-size: 0.9em;
289
-@ font-weight: bold;
290
-@ text-align: center;
291
-@ letter-spacing: 1px;
292
-@ background-color: #a09048;
293
-@ color: black;
294
-@ }
295
-@
296
-@ /* The submenu bar that *sometimes* appears below the main menu */
297
-@ div.submenu, div.sectionmenu {
298
-@ padding: 3px 10px 3px 0px;
299
-@ font-size: 0.9em;
300
-@ text-align: center;
301
-@ background-color: #c0af58;
302
-@ color: white;
303
-@ }
304
-@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
305
-@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
306
-@ padding: 3px 10px 3px 10px;
307
-@ color: white;
308
-@ text-decoration: none;
309
-@ }
310
-@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
311
-@ color: #a09048;
312
-@ background-color: white;
313
-@ }
314
-@
315
-@ /* All page content from the bottom of the menu or submenu down to
316
-@ ** the footer */
317
-@ div.content {
318
-@ padding: 1ex 5px;
319
-@ }
320
-@ div.content a { color: #706532; }
321
-@ div.content a:link { color: #706532; }
322
-@ div.content a:visited { color: #704032; }
323
-@ div.content a:hover { background-color: white; color: #706532; }
324
-@
325
-@ /* Some pages have section dividers */
326
-@ div.section {
327
-@ margin-bottom: 0px;
328
-@ margin-top: 1em;
329
-@ padding: 3px 3px 0 3px;
330
-@ font-size: 1.2em;
331
-@ font-weight: bold;
332
-@ background-color: #a09048;
333
-@ color: white;
334
-@ white-space: nowrap;
335
-@ }
336
-@
337
-@ /* The "Date" that occurs on the left hand side of timelines */
338
-@ div.divider {
339
-@ background: #e1d498;
340
-@ border: 2px #a09048 solid;
341
-@ font-size: 1em; font-weight: normal;
342
-@ padding: .25em;
343
-@ margin: .2em 0 .2em 0;
344
-@ float: left;
345
-@ clear: left;
346
-@ white-space: nowrap;
347
-@ }
348
-@
349
-@ /* The footer at the very bottom of the page */
350
-@ div.footer {
351
-@ font-size: 0.8em;
352
-@ margin-top: 12px;
353
-@ padding: 5px 10px 5px 10px;
354
-@ text-align: right;
355
-@ background-color: #a09048;
356
-@ color: white;
357
-@ }
358
-@
359
-@ /* Hyperlink colors */
360
-@ div.footer a { color: white; }
361
-@ div.footer a:link { color: white; }
362
-@ div.footer a:visited { color: white; }
363
-@ div.footer a:hover { background-color: white; color: #558195; }
364
-@
365
-@ /* <verbatim> blocks */
366
-@ pre.verbatim {
367
-@ background-color: #f5f5f5;
368
-@ padding: 0.5em;
369
-@ white-space: pre-wrap;
370
-@ }
371
-@
372
-@ /* The label/value pairs on (for example) the ci page */
373
-@ table.label-value th {
374
-@ vertical-align: top;
375
-@ text-align: right;
376
-@ padding: 0.2ex 2ex;
377
-@ }');
378
-@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
379
-@ <head>
380
-@ <base href="$baseurl/$current_page" />
381
-@ <title>$<project_name>: $<title></title>
382
-@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
383
-@ href="$home/timeline.rss">
384
-@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
385
-@ media="screen">
386
-@ </head>
387
-@ <body>
388
-@ <div class="header">
389
-@ <div class="title">$<title></div>
390
-@ <div class="status">
391
-@ <div class="logo">$<project_name></div><br/>
392
-@ <th1>
393
-@ if {[info exists login]} {
394
-@ puts "Logged in as $login"
395
-@ } else {
396
-@ puts "Not logged in"
397
-@ }
398
-@ </th1></div>
399
-@ </div>
400
-@ <div class="mainmenu">
401
-@ <th1>
402
-@ html "<a href=''$home$index_page''>Home</a>\n"
403
-@ if {[anycap jor]} {
404
-@ html "<a href=''$home/timeline''>Timeline</a>\n"
405
-@ }
406
-@ if {[hascap oh]} {
407
-@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
408
-@ }
409
-@ if {[hascap o]} {
410
-@ html "<a href=''$home/brlist''>Branches</a>\n"
411
-@ html "<a href=''$home/taglist''>Tags</a>\n"
412
-@ }
413
-@ if {[hascap r]} {
414
-@ html "<a href=''$home/reportlist''>Tickets</a>\n"
415
-@ }
416
-@ if {[hascap j]} {
417
-@ html "<a href=''$home/wiki''>Wiki</a>\n"
418
-@ }
419
-@ if {[hascap s]} {
420
-@ html "<a href=''$home/setup''>Admin</a>\n"
421
-@ } elseif {[hascap a]} {
422
-@ html "<a href=''$home/setup_ulist''>Users</a>\n"
423
-@ }
424
-@ if {[info exists login]} {
425
-@ html "<a href=''$home/login''>Logout</a>\n"
426
-@ } else {
427
-@ html "<a href=''$home/login''>Login</a>\n"
428
-@ }
429
-@ </th1></div>
430
-@ ');
431
-@ REPLACE INTO config(name,mtime,value)
432
-@ VALUES('footer',now(),'<div class="footer">
433
-@ Fossil version $manifest_version $manifest_date
434
-@ </div>
435
-@ </body></html>
436
-@ ');
437
-;
438
-
439
-/*
440
-** Black letters on a white or cream background with the main menu
441
-** stuck on the left-hand side.
442
-*/
443
-static const char zBuiltinSkin3[] =
444
-@ REPLACE INTO config(name,mtime,value)
445
-@ VALUES('css',now(),'/* General settings for the entire page */
446
-@ body {
447
-@ margin:0px 0px 0px 0px;
448
-@ padding:0px;
449
-@ font-family:verdana, arial, helvetica, "sans serif";
450
-@ color:#333;
451
-@ background-color:white;
452
-@ }
453
-@
454
-@ /* consistent colours */
455
-@ h2 {
456
-@ color: #333;
457
-@ }
458
-@ h3 {
459
-@ color: #333;
460
-@ }
461
-@
462
-@ /* The project logo in the upper left-hand corner of each page */
463
-@ div.logo {
464
-@ display: table-cell;
465
-@ text-align: left;
466
-@ vertical-align: bottom;
467
-@ font-weight: bold;
468
-@ color: #333;
469
-@ white-space: nowrap;
470
-@ }
471
-@
472
-@ /* The page title centered at the top of each page */
473
-@ div.title {
474
-@ display: table-cell;
475
-@ font-size: 2em;
476
-@ font-weight: bold;
477
-@ text-align: center;
478
-@ color: #333;
479
-@ vertical-align: bottom;
480
-@ width: 100%;
481
-@ }
482
-@
483
-@ /* The login status message in the top right-hand corner */
484
-@ div.status {
485
-@ display: table-cell;
486
-@ padding-right: 10px;
487
-@ text-align: right;
488
-@ vertical-align: bottom;
489
-@ padding-bottom: 5px;
490
-@ color: #333;
491
-@ font-size: 0.8em;
492
-@ font-weight: bold;
493
-@ white-space: nowrap;
494
-@ }
495
-@
496
-@ /* The header across the top of the page */
497
-@ div.header {
498
-@ margin:10px 0px 10px 0px;
499
-@ padding:1px 0px 0px 20px;
500
-@ border-style:solid;
501
-@ border-color:black;
502
-@ border-width:1px 0px;
503
-@ background-color:#eee;
504
-@ }
505
-@
506
-@ /* The main menu bar that appears at the top left of the page beneath
507
-@ ** the header. Width must be co-ordinated with the container below */
508
-@ div.mainmenu {
509
-@ float: left;
510
-@ margin-left: 10px;
511
-@ margin-right: 10px;
512
-@ font-size: 0.9em;
513
-@ font-weight: bold;
514
-@ padding:5px;
515
-@ background-color:#eee;
516
-@ border:1px solid #999;
517
-@ width:8em;
518
-@ }
519
-@
520
-@ /* Main menu is now a list */
521
-@ div.mainmenu ul {
522
-@ padding: 0;
523
-@ list-style:none;
524
-@ }
525
-@ div.mainmenu a, div.mainmenu a:visited{
526
-@ padding: 1px 10px 1px 10px;
527
-@ color: #333;
528
-@ text-decoration: none;
529
-@ }
530
-@ div.mainmenu a:hover {
531
-@ color: #eee;
532
-@ background-color: #333;
533
-@ }
534
-@
535
-@ /* Container for the sub-menu and content so they don''t spread
536
-@ ** out underneath the main menu */
537
-@ #container {
538
-@ padding-left: 9em;
539
-@ }
540
-@
541
-@ /* The submenu bar that *sometimes* appears below the main menu */
542
-@ div.submenu, div.sectionmenu {
543
-@ padding: 3px 10px 3px 10px;
544
-@ font-size: 0.9em;
545
-@ text-align: center;
546
-@ border:1px solid #999;
547
-@ border-width:1px 0px;
548
-@ background-color: #eee;
549
-@ color: #333;
550
-@ }
551
-@ div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link,
552
-@ div.sectionmenu>a.button:visited {
553
-@ padding: 3px 10px 3px 10px;
554
-@ color: #333;
555
-@ text-decoration: none;
556
-@ }
557
-@ div.submenu a:hover, div.sectionmenu>a.button:hover {
558
-@ color: #eee;
559
-@ background-color: #333;
560
-@ }
561
-@
562
-@ /* All page content from the bottom of the menu or submenu down to
563
-@ ** the footer */
564
-@ div.content {
565
-@ padding: 2ex 1ex 0ex 2ex;
566
-@ }
567
-@
568
-@ /* Some pages have section dividers */
569
-@ div.section {
570
-@ margin-bottom: 0px;
571
-@ margin-top: 1em;
572
-@ padding: 1px 1px 1px 1px;
573
-@ font-size: 1.2em;
574
-@ font-weight: bold;
575
-@ border-style:solid;
576
-@ border-color:#999;
577
-@ border-width:1px 0px;
578
-@ background-color: #eee;
579
-@ color: #333;
580
-@ white-space: nowrap;
581
-@ }
582
-@
583
-@ /* The "Date" that occurs on the left hand side of timelines */
584
-@ div.divider {
585
-@ background: #eee;
586
-@ border: 2px #999 solid;
587
-@ font-size: 1em; font-weight: normal;
588
-@ padding: .25em;
589
-@ margin: .2em 0 .2em 0;
590
-@ float: left;
591
-@ clear: left;
592
-@ color: #333;
593
-@ white-space: nowrap;
594
-@ }
595
-@
596
-@ /* The footer at the very bottom of the page */
597
-@ div.footer {
598
-@ font-size: 0.8em;
599
-@ margin-top: 12px;
600
-@ padding: 5px 10px 5px 10px;
601
-@ text-align: right;
602
-@ background-color: #eee;
603
-@ color: #555;
604
-@ }
605
-@
606
-@ /* <verbatim> blocks */
607
-@ pre.verbatim {
608
-@ background-color: #f5f5f5;
609
-@ padding: 0.5em;
610
-@ white-space: pre-wrap;
611
-@ }
612
-@
613
-@ /* The label/value pairs on (for example) the ci page */
614
-@ table.label-value th {
615
-@ vertical-align: top;
616
-@ text-align: right;
617
-@ padding: 0.2ex 2ex;
618
-@ }');
619
-@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
620
-@ <head>
621
-@ <base href="$baseurl/$current_page" />
622
-@ <title>$<project_name>: $<title></title>
623
-@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
624
-@ href="$home/timeline.rss">
625
-@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
626
-@ media="screen">
627
-@ </head>
628
-@ <body>
629
-@ <div class="header">
630
-@ <div class="logo">
631
-@ <img src="$logo_image_url" alt="logo">
632
-@ <br />$<project_name>
633
-@ </div>
634
-@ <div class="title">$<title></div>
635
-@ <div class="status"><th1>
636
-@ if {[info exists login]} {
637
-@ puts "Logged in as $login"
638
-@ } else {
639
-@ puts "Not logged in"
640
-@ }
641
-@ </th1></div>
642
-@ </div>
643
-@ <div class="mainmenu">
644
-@ <th1>
645
-@ html "<a href=''$home$index_page''>Home</a>\n"
646
-@ if {[anycap jor]} {
647
-@ html "<a href=''$home/timeline''>Timeline</a>\n"
648
-@ }
649
-@ if {[hascap oh]} {
650
-@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
651
-@ }
652
-@ if {[hascap o]} {
653
-@ html "<a href=''$home/brlist''>Branches</a>\n"
654
-@ html "<a href=''$home/taglist''>Tags</a>\n"
655
-@ }
656
-@ if {[hascap r]} {
657
-@ html "<a href=''$home/reportlist''>Tickets</a>\n"
658
-@ }
659
-@ if {[hascap j]} {
660
-@ html "<a href=''$home/wiki''>Wiki</a>\n"
661
-@ }
662
-@ if {[hascap s]} {
663
-@ html "<a href=''$home/setup''>Admin</a>\n"
664
-@ } elseif {[hascap a]} {
665
-@ html "<a href=''$home/setup_ulist''>Users</a>\n"
666
-@ }
667
-@ if {[info exists login]} {
668
-@ html "<a href=''$home/login''>Logout</a>\n"
669
-@ } else {
670
-@ html "<a href=''$home/login''>Login</a>\n"
671
-@ }
672
-@ </th1></ul></div>
673
-@ <div id="container">
674
-@ ');
675
-@ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div>
676
-@ <div class="footer">
677
-@ Fossil version $manifest_version $manifest_date
678
-@ </div>
679
-@ </body></html>
680
-@ ');
681
-;
682
-
683
-
684
-/*
685
-** Shadow boxes and rounded corners.
686
-*/
687
-static const char zBuiltinSkin4[] =
688
-@ REPLACE INTO config(name,mtime,value)
689
-@ VALUES('css',now(),'/* General settings for the entire page */
690
-@ html {
691
-@ min-height: 100%;
692
-@ }
693
-@ body {
694
-@ margin: 0ex 1ex;
695
-@ padding: 0px;
696
-@ background-color: white;
697
-@ color: #333;
698
-@ font-family: Verdana, sans-serif;
699
-@ font-size: 0.8em;
700
-@ }
701
-@
702
-@ /* The project logo in the upper left-hand corner of each page */
703
-@ div.logo {
704
-@ display: table-cell;
705
-@ text-align: right;
706
-@ vertical-align: bottom;
707
-@ font-weight: normal;
708
-@ white-space: nowrap;
709
-@ }
710
-@
711
-@ /* Widths */
712
-@ div.header, div.mainmenu, div.submenu, div.content, div.footer {
713
-@ max-width: 900px;
714
-@ margin: auto;
715
-@ padding: 3px 20px 3px 20px;
716
-@ clear: both;
717
-@ }
718
-@
719
-@ /* The page title at the top of each page */
720
-@ div.title {
721
-@ display: table-cell;
722
-@ padding-left: 10px;
723
-@ font-size: 2em;
724
-@ margin: 10px 0 10px -20px;
725
-@ vertical-align: bottom;
726
-@ text-align: left;
727
-@ width: 80%;
728
-@ font-family: Verdana, sans-serif;
729
-@ font-weight: bold;
730
-@ color: #558195;
731
-@ text-shadow: 0px 2px 2px #999999;
732
-@ }
733
-@
734
-@ /* The login status message in the top right-hand corner */
735
-@ div.status {
736
-@ display: table-cell;
737
-@ text-align: right;
738
-@ vertical-align: bottom;
739
-@ color: #333;
740
-@ margin-right: -20px;
741
-@ white-space: nowrap;
742
-@ }
743
-@
744
-@ /* The main menu bar that appears at the top of the page beneath
745
-@ ** the header */
746
-@ div.mainmenu {
747
-@ text-align: center;
748
-@ color: white;
749
-@ border-top-left-radius: 5px;
750
-@ border-top-right-radius: 5px;
751
-@ vertical-align: middle;
752
-@ padding-top: 8px;
753
-@ padding-bottom: 8px;
754
-@ background-color: #446979;
755
-@ box-shadow: 0px 3px 4px #333333;
756
-@ }
757
-@
758
-@ /* The submenu bar that *sometimes* appears below the main menu */
759
-@ div.submenu {
760
-@ padding-top:10px;
761
-@ padding-bottom:0;
762
-@ text-align: right;
763
-@ color: #000;
764
-@ background-color: #fff;
765
-@ height: 1.5em;
766
-@ vertical-align:middle;
767
-@ box-shadow: 0px 3px 4px #999;
768
-@ }
769
-@ div.mainmenu a, div.mainmenu a:visited {
770
-@ padding: 3px 10px 3px 10px;
771
-@ color: white;
772
-@ text-decoration: none;
773
-@ }
774
-@ div.submenu a, div.submenu a:visited, a.button,
775
-@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
776
-@ padding: 2px 8px;
777
-@ color: #000;
778
-@ font-family: Arial;
779
-@ text-decoration: none;
780
-@ margin:auto;
781
-@ border-radius: 5px;
782
-@ background-color: #e0e0e0;
783
-@ text-shadow: 0px -1px 0px #eee;
784
-@ border: 1px solid #000;
785
-@ }
786
-@
787
-@ div.mainmenu a:hover {
788
-@ color: #000;
789
-@ background-color: white;
790
-@ }
791
-@
792
-@ div.submenu a:hover, div.sectionmenu>a.button:hover {
793
-@ background-color: #c0c0c0;
794
-@ }
795
-@
796
-@ /* All page content from the bottom of the menu or submenu down to
797
-@ ** the footer */
798
-@ div.content {
799
-@ background-color: #fff;
800
-@ box-shadow: 0px 3px 4px #999;
801
-@ border-bottom-right-radius: 5px;
802
-@ border-bottom-left-radius: 5px;
803
-@ padding-bottom: 1em;
804
-@ min-height:40%;
805
-@ }
806
-@
807
-@
808
-@ /* Some pages have section dividers */
809
-@ div.section {
810
-@ margin-bottom: 0.5em;
811
-@ margin-top: 1em;
812
-@ margin-right: auto;
813
-@ padding: 1px 1px 1px 1px;
814
-@ font-size: 1.2em;
815
-@ font-weight: bold;
816
-@ text-align: center;
817
-@ color: white;
818
-@ border-radius: 5px;
819
-@ background-color: #446979;
820
-@ box-shadow: 0px 3px 4px #333333;
821
-@ white-space: nowrap;
822
-@ }
823
-@
824
-@ /* The "Date" that occurs on the left hand side of timelines */
825
-@ div.divider {
826
-@ font-size: 1.2em;
827
-@ font-family: Georgia, serif;
828
-@ font-weight: bold;
829
-@ margin-top: 1em;
830
-@ white-space: nowrap;
831
-@ }
832
-@
833
-@ /* The footer at the very bottom of the page */
834
-@ div.footer {
835
-@ font-size: 0.9em;
836
-@ text-align: right;
837
-@ margin-bottom: 1em;
838
-@ color: #666;
839
-@ }
840
-@
841
-@ /* Hyperlink colors in the footer */
842
-@ div.footer a { color: white; }
843
-@ div.footer a:link { color: white; }
844
-@ div.footer a:visited { color: white; }
845
-@ div.footer a:hover { background-color: white; color: #558195; }
846
-@
847
-@ /* <verbatim> blocks */
848
-@ pre.verbatim, blockquote pre {
849
-@ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
850
-@ background-color: #f3f3f3;
851
-@ padding: 0.5em;
852
-@ white-space: pre-wrap;
853
-@ }
854
-@
855
-@ blockquote pre {
856
-@ border: 1px #000 dashed;
857
-@ }
858
-@
859
-@ /* The label/value pairs on (for example) the ci page */
860
-@ table.label-value th {
861
-@ vertical-align: top;
862
-@ text-align: right;
863
-@ padding: 0.2ex 2ex;
864
-@ }
865
-@
866
-@ table.report tr th {
867
-@ padding: 3px 5px;
868
-@ text-transform: capitalize;
869
-@ cursor: pointer;
870
-@ }
871
-@
872
-@ table.report tr td {
873
-@ padding: 3px 5px;
874
-@ cursor: pointer;
875
-@ }
876
-@
877
-@ textarea {
878
-@ font-size: 1em;
879
-@ }
880
-@
881
-@ .fullsize-text {
882
-@ font-size: 1.25em;
883
-@ }');
884
-@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
885
-@ <head>
886
-@ <base href="$baseurl/$current_page" />
887
-@ <title>$<project_name>: $<title></title>
888
-@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
889
-@ href="$home/timeline.rss">
890
-@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
891
-@ media="screen">
892
-@ </head>
893
-@ <body>
894
-@ <div class="header">
895
-@ <div class="logo">
896
-@ <img src="$logo_image_url" alt="logo">
897
-@ <br />$<project_name>
898
-@ </div>
899
-@ <div class="title">$<title></div>
900
-@ <div class="status"><th1>
901
-@ if {[info exists login]} {
902
-@ puts "Logged in as $login"
903
-@ } else {
904
-@ puts "Not logged in"
905
-@ }
906
-@ </th1></div>
907
-@ </div>
908
-@ <div class="mainmenu">
909
-@ <th1>
910
-@ html "<a href=''$home$index_page''>Home</a>\n"
911
-@ if {[anycap jor]} {
912
-@ html "<a href=''$home/timeline''>Timeline</a>\n"
913
-@ }
914
-@ if {[hascap oh]} {
915
-@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
916
-@ }
917
-@ if {[hascap o]} {
918
-@ html "<a href=''$home/brlist''>Branches</a>\n"
919
-@ html "<a href=''$home/taglist''>Tags</a>\n"
920
-@ }
921
-@ if {[hascap r]} {
922
-@ html "<a href=''$home/reportlist''>Tickets</a>\n"
923
-@ }
924
-@ if {[hascap j]} {
925
-@ html "<a href=''$home/wiki''>Wiki</a>\n"
926
-@ }
927
-@ if {[hascap s]} {
928
-@ html "<a href=''$home/setup''>Admin</a>\n"
929
-@ } elseif {[hascap a]} {
930
-@ html "<a href=''$home/setup_ulist''>Users</a>\n"
931
-@ }
932
-@ if {[info exists login]} {
933
-@ html "<a href=''$home/login''>Logout</a>\n"
934
-@ } else {
935
-@ html "<a href=''$home/login''>Login</a>\n"
936
-@ }
937
-@ </th1></div>
938
-@ <div id="container">
939
-@ ');
940
-@ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div>
941
-@ <div class="footer">
942
-@ Fossil version $manifest_version $manifest_date
943
-@ </div>
944
-@ </body></html>
945
-@ ');
946
-;
947
-
948
-
949
-/*
950
-** This skin is intended to be almost identical to the default one, with the
951
-** following changes to the header and footer:
952
-**
953
-** 1. The logo image in the header has been modified to be a hyperlink to the
954
-** root of the web site containing the repository using the same scheme
955
-** (i.e. HTTP or HTTPS) as the base URL for the repository. The header
956
-** contains a TH1 script block to help accomplish these tasks.
957
-**
958
-** 2. The Fossil version information in the footer has been augmented with
959
-** hyperlinks to the corresponding points on the timeline in the official
960
-** Fossil repository. Additionally, if the Tcl integration feature is
961
-** enabled, the loaded version of Tcl is included, with a hyperlink to the
962
-** official Tcl/Tk web site. The footer also contains a TH1 script block
963
-** to help accomplish these tasks.
964
-*/
965
-static const char zBuiltinSkin5[] =
966
-@ REPLACE INTO config(name,mtime,value)
967
-@ VALUES('css',now(),'/* General settings for the entire page */
968
-@ body {
969
-@ margin: 0ex 1ex;
970
-@ padding: 0px;
971
-@ background-color: white;
972
-@ font-family: sans-serif;
973
-@ }
974
-@
975
-@ /* The project logo in the upper left-hand corner of each page */
976
-@ div.logo {
977
-@ display: table-cell;
978
-@ text-align: center;
979
-@ vertical-align: bottom;
980
-@ font-weight: bold;
981
-@ color: #558195;
982
-@ min-width: 200px;
983
-@ white-space: nowrap;
984
-@ }
985
-@
986
-@ /* The page title centered at the top of each page */
987
-@ div.title {
988
-@ display: table-cell;
989
-@ font-size: 2em;
990
-@ font-weight: bold;
991
-@ text-align: center;
992
-@ padding: 0 0 0 1em;
993
-@ color: #558195;
994
-@ vertical-align: bottom;
995
-@ width: 100%;
996
-@ }
997
-@
998
-@ /* The login status message in the top right-hand corner */
999
-@ div.status {
1000
-@ display: table-cell;
1001
-@ text-align: right;
1002
-@ vertical-align: bottom;
1003
-@ color: #558195;
1004
-@ font-size: 0.8em;
1005
-@ font-weight: bold;
1006
-@ min-width: 200px;
1007
-@ white-space: nowrap;
1008
-@ }
1009
-@
1010
-@ /* The header across the top of the page */
1011
-@ div.header {
1012
-@ display: table;
1013
-@ width: 100%;
1014
-@ }
1015
-@
1016
-@ /* The main menu bar that appears at the top of the page beneath
1017
-@ ** the header */
1018
-@ div.mainmenu {
1019
-@ padding: 5px 10px 5px 10px;
1020
-@ font-size: 0.9em;
1021
-@ font-weight: bold;
1022
-@ text-align: center;
1023
-@ letter-spacing: 1px;
1024
-@ background-color: #558195;
1025
-@ border-top-left-radius: 8px;
1026
-@ border-top-right-radius: 8px;
1027
-@ color: white;
1028
-@ }
1029
-@
1030
-@ /* The submenu bar that *sometimes* appears below the main menu */
1031
-@ div.submenu, div.sectionmenu {
1032
-@ padding: 3px 10px 3px 0px;
1033
-@ font-size: 0.9em;
1034
-@ text-align: center;
1035
-@ background-color: #456878;
1036
-@ color: white;
1037
-@ }
1038
-@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
1039
-@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
1040
-@ padding: 3px 10px 3px 10px;
1041
-@ color: white;
1042
-@ text-decoration: none;
1043
-@ }
1044
-@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
1045
-@ color: #558195;
1046
-@ background-color: white;
1047
-@ }
1048
-@
1049
-@ /* All page content from the bottom of the menu or submenu down to
1050
-@ ** the footer */
1051
-@ div.content {
1052
-@ padding: 0ex 1ex 1ex 1ex;
1053
-@ border: solid #aaa;
1054
-@ border-width: 1px;
1055
-@ }
1056
-@
1057
-@ /* Some pages have section dividers */
1058
-@ div.section {
1059
-@ margin-bottom: 0px;
1060
-@ margin-top: 1em;
1061
-@ padding: 1px 1px 1px 1px;
1062
-@ font-size: 1.2em;
1063
-@ font-weight: bold;
1064
-@ background-color: #558195;
1065
-@ color: white;
1066
-@ white-space: nowrap;
1067
-@ }
1068
-@
1069
-@ /* The "Date" that occurs on the left hand side of timelines */
1070
-@ div.divider {
1071
-@ background: #a1c4d4;
1072
-@ border: 2px #558195 solid;
1073
-@ font-size: 1em; font-weight: normal;
1074
-@ padding: .25em;
1075
-@ margin: .2em 0 .2em 0;
1076
-@ float: left;
1077
-@ clear: left;
1078
-@ white-space: nowrap;
1079
-@ }
1080
-@
1081
-@ /* The footer at the very bottom of the page */
1082
-@ div.footer {
1083
-@ clear: both;
1084
-@ font-size: 0.8em;
1085
-@ padding: 5px 10px 5px 10px;
1086
-@ text-align: right;
1087
-@ background-color: #558195;
1088
-@ border-bottom-left-radius: 8px;
1089
-@ border-bottom-right-radius: 8px;
1090
-@ color: white;
1091
-@ }
1092
-@
1093
-@ /* Hyperlink colors in the footer */
1094
-@ div.footer a { color: white; }
1095
-@ div.footer a:link { color: white; }
1096
-@ div.footer a:visited { color: white; }
1097
-@ div.footer a:hover { background-color: white; color: #558195; }
1098
-@
1099
-@ /* verbatim blocks */
1100
-@ pre.verbatim {
1101
-@ background-color: #f5f5f5;
1102
-@ padding: 0.5em;
1103
-@ white-space: pre-wrap;
1104
-@ }
1105
-@
1106
-@ /* The label/value pairs on (for example) the ci page */
1107
-@ table.label-value th {
1108
-@ vertical-align: top;
1109
-@ text-align: right;
1110
-@ padding: 0.2ex 2ex;
1111
-@ }');
1112
-@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
1113
-@ <head>
1114
-@ <base href="$baseurl/$current_page" />
1115
-@ <title>$<project_name>: $<title></title>
1116
-@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
1117
-@ href="$home/timeline.rss" />
1118
-@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
1119
-@ media="screen" />
1120
-@ </head>
1121
-@ <body>
1122
-@ <div class="header">
1123
-@ <div class="logo">
1124
-@ <th1>
1125
-@ ##
1126
-@ ## NOTE: The purpose of this procedure is to take the base URL of the
1127
-@ ## Fossil project and return the root of the entire web site using
1128
-@ ## the same URI scheme as the base URL (e.g. http or https).
1129
-@ ##
1130
-@ proc getLogoUrl { baseurl } {
1131
-@ set idx(first) [string first // $baseurl]
1132
-@ if {$idx(first) != -1} {
1133
-@ ##
1134
-@ ## NOTE: Skip second slash.
1135
-@ ##
1136
-@ set idx(first+1) [expr {$idx(first) + 2}]
1137
-@ ##
1138
-@ ## NOTE: (part 1) The [string first] command does NOT actually
1139
-@ ## the optional startIndex argument as specified in the
1140
-@ ## TH1 support manual; therefore, we fake it by using the
1141
-@ ## [string range] command and then adding the necessary
1142
-@ ## offset to the resulting index manually (below). In Tcl,
1143
-@ ## we could use the following instead:
1144
-@ ##
1145
-@ ## set idx(next) [string first / $baseurl $idx(first+1)]
1146
-@ ##
1147
-@ set idx(nextRange) [string range $baseurl $idx(first+1) end]
1148
-@ set idx(next) [string first / $idx(nextRange)]
1149
-@ if {$idx(next) != -1} {
1150
-@ ##
1151
-@ ## NOTE: (part 2) Add the necessary offset to the result of the
1152
-@ ## search for the next slash (i.e. the one after the initial
1153
-@ ## search for the two slashes).
1154
-@ ##
1155
-@ set idx(next) [expr {$idx(next) + $idx(first+1)}]
1156
-@ ##
1157
-@ ## NOTE: Back up one character from the next slash.
1158
-@ ##
1159
-@ set idx(next-1) [expr {$idx(next) - 1}]
1160
-@ ##
1161
-@ ## NOTE: Extract the URI scheme and host from the base URL.
1162
-@ ##
1163
-@ set scheme [string range $baseurl 0 $idx(first)]
1164
-@ set host [string range $baseurl $idx(first+1) $idx(next-1)]
1165
-@ ##
1166
-@ ## NOTE: Try to stay in SSL mode if we are there now.
1167
-@ ##
1168
-@ if {[string compare $scheme http:/] == 0} {
1169
-@ set scheme http://
1170
-@ } else {
1171
-@ set scheme https://
1172
-@ }
1173
-@ set logourl $scheme$host/
1174
-@ } else {
1175
-@ set logourl $baseurl
1176
-@ }
1177
-@ } else {
1178
-@ set logourl $baseurl
1179
-@ }
1180
-@ return $logourl
1181
-@ }
1182
-@ set logourl [getLogoUrl $baseurl]
1183
-@ </th1>
1184
-@ <a href="$logourl">
1185
-@ <img src="$logo_image_url" border="0" alt="$project_name">
1186
-@ </a>
1187
-@ </div>
1188
-@ <div class="title"><small>$<project_name></small><br />$<title></div>
1189
-@ <div class="status"><th1>
1190
-@ if {[info exists login]} {
1191
-@ puts "Logged in as $login"
1192
-@ } else {
1193
-@ puts "Not logged in"
1194
-@ }
1195
-@ </th1></div>
1196
-@ </div>
1197
-@ <div class="mainmenu">
1198
-@ <th1>
1199
-@ html "<a href=''$home$index_page''>Home</a>\n"
1200
-@ if {[anycap jor]} {
1201
-@ html "<a href=''$home/timeline''>Timeline</a>\n"
1202
-@ }
1203
-@ if {[hascap oh]} {
1204
-@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
1205
-@ }
1206
-@ if {[hascap o]} {
1207
-@ html "<a href=''$home/brlist''>Branches</a>\n"
1208
-@ html "<a href=''$home/taglist''>Tags</a>\n"
1209
-@ }
1210
-@ if {[hascap r]} {
1211
-@ html "<a href=''$home/reportlist''>Tickets</a>\n"
1212
-@ }
1213
-@ if {[hascap j]} {
1214
-@ html "<a href=''$home/wiki''>Wiki</a>\n"
1215
-@ }
1216
-@ if {[hascap s]} {
1217
-@ html "<a href=''$home/setup''>Admin</a>\n"
1218
-@ } elseif {[hascap a]} {
1219
-@ html "<a href=''$home/setup_ulist''>Users</a>\n"
1220
-@ }
1221
-@ if {[info exists login]} {
1222
-@ html "<a href=''$home/login''>Logout</a>\n"
1223
-@ } else {
1224
-@ html "<a href=''$home/login''>Login</a>\n"
1225
-@ }
1226
-@ </th1></div>
1227
-@ ');
1228
-@ REPLACE INTO config(name,mtime,value)
1229
-@ VALUES('footer',now(),'<div class="footer">
1230
-@ <th1>
1231
-@ proc getTclVersion {} {
1232
-@ if {[catch {tclEval info patchlevel} tclVersion] == 0} {
1233
-@ return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
1234
-@ }
1235
-@ return ""
1236
-@ }
1237
-@ proc getVersion { version } {
1238
-@ set length [string length $version]
1239
-@ return [string range $version 1 [expr {$length - 2}]]
1240
-@ }
1241
-@ set version [getVersion $manifest_version]
1242
-@ set tclVersion [getTclVersion]
1243
-@ set fossilUrl http://www.fossil-scm.org
1244
-@ </th1>
1245
-@ This page was generated in about
1246
-@ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
1247
-@ <a href="$fossilUrl/">Fossil</a>
1248
-@ version $release_version $tclVersion
1249
-@ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
1250
-@ <a href="$fossilUrl/index.html/timeline?c=$manifest_date&amp;y=ci">$manifest_date</a>
1251
-@ </div>
1252
-@ </body></html>
1253
-@ ');
1254
-;
1255
-
125624
/*
125725
** An array of available built-in skins.
26
+**
27
+** To add new built-in skins:
28
+**
29
+** 1. Pick a name for the new skin. (Here we use "xyzzy").
30
+**
31
+** 2. Install files skins/xyzzy/css.txt, skins/xyzzy/header.txt,
32
+** and skins/xyzzy/footer.txt into the source tree.
33
+**
34
+** 3. Rerun "tclsh makemake.tcl" in the src/ folder in order to
35
+** rebuild the makefiles to reference the new CSS, headers, and footers.
36
+**
37
+** 4. Make an entry in the following array for the new skin.
125838
*/
125939
static struct BuiltinSkin {
1260
- const char *zName;
1261
- const char *zValue;
40
+ const char *zDesc; /* Description of this skin */
41
+ const char *zLabel; /* The directory under skins/ holding this skin */
42
+ char *zSQL; /* Filled in at run-time with SQL to insert this skin */
126243
} aBuiltinSkin[] = {
1263
- { "Default", 0 /* Filled in at runtime */ },
1264
- { "Plain Gray, No Logo", zBuiltinSkin1 },
1265
- { "Khaki, No Logo", zBuiltinSkin2 },
1266
- { "Black & White, Menu on Left", zBuiltinSkin3 },
1267
- { "Shadow boxes & Rounded Corners", zBuiltinSkin4 },
1268
- { "Enhanced Default", zBuiltinSkin5 },
44
+ { "Default", "default", 0 },
45
+ { "Plain Gray, No Logo", "plain_gray", 0 },
46
+ { "Khaki, No Logo", "khaki", 0 },
47
+ { "Black & White, Menu on Left", "black_and_white", 0 },
48
+ { "Shadow boxes & Rounded Corners", "rounded1", 0 },
49
+ { "Enhanced Default", "enhanced1", 0 },
50
+ { "San Francisco Modern", "etienne1", 0 },
51
+ { "Eagle", "eagle", 0 },
126952
};
127053
127154
/*
127255
** For a skin named zSkinName, compute the name of the CONFIG table
127356
** entry where that skin is stored and return it.
@@ -1286,57 +69,158 @@
128669
}
128770
return z;
128871
}
128972
129073
/*
1291
-** Construct and return a string that represents the current skin if
1292
-** useDefault==0 or a string for the default skin if useDefault==1.
74
+** Return true if there exists a skin name "zSkinName".
75
+*/
76
+static int skinExists(const char *zSkinName){
77
+ int i;
78
+ if( zSkinName==0 ) return 0;
79
+ for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
80
+ if( fossil_strcmp(zSkinName, aBuiltinSkin[i].zDesc)==0 ) return 1;
81
+ }
82
+ return db_exists("SELECT 1 FROM config WHERE name='skin:%q'", zSkinName);
83
+}
84
+
85
+/*
86
+** Construct and return an string of SQL statements that represents
87
+** a "skin" setting. If zName==0 then return the skin currently
88
+** installed. Otherwise, return one of the built-in skins designated
89
+** by zName.
129390
**
129491
** Memory to hold the returned string is obtained from malloc.
129592
*/
1296
-static char *getSkin(int useDefault){
93
+static char *getSkin(const char *zName){
94
+ const char *z;
95
+ char *zLabel;
96
+ static const char *azType[] = { "css", "header", "footer" };
97
+ int i;
129798
Blob val;
129899
blob_zero(&val);
1299
- blob_appendf(&val,
1300
- "REPLACE INTO config(name,value,mtime) VALUES('css',%Q,now());\n",
1301
- useDefault ? zDefaultCSS : db_get("css", (char*)zDefaultCSS)
1302
- );
1303
- blob_appendf(&val,
1304
- "REPLACE INTO config(name,value,mtime) VALUES('header',%Q,now());\n",
1305
- useDefault ? zDefaultHeader : db_get("header", (char*)zDefaultHeader)
1306
- );
1307
- blob_appendf(&val,
1308
- "REPLACE INTO config(name,value,mtime) VALUES('footer',%Q,now());\n",
1309
- useDefault ? zDefaultFooter : db_get("footer", (char*)zDefaultFooter)
1310
- );
100
+ for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
101
+ if( zName ){
102
+ zLabel = mprintf("skins/%s/%s.txt", zName, azType[i]);
103
+ z = builtin_text(zLabel);
104
+ fossil_free(zLabel);
105
+ }else{
106
+ z = db_get(azType[i], 0);
107
+ if( z==0 ){
108
+ zLabel = mprintf("skins/default/%s.txt", azType[i]);
109
+ z = builtin_text(zLabel);
110
+ fossil_free(zLabel);
111
+ }
112
+ }
113
+ blob_appendf(&val,
114
+ "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now());\n",
115
+ azType[i], z
116
+ );
117
+ }
1311118
return blob_str(&val);
1312119
}
1313120
1314121
/*
1315
-** Construct the default skin string and fill in the corresponding
1316
-** entry in aBuildinSkin[]
122
+** Respond to a Rename button press. Return TRUE if a dialog was painted.
123
+** Return FALSE to continue with the main Skins page.
124
+*/
125
+static int skinRename(void){
126
+ const char *zOldName;
127
+ const char *zNewName;
128
+ int ex = 0;
129
+ if( P("rename")==0 ) return 0;
130
+ zOldName = P("sn");
131
+ zNewName = P("newname");
132
+ if( zOldName==0 ) return 0;
133
+ if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){
134
+ if( zNewName==0 ) zNewName = zOldName;
135
+ style_header("Rename A Skin");
136
+ if( ex ){
137
+ @ <p><span class="generalError">There is already another skin
138
+ @ named "%h(zNewName)". Choose a different name.</span></p>
139
+ }
140
+ @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
141
+ @ <table border="0"><tr>
142
+ @ <tr><td align="right">Current name:<td align="left"><b>%h(zOldName)</b>
143
+ @ <tr><td align="right">New name:<td align="left">
144
+ @ <input type="text" size="35" name="newname" value="%h(zNewName)">
145
+ @ <tr><td><td>
146
+ @ <input type="hidden" name="sn" value="%h(zOldName)">
147
+ @ <input type="submit" name="rename" value="Rename">
148
+ @ <input type="submit" name="canren" value="Cancel">
149
+ @ </table>
150
+ login_insert_csrf_secret();
151
+ @ </div></form>
152
+ style_footer();
153
+ return 1;
154
+ }
155
+ db_multi_exec(
156
+ "UPDATE config SET name='skin:%q' WHERE name='skin:%q';",
157
+ zNewName, zOldName
158
+ );
159
+ return 0;
160
+}
161
+
162
+/*
163
+** Respond to a Save button press. Return TRUE if a dialog was painted.
164
+** Return FALSE to continue with the main Skins page.
1317165
*/
1318
-static void setDefaultSkin(void){
1319
- aBuiltinSkin[0].zValue = getSkin(1);
166
+static int skinSave(const char *zCurrent){
167
+ const char *zNewName;
168
+ int ex = 0;
169
+ if( P("save")==0 ) return 0;
170
+ zNewName = P("svname");
171
+ if( zNewName && zNewName[0]!=0 ){
172
+ }
173
+ if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){
174
+ if( zNewName==0 ) zNewName = "";
175
+ style_header("Save Current Skin");
176
+ if( ex ){
177
+ @ <p><span class="generalError">There is already another skin
178
+ @ named "%h(zNewName)". Choose a different name.</span></p>
179
+ }
180
+ @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
181
+ @ <table border="0"><tr>
182
+ @ <tr><td align="right">Name for this skin:<td align="left">
183
+ @ <input type="text" size="35" name="svname" value="%h(zNewName)">
184
+ @ <tr><td><td>
185
+ @ <input type="submit" name="save" value="Save">
186
+ @ <input type="submit" name="cansave" value="Cancel">
187
+ @ </table>
188
+ login_insert_csrf_secret();
189
+ @ </div></form>
190
+ style_footer();
191
+ return 1;
192
+ }
193
+ db_multi_exec(
194
+ "INSERT OR IGNORE INTO config(name, value, mtime)"
195
+ "VALUES('skin:%q',%Q,now())",
196
+ zNewName, zCurrent
197
+ );
198
+ return 0;
1320199
}
1321200
1322201
/*
1323202
** WEBPAGE: setup_skin
1324203
*/
1325204
void setup_skin(void){
1326205
const char *z;
1327206
char *zName;
1328207
char *zErr = 0;
1329
- const char *zCurrent; /* Current skin */
1330
- int i; /* Loop counter */
208
+ const char *zCurrent = 0; /* Current skin */
209
+ int i; /* Loop counter */
1331210
Stmt q;
211
+ int seenCurrent = 0;
1332212
1333213
login_check_credentials();
1334214
if( !g.perm.Setup ){
1335215
login_needed();
1336216
}
1337217
db_begin_transaction();
218
+ zCurrent = getSkin(0);
219
+ for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
220
+ aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
221
+ }
1338222
1339223
/* Process requests to delete a user-defined skin */
1340224
if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
1341225
style_header("Confirm Custom Skin Delete");
1342226
@ <form action="%s(g.zTop)/setup_skin" method="post"><div>
@@ -1351,51 +235,42 @@
1351235
return;
1352236
}
1353237
if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
1354238
db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
1355239
}
1356
-
1357
- setDefaultSkin();
1358
- zCurrent = getSkin(0);
1359
-
1360
- if( P("save")!=0 && (zName = skinVarName(P("save"),0))!=0 ){
1361
- if( db_exists("SELECT 1 FROM config WHERE name=%Q", zName)
1362
- || fossil_strcmp(zName, "Default")==0 ){
1363
- zErr = mprintf("Skin name \"%h\" already exists. "
1364
- "Choose a different name.", P("sn"));
1365
- }else{
1366
- db_multi_exec("INSERT INTO config(name,value,mtime) VALUES(%Q,%Q,now())",
1367
- zName, zCurrent
1368
- );
1369
- }
1370
- }
1371
-
1372
- /* The user pressed the "Use This Skin" button. */
240
+ if( skinRename() ) return;
241
+ if( skinSave(zCurrent) ) return;
242
+
243
+ /* The user pressed one of the "Install" buttons. */
1373244
if( P("load") && (z = P("sn"))!=0 && z[0] ){
1374245
int seen = 0;
246
+
247
+ /* Check to see if the current skin is already saved. If it is, there
248
+ ** is no need to create a backup */
249
+ zCurrent = getSkin(0);
1375250
for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
1376
- if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
251
+ if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
1377252
seen = 1;
1378253
break;
1379254
}
1380255
}
1381256
if( !seen ){
1382257
seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
1383258
" AND value=%Q", zCurrent);
1384
- }
1385
- if( !seen ){
1386
- db_multi_exec(
1387
- "INSERT INTO config(name,value,mtime) VALUES("
1388
- " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
1389
- " %Q,now())", zCurrent
1390
- );
259
+ if( !seen ){
260
+ db_multi_exec(
261
+ "INSERT INTO config(name,value,mtime) VALUES("
262
+ " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
263
+ " %Q,now())", zCurrent
264
+ );
265
+ }
1391266
}
1392267
seen = 0;
1393268
for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
1394
- if( fossil_strcmp(aBuiltinSkin[i].zName, z)==0 ){
269
+ if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){
1395270
seen = 1;
1396
- zCurrent = aBuiltinSkin[i].zValue;
271
+ zCurrent = aBuiltinSkin[i].zSQL;
1397272
db_multi_exec("%s", zCurrent/*safe-for-%s*/);
1398273
break;
1399274
}
1400275
}
1401276
if( !seen ){
@@ -1409,48 +284,59 @@
1409284
if( zErr ){
1410285
@ <p><font color="red">%h(zErr)</font></p>
1411286
}
1412287
@ <p>A "skin" is a combination of
1413288
@ <a href="setup_editcss">CSS</a>,
1414
- @ <a href="setup_header">Header</a>,
1415
- @ <a href="setup_footer">Footer</a>, and
1416
- @ <a href="setup_logo">Logo</a> that determines the look and feel
289
+ @ <a href="setup_header">Header</a>, and
290
+ @ <a href="setup_footer">Footer</a> that determines the look and feel
1417291
@ of the web interface.</p>
1418292
@
1419293
@ <h2>Available Skins:</h2>
1420
- @ <ol>
294
+ @ <table border="0">
1421295
for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
1422
- z = aBuiltinSkin[i].zName;
1423
- if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
1424
- @ <li><p>%h(z).&nbsp;&nbsp; <b>Currently In Use</b></p>
296
+ z = aBuiltinSkin[i].zDesc;
297
+ @ <tr><td>%d(i+1).<td>%h(z)<td>&nbsp;&nbsp;<td>
298
+ if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
299
+ @ (Currently In Use)
300
+ seenCurrent = 1;
1425301
}else{
1426
- @ <li><form action="%s(g.zTop)/setup_skin" method="post"><div>
1427
- @ %h(z).&nbsp;&nbsp;
302
+ @ <form action="%s(g.zTop)/setup_skin" method="post">
1428303
@ <input type="hidden" name="sn" value="%h(z)" />
1429
- @ <input type="submit" name="load" value="Use This Skin" />
1430
- @ </div></form></li>
304
+ @ <input type="submit" name="load" value="Install" />
305
+ @ </form>
1431306
}
307
+ @ </tr>
1432308
}
1433309
db_prepare(&q,
1434310
"SELECT substr(name, 6), value FROM config"
1435311
" WHERE name GLOB 'skin:*'"
1436312
" ORDER BY name"
1437313
);
1438314
while( db_step(&q)==SQLITE_ROW ){
1439315
const char *zN = db_column_text(&q, 0);
1440316
const char *zV = db_column_text(&q, 1);
1441
- if( fossil_strcmp(zV, zCurrent)==0 ){
1442
- @ <li><p>%h(zN).&nbsp;&nbsp; <b>Currently In Use</b></p>
1443
- }else{
1444
- @ <li><form action="%s(g.zTop)/setup_skin" method="post">
1445
- @ %h(zN).&nbsp;&nbsp;
1446
- @ <input type="hidden" name="sn" value="%h(zN)">
1447
- @ <input type="submit" name="load" value="Use This Skin">
1448
- @ <input type="submit" name="del1" value="Delete This Skin">
1449
- @ </form></li>
1450
- }
317
+ i++;
318
+ @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
319
+ @ <form action="%s(g.zTop)/setup_skin" method="post">
320
+ if( fossil_strcmp(zV, zCurrent)==0 ){
321
+ @ (Currently In Use)
322
+ seenCurrent = 1;
323
+ }else{
324
+ @ <input type="submit" name="load" value="Install">
325
+ @ <input type="submit" name="del1" value="Delete">
326
+ }
327
+ @ <input type="submit" name="rename" value="Rename">
328
+ @ <input type="hidden" name="sn" value="%h(zN)">
329
+ @ </form></tr>
1451330
}
1452331
db_finalize(&q);
1453
- @ </ol>
332
+ if( !seenCurrent ){
333
+ i++;
334
+ @ <tr><td>%d(i).<td><i>Current Configuration</i><td>&nbsp;&nbsp;<td>
335
+ @ <form action="%s(g.zTop)/setup_skin" method="post">
336
+ @ <input type="submit" name="save" value="Save">
337
+ @ </form>
338
+ }
339
+ @ </table>
1454340
style_footer();
1455341
db_end_transaction(0);
1456342
}
1457343
--- src/skins.c
+++ src/skins.c
@@ -19,1255 +19,38 @@
19 */
20 #include "config.h"
21 #include <assert.h>
22 #include "skins.h"
23
24 /* @-comment: ## */
25 /*
26 ** A black-and-white theme with the project title in a bar across the top
27 ** and no logo image.
28 */
29 static const char zBuiltinSkin1[] =
30 @ REPLACE INTO config(name,mtime,value)
31 @ VALUES('css',now(),'/* General settings for the entire page */
32 @ body {
33 @ margin: 0ex 1ex;
34 @ padding: 0px;
35 @ background-color: white;
36 @ font-family: sans-serif;
37 @ }
38 @
39 @ /* The project logo in the upper left-hand corner of each page */
40 @ div.logo {
41 @ display: table-row;
42 @ text-align: center;
43 @ /* vertical-align: bottom;*/
44 @ font-size: 2em;
45 @ font-weight: bold;
46 @ background-color: #707070;
47 @ color: #ffffff;
48 @ min-width: 200px;
49 @ white-space: nowrap;
50 @ }
51 @
52 @ /* The page title centered at the top of each page */
53 @ div.title {
54 @ display: table-cell;
55 @ font-size: 1.5em;
56 @ font-weight: bold;
57 @ text-align: center;
58 @ padding: 0 0 0 10px;
59 @ color: #404040;
60 @ vertical-align: bottom;
61 @ width: 100%;
62 @ }
63 @
64 @ /* The login status message in the top right-hand corner */
65 @ div.status {
66 @ display: table-cell;
67 @ text-align: right;
68 @ vertical-align: bottom;
69 @ color: #404040;
70 @ font-size: 0.8em;
71 @ font-weight: bold;
72 @ min-width: 200px;
73 @ white-space: nowrap;
74 @ }
75 @
76 @ /* The header across the top of the page */
77 @ div.header {
78 @ display: table;
79 @ width: 100%;
80 @ }
81 @
82 @ /* The main menu bar that appears at the top of the page beneath
83 @ ** the header */
84 @ div.mainmenu {
85 @ padding: 5px 10px 5px 10px;
86 @ font-size: 0.9em;
87 @ font-weight: bold;
88 @ text-align: center;
89 @ letter-spacing: 1px;
90 @ background-color: #404040;
91 @ color: white;
92 @ }
93 @
94 @ /* The submenu bar that *sometimes* appears below the main menu */
95 @ div.submenu, div.sectionmenu {
96 @ padding: 3px 10px 3px 0px;
97 @ font-size: 0.9em;
98 @ text-align: center;
99 @ background-color: #606060;
100 @ color: white;
101 @ }
102 @ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
103 @ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
104 @ padding: 3px 10px 3px 10px;
105 @ color: white;
106 @ text-decoration: none;
107 @ }
108 @ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
109 @ color: #404040;
110 @ background-color: white;
111 @ }
112 @
113 @ /* All page content from the bottom of the menu or submenu down to
114 @ ** the footer */
115 @ div.content {
116 @ padding: 0ex 0ex 0ex 0ex;
117 @ }
118 @ /* Hyperlink colors */
119 @ div.content a { color: #604000; }
120 @ div.content a:link { color: #604000;}
121 @ div.content a:visited { color: #600000; }
122 @
123 @ /* <verbatim> blocks */
124 @ pre.verbatim {
125 @ background-color: #ffffff;
126 @ padding: 0.5em;
127 @ white-space: pre-wrap;
128 @ }
129 @
130 @ /* Some pages have section dividers */
131 @ div.section {
132 @ margin-bottom: 0px;
133 @ margin-top: 1em;
134 @ padding: 1px 1px 1px 1px;
135 @ font-size: 1.2em;
136 @ font-weight: bold;
137 @ background-color: #404040;
138 @ color: white;
139 @ white-space: nowrap;
140 @ }
141 @
142 @ /* The "Date" that occurs on the left hand side of timelines */
143 @ div.divider {
144 @ background: #a0a0a0;
145 @ border: 2px #505050 solid;
146 @ font-size: 1em; font-weight: normal;
147 @ padding: .25em;
148 @ margin: .2em 0 .2em 0;
149 @ float: left;
150 @ clear: left;
151 @ white-space: nowrap;
152 @ }
153 @
154 @ /* The footer at the very bottom of the page */
155 @ div.footer {
156 @ font-size: 0.8em;
157 @ margin-top: 12px;
158 @ padding: 5px 10px 5px 10px;
159 @ text-align: right;
160 @ background-color: #404040;
161 @ color: white;
162 @ }
163 @
164 @ /* The label/value pairs on (for example) the vinfo page */
165 @ table.label-value th {
166 @ vertical-align: top;
167 @ text-align: right;
168 @ padding: 0.2ex 2ex;
169 @ }');
170 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
171 @ <head>
172 @ <base href="$baseurl/$current_page" />
173 @ <title>$<project_name>: $<title></title>
174 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
175 @ href="$home/timeline.rss">
176 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
177 @ media="screen">
178 @ </head>
179 @ <body>
180 @ <div class="header">
181 @ <div class="title"><small>$<project_name></small><br />$<title></div>
182 @ <div class="status"><th1>
183 @ if {[info exists login]} {
184 @ puts "Logged in as $login"
185 @ } else {
186 @ puts "Not logged in"
187 @ }
188 @ </th1></div>
189 @ </div>
190 @ <div class="mainmenu">
191 @ <th1>
192 @ html "<a href=''$home$index_page''>Home</a>\n"
193 @ if {[anycap jor]} {
194 @ html "<a href=''$home/timeline''>Timeline</a>\n"
195 @ }
196 @ if {[hascap oh]} {
197 @ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
198 @ }
199 @ if {[hascap o]} {
200 @ html "<a href=''$home/brlist''>Branches</a>\n"
201 @ html "<a href=''$home/taglist''>Tags</a>\n"
202 @ }
203 @ if {[hascap r]} {
204 @ html "<a href=''$home/reportlist''>Tickets</a>\n"
205 @ }
206 @ if {[hascap j]} {
207 @ html "<a href=''$home/wiki''>Wiki</a>\n"
208 @ }
209 @ if {[hascap s]} {
210 @ html "<a href=''$home/setup''>Admin</a>\n"
211 @ } elseif {[hascap a]} {
212 @ html "<a href=''$home/setup_ulist''>Users</a>\n"
213 @ }
214 @ if {[info exists login]} {
215 @ html "<a href=''$home/login''>Logout</a>\n"
216 @ } else {
217 @ html "<a href=''$home/login''>Login</a>\n"
218 @ }
219 @ </th1></div>
220 @ ');
221 @ REPLACE INTO config(name,mtime,value)
222 @ VALUES('footer',now(),'<div class="footer">
223 @ Fossil version $manifest_version $manifest_date
224 @ </div>
225 @ </body></html>
226 @ ');
227 ;
228
229 /*
230 ** A tan theme with the project title above the user identification
231 ** and no logo image.
232 */
233 static const char zBuiltinSkin2[] =
234 @ REPLACE INTO config(name,mtime,value)
235 @ VALUES('css',now(),'/* General settings for the entire page */
236 @ body {
237 @ margin: 0ex 0ex;
238 @ padding: 0px;
239 @ background-color: #fef3bc;
240 @ font-family: sans-serif;
241 @ }
242 @
243 @ /* The project logo in the upper left-hand corner of each page */
244 @ div.logo {
245 @ display: inline;
246 @ text-align: center;
247 @ vertical-align: bottom;
248 @ font-weight: bold;
249 @ font-size: 2.5em;
250 @ color: #a09048;
251 @ white-space: nowrap;
252 @ }
253 @
254 @ /* The page title centered at the top of each page */
255 @ div.title {
256 @ display: table-cell;
257 @ font-size: 2em;
258 @ font-weight: bold;
259 @ text-align: left;
260 @ padding: 0 0 0 5px;
261 @ color: #a09048;
262 @ vertical-align: bottom;
263 @ width: 100%;
264 @ }
265 @
266 @ /* The login status message in the top right-hand corner */
267 @ div.status {
268 @ display: table-cell;
269 @ text-align: right;
270 @ vertical-align: bottom;
271 @ color: #a09048;
272 @ padding: 5px 5px 0 0;
273 @ font-size: 0.8em;
274 @ font-weight: bold;
275 @ white-space: nowrap;
276 @ }
277 @
278 @ /* The header across the top of the page */
279 @ div.header {
280 @ display: table;
281 @ width: 100%;
282 @ }
283 @
284 @ /* The main menu bar that appears at the top of the page beneath
285 @ ** the header */
286 @ div.mainmenu {
287 @ padding: 5px 10px 5px 10px;
288 @ font-size: 0.9em;
289 @ font-weight: bold;
290 @ text-align: center;
291 @ letter-spacing: 1px;
292 @ background-color: #a09048;
293 @ color: black;
294 @ }
295 @
296 @ /* The submenu bar that *sometimes* appears below the main menu */
297 @ div.submenu, div.sectionmenu {
298 @ padding: 3px 10px 3px 0px;
299 @ font-size: 0.9em;
300 @ text-align: center;
301 @ background-color: #c0af58;
302 @ color: white;
303 @ }
304 @ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
305 @ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
306 @ padding: 3px 10px 3px 10px;
307 @ color: white;
308 @ text-decoration: none;
309 @ }
310 @ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
311 @ color: #a09048;
312 @ background-color: white;
313 @ }
314 @
315 @ /* All page content from the bottom of the menu or submenu down to
316 @ ** the footer */
317 @ div.content {
318 @ padding: 1ex 5px;
319 @ }
320 @ div.content a { color: #706532; }
321 @ div.content a:link { color: #706532; }
322 @ div.content a:visited { color: #704032; }
323 @ div.content a:hover { background-color: white; color: #706532; }
324 @
325 @ /* Some pages have section dividers */
326 @ div.section {
327 @ margin-bottom: 0px;
328 @ margin-top: 1em;
329 @ padding: 3px 3px 0 3px;
330 @ font-size: 1.2em;
331 @ font-weight: bold;
332 @ background-color: #a09048;
333 @ color: white;
334 @ white-space: nowrap;
335 @ }
336 @
337 @ /* The "Date" that occurs on the left hand side of timelines */
338 @ div.divider {
339 @ background: #e1d498;
340 @ border: 2px #a09048 solid;
341 @ font-size: 1em; font-weight: normal;
342 @ padding: .25em;
343 @ margin: .2em 0 .2em 0;
344 @ float: left;
345 @ clear: left;
346 @ white-space: nowrap;
347 @ }
348 @
349 @ /* The footer at the very bottom of the page */
350 @ div.footer {
351 @ font-size: 0.8em;
352 @ margin-top: 12px;
353 @ padding: 5px 10px 5px 10px;
354 @ text-align: right;
355 @ background-color: #a09048;
356 @ color: white;
357 @ }
358 @
359 @ /* Hyperlink colors */
360 @ div.footer a { color: white; }
361 @ div.footer a:link { color: white; }
362 @ div.footer a:visited { color: white; }
363 @ div.footer a:hover { background-color: white; color: #558195; }
364 @
365 @ /* <verbatim> blocks */
366 @ pre.verbatim {
367 @ background-color: #f5f5f5;
368 @ padding: 0.5em;
369 @ white-space: pre-wrap;
370 @ }
371 @
372 @ /* The label/value pairs on (for example) the ci page */
373 @ table.label-value th {
374 @ vertical-align: top;
375 @ text-align: right;
376 @ padding: 0.2ex 2ex;
377 @ }');
378 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
379 @ <head>
380 @ <base href="$baseurl/$current_page" />
381 @ <title>$<project_name>: $<title></title>
382 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
383 @ href="$home/timeline.rss">
384 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
385 @ media="screen">
386 @ </head>
387 @ <body>
388 @ <div class="header">
389 @ <div class="title">$<title></div>
390 @ <div class="status">
391 @ <div class="logo">$<project_name></div><br/>
392 @ <th1>
393 @ if {[info exists login]} {
394 @ puts "Logged in as $login"
395 @ } else {
396 @ puts "Not logged in"
397 @ }
398 @ </th1></div>
399 @ </div>
400 @ <div class="mainmenu">
401 @ <th1>
402 @ html "<a href=''$home$index_page''>Home</a>\n"
403 @ if {[anycap jor]} {
404 @ html "<a href=''$home/timeline''>Timeline</a>\n"
405 @ }
406 @ if {[hascap oh]} {
407 @ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
408 @ }
409 @ if {[hascap o]} {
410 @ html "<a href=''$home/brlist''>Branches</a>\n"
411 @ html "<a href=''$home/taglist''>Tags</a>\n"
412 @ }
413 @ if {[hascap r]} {
414 @ html "<a href=''$home/reportlist''>Tickets</a>\n"
415 @ }
416 @ if {[hascap j]} {
417 @ html "<a href=''$home/wiki''>Wiki</a>\n"
418 @ }
419 @ if {[hascap s]} {
420 @ html "<a href=''$home/setup''>Admin</a>\n"
421 @ } elseif {[hascap a]} {
422 @ html "<a href=''$home/setup_ulist''>Users</a>\n"
423 @ }
424 @ if {[info exists login]} {
425 @ html "<a href=''$home/login''>Logout</a>\n"
426 @ } else {
427 @ html "<a href=''$home/login''>Login</a>\n"
428 @ }
429 @ </th1></div>
430 @ ');
431 @ REPLACE INTO config(name,mtime,value)
432 @ VALUES('footer',now(),'<div class="footer">
433 @ Fossil version $manifest_version $manifest_date
434 @ </div>
435 @ </body></html>
436 @ ');
437 ;
438
439 /*
440 ** Black letters on a white or cream background with the main menu
441 ** stuck on the left-hand side.
442 */
443 static const char zBuiltinSkin3[] =
444 @ REPLACE INTO config(name,mtime,value)
445 @ VALUES('css',now(),'/* General settings for the entire page */
446 @ body {
447 @ margin:0px 0px 0px 0px;
448 @ padding:0px;
449 @ font-family:verdana, arial, helvetica, "sans serif";
450 @ color:#333;
451 @ background-color:white;
452 @ }
453 @
454 @ /* consistent colours */
455 @ h2 {
456 @ color: #333;
457 @ }
458 @ h3 {
459 @ color: #333;
460 @ }
461 @
462 @ /* The project logo in the upper left-hand corner of each page */
463 @ div.logo {
464 @ display: table-cell;
465 @ text-align: left;
466 @ vertical-align: bottom;
467 @ font-weight: bold;
468 @ color: #333;
469 @ white-space: nowrap;
470 @ }
471 @
472 @ /* The page title centered at the top of each page */
473 @ div.title {
474 @ display: table-cell;
475 @ font-size: 2em;
476 @ font-weight: bold;
477 @ text-align: center;
478 @ color: #333;
479 @ vertical-align: bottom;
480 @ width: 100%;
481 @ }
482 @
483 @ /* The login status message in the top right-hand corner */
484 @ div.status {
485 @ display: table-cell;
486 @ padding-right: 10px;
487 @ text-align: right;
488 @ vertical-align: bottom;
489 @ padding-bottom: 5px;
490 @ color: #333;
491 @ font-size: 0.8em;
492 @ font-weight: bold;
493 @ white-space: nowrap;
494 @ }
495 @
496 @ /* The header across the top of the page */
497 @ div.header {
498 @ margin:10px 0px 10px 0px;
499 @ padding:1px 0px 0px 20px;
500 @ border-style:solid;
501 @ border-color:black;
502 @ border-width:1px 0px;
503 @ background-color:#eee;
504 @ }
505 @
506 @ /* The main menu bar that appears at the top left of the page beneath
507 @ ** the header. Width must be co-ordinated with the container below */
508 @ div.mainmenu {
509 @ float: left;
510 @ margin-left: 10px;
511 @ margin-right: 10px;
512 @ font-size: 0.9em;
513 @ font-weight: bold;
514 @ padding:5px;
515 @ background-color:#eee;
516 @ border:1px solid #999;
517 @ width:8em;
518 @ }
519 @
520 @ /* Main menu is now a list */
521 @ div.mainmenu ul {
522 @ padding: 0;
523 @ list-style:none;
524 @ }
525 @ div.mainmenu a, div.mainmenu a:visited{
526 @ padding: 1px 10px 1px 10px;
527 @ color: #333;
528 @ text-decoration: none;
529 @ }
530 @ div.mainmenu a:hover {
531 @ color: #eee;
532 @ background-color: #333;
533 @ }
534 @
535 @ /* Container for the sub-menu and content so they don''t spread
536 @ ** out underneath the main menu */
537 @ #container {
538 @ padding-left: 9em;
539 @ }
540 @
541 @ /* The submenu bar that *sometimes* appears below the main menu */
542 @ div.submenu, div.sectionmenu {
543 @ padding: 3px 10px 3px 10px;
544 @ font-size: 0.9em;
545 @ text-align: center;
546 @ border:1px solid #999;
547 @ border-width:1px 0px;
548 @ background-color: #eee;
549 @ color: #333;
550 @ }
551 @ div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link,
552 @ div.sectionmenu>a.button:visited {
553 @ padding: 3px 10px 3px 10px;
554 @ color: #333;
555 @ text-decoration: none;
556 @ }
557 @ div.submenu a:hover, div.sectionmenu>a.button:hover {
558 @ color: #eee;
559 @ background-color: #333;
560 @ }
561 @
562 @ /* All page content from the bottom of the menu or submenu down to
563 @ ** the footer */
564 @ div.content {
565 @ padding: 2ex 1ex 0ex 2ex;
566 @ }
567 @
568 @ /* Some pages have section dividers */
569 @ div.section {
570 @ margin-bottom: 0px;
571 @ margin-top: 1em;
572 @ padding: 1px 1px 1px 1px;
573 @ font-size: 1.2em;
574 @ font-weight: bold;
575 @ border-style:solid;
576 @ border-color:#999;
577 @ border-width:1px 0px;
578 @ background-color: #eee;
579 @ color: #333;
580 @ white-space: nowrap;
581 @ }
582 @
583 @ /* The "Date" that occurs on the left hand side of timelines */
584 @ div.divider {
585 @ background: #eee;
586 @ border: 2px #999 solid;
587 @ font-size: 1em; font-weight: normal;
588 @ padding: .25em;
589 @ margin: .2em 0 .2em 0;
590 @ float: left;
591 @ clear: left;
592 @ color: #333;
593 @ white-space: nowrap;
594 @ }
595 @
596 @ /* The footer at the very bottom of the page */
597 @ div.footer {
598 @ font-size: 0.8em;
599 @ margin-top: 12px;
600 @ padding: 5px 10px 5px 10px;
601 @ text-align: right;
602 @ background-color: #eee;
603 @ color: #555;
604 @ }
605 @
606 @ /* <verbatim> blocks */
607 @ pre.verbatim {
608 @ background-color: #f5f5f5;
609 @ padding: 0.5em;
610 @ white-space: pre-wrap;
611 @ }
612 @
613 @ /* The label/value pairs on (for example) the ci page */
614 @ table.label-value th {
615 @ vertical-align: top;
616 @ text-align: right;
617 @ padding: 0.2ex 2ex;
618 @ }');
619 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
620 @ <head>
621 @ <base href="$baseurl/$current_page" />
622 @ <title>$<project_name>: $<title></title>
623 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
624 @ href="$home/timeline.rss">
625 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
626 @ media="screen">
627 @ </head>
628 @ <body>
629 @ <div class="header">
630 @ <div class="logo">
631 @ <img src="$logo_image_url" alt="logo">
632 @ <br />$<project_name>
633 @ </div>
634 @ <div class="title">$<title></div>
635 @ <div class="status"><th1>
636 @ if {[info exists login]} {
637 @ puts "Logged in as $login"
638 @ } else {
639 @ puts "Not logged in"
640 @ }
641 @ </th1></div>
642 @ </div>
643 @ <div class="mainmenu">
644 @ <th1>
645 @ html "<a href=''$home$index_page''>Home</a>\n"
646 @ if {[anycap jor]} {
647 @ html "<a href=''$home/timeline''>Timeline</a>\n"
648 @ }
649 @ if {[hascap oh]} {
650 @ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
651 @ }
652 @ if {[hascap o]} {
653 @ html "<a href=''$home/brlist''>Branches</a>\n"
654 @ html "<a href=''$home/taglist''>Tags</a>\n"
655 @ }
656 @ if {[hascap r]} {
657 @ html "<a href=''$home/reportlist''>Tickets</a>\n"
658 @ }
659 @ if {[hascap j]} {
660 @ html "<a href=''$home/wiki''>Wiki</a>\n"
661 @ }
662 @ if {[hascap s]} {
663 @ html "<a href=''$home/setup''>Admin</a>\n"
664 @ } elseif {[hascap a]} {
665 @ html "<a href=''$home/setup_ulist''>Users</a>\n"
666 @ }
667 @ if {[info exists login]} {
668 @ html "<a href=''$home/login''>Logout</a>\n"
669 @ } else {
670 @ html "<a href=''$home/login''>Login</a>\n"
671 @ }
672 @ </th1></ul></div>
673 @ <div id="container">
674 @ ');
675 @ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div>
676 @ <div class="footer">
677 @ Fossil version $manifest_version $manifest_date
678 @ </div>
679 @ </body></html>
680 @ ');
681 ;
682
683
684 /*
685 ** Shadow boxes and rounded corners.
686 */
687 static const char zBuiltinSkin4[] =
688 @ REPLACE INTO config(name,mtime,value)
689 @ VALUES('css',now(),'/* General settings for the entire page */
690 @ html {
691 @ min-height: 100%;
692 @ }
693 @ body {
694 @ margin: 0ex 1ex;
695 @ padding: 0px;
696 @ background-color: white;
697 @ color: #333;
698 @ font-family: Verdana, sans-serif;
699 @ font-size: 0.8em;
700 @ }
701 @
702 @ /* The project logo in the upper left-hand corner of each page */
703 @ div.logo {
704 @ display: table-cell;
705 @ text-align: right;
706 @ vertical-align: bottom;
707 @ font-weight: normal;
708 @ white-space: nowrap;
709 @ }
710 @
711 @ /* Widths */
712 @ div.header, div.mainmenu, div.submenu, div.content, div.footer {
713 @ max-width: 900px;
714 @ margin: auto;
715 @ padding: 3px 20px 3px 20px;
716 @ clear: both;
717 @ }
718 @
719 @ /* The page title at the top of each page */
720 @ div.title {
721 @ display: table-cell;
722 @ padding-left: 10px;
723 @ font-size: 2em;
724 @ margin: 10px 0 10px -20px;
725 @ vertical-align: bottom;
726 @ text-align: left;
727 @ width: 80%;
728 @ font-family: Verdana, sans-serif;
729 @ font-weight: bold;
730 @ color: #558195;
731 @ text-shadow: 0px 2px 2px #999999;
732 @ }
733 @
734 @ /* The login status message in the top right-hand corner */
735 @ div.status {
736 @ display: table-cell;
737 @ text-align: right;
738 @ vertical-align: bottom;
739 @ color: #333;
740 @ margin-right: -20px;
741 @ white-space: nowrap;
742 @ }
743 @
744 @ /* The main menu bar that appears at the top of the page beneath
745 @ ** the header */
746 @ div.mainmenu {
747 @ text-align: center;
748 @ color: white;
749 @ border-top-left-radius: 5px;
750 @ border-top-right-radius: 5px;
751 @ vertical-align: middle;
752 @ padding-top: 8px;
753 @ padding-bottom: 8px;
754 @ background-color: #446979;
755 @ box-shadow: 0px 3px 4px #333333;
756 @ }
757 @
758 @ /* The submenu bar that *sometimes* appears below the main menu */
759 @ div.submenu {
760 @ padding-top:10px;
761 @ padding-bottom:0;
762 @ text-align: right;
763 @ color: #000;
764 @ background-color: #fff;
765 @ height: 1.5em;
766 @ vertical-align:middle;
767 @ box-shadow: 0px 3px 4px #999;
768 @ }
769 @ div.mainmenu a, div.mainmenu a:visited {
770 @ padding: 3px 10px 3px 10px;
771 @ color: white;
772 @ text-decoration: none;
773 @ }
774 @ div.submenu a, div.submenu a:visited, a.button,
775 @ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
776 @ padding: 2px 8px;
777 @ color: #000;
778 @ font-family: Arial;
779 @ text-decoration: none;
780 @ margin:auto;
781 @ border-radius: 5px;
782 @ background-color: #e0e0e0;
783 @ text-shadow: 0px -1px 0px #eee;
784 @ border: 1px solid #000;
785 @ }
786 @
787 @ div.mainmenu a:hover {
788 @ color: #000;
789 @ background-color: white;
790 @ }
791 @
792 @ div.submenu a:hover, div.sectionmenu>a.button:hover {
793 @ background-color: #c0c0c0;
794 @ }
795 @
796 @ /* All page content from the bottom of the menu or submenu down to
797 @ ** the footer */
798 @ div.content {
799 @ background-color: #fff;
800 @ box-shadow: 0px 3px 4px #999;
801 @ border-bottom-right-radius: 5px;
802 @ border-bottom-left-radius: 5px;
803 @ padding-bottom: 1em;
804 @ min-height:40%;
805 @ }
806 @
807 @
808 @ /* Some pages have section dividers */
809 @ div.section {
810 @ margin-bottom: 0.5em;
811 @ margin-top: 1em;
812 @ margin-right: auto;
813 @ padding: 1px 1px 1px 1px;
814 @ font-size: 1.2em;
815 @ font-weight: bold;
816 @ text-align: center;
817 @ color: white;
818 @ border-radius: 5px;
819 @ background-color: #446979;
820 @ box-shadow: 0px 3px 4px #333333;
821 @ white-space: nowrap;
822 @ }
823 @
824 @ /* The "Date" that occurs on the left hand side of timelines */
825 @ div.divider {
826 @ font-size: 1.2em;
827 @ font-family: Georgia, serif;
828 @ font-weight: bold;
829 @ margin-top: 1em;
830 @ white-space: nowrap;
831 @ }
832 @
833 @ /* The footer at the very bottom of the page */
834 @ div.footer {
835 @ font-size: 0.9em;
836 @ text-align: right;
837 @ margin-bottom: 1em;
838 @ color: #666;
839 @ }
840 @
841 @ /* Hyperlink colors in the footer */
842 @ div.footer a { color: white; }
843 @ div.footer a:link { color: white; }
844 @ div.footer a:visited { color: white; }
845 @ div.footer a:hover { background-color: white; color: #558195; }
846 @
847 @ /* <verbatim> blocks */
848 @ pre.verbatim, blockquote pre {
849 @ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
850 @ background-color: #f3f3f3;
851 @ padding: 0.5em;
852 @ white-space: pre-wrap;
853 @ }
854 @
855 @ blockquote pre {
856 @ border: 1px #000 dashed;
857 @ }
858 @
859 @ /* The label/value pairs on (for example) the ci page */
860 @ table.label-value th {
861 @ vertical-align: top;
862 @ text-align: right;
863 @ padding: 0.2ex 2ex;
864 @ }
865 @
866 @ table.report tr th {
867 @ padding: 3px 5px;
868 @ text-transform: capitalize;
869 @ cursor: pointer;
870 @ }
871 @
872 @ table.report tr td {
873 @ padding: 3px 5px;
874 @ cursor: pointer;
875 @ }
876 @
877 @ textarea {
878 @ font-size: 1em;
879 @ }
880 @
881 @ .fullsize-text {
882 @ font-size: 1.25em;
883 @ }');
884 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
885 @ <head>
886 @ <base href="$baseurl/$current_page" />
887 @ <title>$<project_name>: $<title></title>
888 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
889 @ href="$home/timeline.rss">
890 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
891 @ media="screen">
892 @ </head>
893 @ <body>
894 @ <div class="header">
895 @ <div class="logo">
896 @ <img src="$logo_image_url" alt="logo">
897 @ <br />$<project_name>
898 @ </div>
899 @ <div class="title">$<title></div>
900 @ <div class="status"><th1>
901 @ if {[info exists login]} {
902 @ puts "Logged in as $login"
903 @ } else {
904 @ puts "Not logged in"
905 @ }
906 @ </th1></div>
907 @ </div>
908 @ <div class="mainmenu">
909 @ <th1>
910 @ html "<a href=''$home$index_page''>Home</a>\n"
911 @ if {[anycap jor]} {
912 @ html "<a href=''$home/timeline''>Timeline</a>\n"
913 @ }
914 @ if {[hascap oh]} {
915 @ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
916 @ }
917 @ if {[hascap o]} {
918 @ html "<a href=''$home/brlist''>Branches</a>\n"
919 @ html "<a href=''$home/taglist''>Tags</a>\n"
920 @ }
921 @ if {[hascap r]} {
922 @ html "<a href=''$home/reportlist''>Tickets</a>\n"
923 @ }
924 @ if {[hascap j]} {
925 @ html "<a href=''$home/wiki''>Wiki</a>\n"
926 @ }
927 @ if {[hascap s]} {
928 @ html "<a href=''$home/setup''>Admin</a>\n"
929 @ } elseif {[hascap a]} {
930 @ html "<a href=''$home/setup_ulist''>Users</a>\n"
931 @ }
932 @ if {[info exists login]} {
933 @ html "<a href=''$home/login''>Logout</a>\n"
934 @ } else {
935 @ html "<a href=''$home/login''>Login</a>\n"
936 @ }
937 @ </th1></div>
938 @ <div id="container">
939 @ ');
940 @ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div>
941 @ <div class="footer">
942 @ Fossil version $manifest_version $manifest_date
943 @ </div>
944 @ </body></html>
945 @ ');
946 ;
947
948
949 /*
950 ** This skin is intended to be almost identical to the default one, with the
951 ** following changes to the header and footer:
952 **
953 ** 1. The logo image in the header has been modified to be a hyperlink to the
954 ** root of the web site containing the repository using the same scheme
955 ** (i.e. HTTP or HTTPS) as the base URL for the repository. The header
956 ** contains a TH1 script block to help accomplish these tasks.
957 **
958 ** 2. The Fossil version information in the footer has been augmented with
959 ** hyperlinks to the corresponding points on the timeline in the official
960 ** Fossil repository. Additionally, if the Tcl integration feature is
961 ** enabled, the loaded version of Tcl is included, with a hyperlink to the
962 ** official Tcl/Tk web site. The footer also contains a TH1 script block
963 ** to help accomplish these tasks.
964 */
965 static const char zBuiltinSkin5[] =
966 @ REPLACE INTO config(name,mtime,value)
967 @ VALUES('css',now(),'/* General settings for the entire page */
968 @ body {
969 @ margin: 0ex 1ex;
970 @ padding: 0px;
971 @ background-color: white;
972 @ font-family: sans-serif;
973 @ }
974 @
975 @ /* The project logo in the upper left-hand corner of each page */
976 @ div.logo {
977 @ display: table-cell;
978 @ text-align: center;
979 @ vertical-align: bottom;
980 @ font-weight: bold;
981 @ color: #558195;
982 @ min-width: 200px;
983 @ white-space: nowrap;
984 @ }
985 @
986 @ /* The page title centered at the top of each page */
987 @ div.title {
988 @ display: table-cell;
989 @ font-size: 2em;
990 @ font-weight: bold;
991 @ text-align: center;
992 @ padding: 0 0 0 1em;
993 @ color: #558195;
994 @ vertical-align: bottom;
995 @ width: 100%;
996 @ }
997 @
998 @ /* The login status message in the top right-hand corner */
999 @ div.status {
1000 @ display: table-cell;
1001 @ text-align: right;
1002 @ vertical-align: bottom;
1003 @ color: #558195;
1004 @ font-size: 0.8em;
1005 @ font-weight: bold;
1006 @ min-width: 200px;
1007 @ white-space: nowrap;
1008 @ }
1009 @
1010 @ /* The header across the top of the page */
1011 @ div.header {
1012 @ display: table;
1013 @ width: 100%;
1014 @ }
1015 @
1016 @ /* The main menu bar that appears at the top of the page beneath
1017 @ ** the header */
1018 @ div.mainmenu {
1019 @ padding: 5px 10px 5px 10px;
1020 @ font-size: 0.9em;
1021 @ font-weight: bold;
1022 @ text-align: center;
1023 @ letter-spacing: 1px;
1024 @ background-color: #558195;
1025 @ border-top-left-radius: 8px;
1026 @ border-top-right-radius: 8px;
1027 @ color: white;
1028 @ }
1029 @
1030 @ /* The submenu bar that *sometimes* appears below the main menu */
1031 @ div.submenu, div.sectionmenu {
1032 @ padding: 3px 10px 3px 0px;
1033 @ font-size: 0.9em;
1034 @ text-align: center;
1035 @ background-color: #456878;
1036 @ color: white;
1037 @ }
1038 @ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
1039 @ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
1040 @ padding: 3px 10px 3px 10px;
1041 @ color: white;
1042 @ text-decoration: none;
1043 @ }
1044 @ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
1045 @ color: #558195;
1046 @ background-color: white;
1047 @ }
1048 @
1049 @ /* All page content from the bottom of the menu or submenu down to
1050 @ ** the footer */
1051 @ div.content {
1052 @ padding: 0ex 1ex 1ex 1ex;
1053 @ border: solid #aaa;
1054 @ border-width: 1px;
1055 @ }
1056 @
1057 @ /* Some pages have section dividers */
1058 @ div.section {
1059 @ margin-bottom: 0px;
1060 @ margin-top: 1em;
1061 @ padding: 1px 1px 1px 1px;
1062 @ font-size: 1.2em;
1063 @ font-weight: bold;
1064 @ background-color: #558195;
1065 @ color: white;
1066 @ white-space: nowrap;
1067 @ }
1068 @
1069 @ /* The "Date" that occurs on the left hand side of timelines */
1070 @ div.divider {
1071 @ background: #a1c4d4;
1072 @ border: 2px #558195 solid;
1073 @ font-size: 1em; font-weight: normal;
1074 @ padding: .25em;
1075 @ margin: .2em 0 .2em 0;
1076 @ float: left;
1077 @ clear: left;
1078 @ white-space: nowrap;
1079 @ }
1080 @
1081 @ /* The footer at the very bottom of the page */
1082 @ div.footer {
1083 @ clear: both;
1084 @ font-size: 0.8em;
1085 @ padding: 5px 10px 5px 10px;
1086 @ text-align: right;
1087 @ background-color: #558195;
1088 @ border-bottom-left-radius: 8px;
1089 @ border-bottom-right-radius: 8px;
1090 @ color: white;
1091 @ }
1092 @
1093 @ /* Hyperlink colors in the footer */
1094 @ div.footer a { color: white; }
1095 @ div.footer a:link { color: white; }
1096 @ div.footer a:visited { color: white; }
1097 @ div.footer a:hover { background-color: white; color: #558195; }
1098 @
1099 @ /* verbatim blocks */
1100 @ pre.verbatim {
1101 @ background-color: #f5f5f5;
1102 @ padding: 0.5em;
1103 @ white-space: pre-wrap;
1104 @ }
1105 @
1106 @ /* The label/value pairs on (for example) the ci page */
1107 @ table.label-value th {
1108 @ vertical-align: top;
1109 @ text-align: right;
1110 @ padding: 0.2ex 2ex;
1111 @ }');
1112 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
1113 @ <head>
1114 @ <base href="$baseurl/$current_page" />
1115 @ <title>$<project_name>: $<title></title>
1116 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
1117 @ href="$home/timeline.rss" />
1118 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
1119 @ media="screen" />
1120 @ </head>
1121 @ <body>
1122 @ <div class="header">
1123 @ <div class="logo">
1124 @ <th1>
1125 @ ##
1126 @ ## NOTE: The purpose of this procedure is to take the base URL of the
1127 @ ## Fossil project and return the root of the entire web site using
1128 @ ## the same URI scheme as the base URL (e.g. http or https).
1129 @ ##
1130 @ proc getLogoUrl { baseurl } {
1131 @ set idx(first) [string first // $baseurl]
1132 @ if {$idx(first) != -1} {
1133 @ ##
1134 @ ## NOTE: Skip second slash.
1135 @ ##
1136 @ set idx(first+1) [expr {$idx(first) + 2}]
1137 @ ##
1138 @ ## NOTE: (part 1) The [string first] command does NOT actually
1139 @ ## the optional startIndex argument as specified in the
1140 @ ## TH1 support manual; therefore, we fake it by using the
1141 @ ## [string range] command and then adding the necessary
1142 @ ## offset to the resulting index manually (below). In Tcl,
1143 @ ## we could use the following instead:
1144 @ ##
1145 @ ## set idx(next) [string first / $baseurl $idx(first+1)]
1146 @ ##
1147 @ set idx(nextRange) [string range $baseurl $idx(first+1) end]
1148 @ set idx(next) [string first / $idx(nextRange)]
1149 @ if {$idx(next) != -1} {
1150 @ ##
1151 @ ## NOTE: (part 2) Add the necessary offset to the result of the
1152 @ ## search for the next slash (i.e. the one after the initial
1153 @ ## search for the two slashes).
1154 @ ##
1155 @ set idx(next) [expr {$idx(next) + $idx(first+1)}]
1156 @ ##
1157 @ ## NOTE: Back up one character from the next slash.
1158 @ ##
1159 @ set idx(next-1) [expr {$idx(next) - 1}]
1160 @ ##
1161 @ ## NOTE: Extract the URI scheme and host from the base URL.
1162 @ ##
1163 @ set scheme [string range $baseurl 0 $idx(first)]
1164 @ set host [string range $baseurl $idx(first+1) $idx(next-1)]
1165 @ ##
1166 @ ## NOTE: Try to stay in SSL mode if we are there now.
1167 @ ##
1168 @ if {[string compare $scheme http:/] == 0} {
1169 @ set scheme http://
1170 @ } else {
1171 @ set scheme https://
1172 @ }
1173 @ set logourl $scheme$host/
1174 @ } else {
1175 @ set logourl $baseurl
1176 @ }
1177 @ } else {
1178 @ set logourl $baseurl
1179 @ }
1180 @ return $logourl
1181 @ }
1182 @ set logourl [getLogoUrl $baseurl]
1183 @ </th1>
1184 @ <a href="$logourl">
1185 @ <img src="$logo_image_url" border="0" alt="$project_name">
1186 @ </a>
1187 @ </div>
1188 @ <div class="title"><small>$<project_name></small><br />$<title></div>
1189 @ <div class="status"><th1>
1190 @ if {[info exists login]} {
1191 @ puts "Logged in as $login"
1192 @ } else {
1193 @ puts "Not logged in"
1194 @ }
1195 @ </th1></div>
1196 @ </div>
1197 @ <div class="mainmenu">
1198 @ <th1>
1199 @ html "<a href=''$home$index_page''>Home</a>\n"
1200 @ if {[anycap jor]} {
1201 @ html "<a href=''$home/timeline''>Timeline</a>\n"
1202 @ }
1203 @ if {[hascap oh]} {
1204 @ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
1205 @ }
1206 @ if {[hascap o]} {
1207 @ html "<a href=''$home/brlist''>Branches</a>\n"
1208 @ html "<a href=''$home/taglist''>Tags</a>\n"
1209 @ }
1210 @ if {[hascap r]} {
1211 @ html "<a href=''$home/reportlist''>Tickets</a>\n"
1212 @ }
1213 @ if {[hascap j]} {
1214 @ html "<a href=''$home/wiki''>Wiki</a>\n"
1215 @ }
1216 @ if {[hascap s]} {
1217 @ html "<a href=''$home/setup''>Admin</a>\n"
1218 @ } elseif {[hascap a]} {
1219 @ html "<a href=''$home/setup_ulist''>Users</a>\n"
1220 @ }
1221 @ if {[info exists login]} {
1222 @ html "<a href=''$home/login''>Logout</a>\n"
1223 @ } else {
1224 @ html "<a href=''$home/login''>Login</a>\n"
1225 @ }
1226 @ </th1></div>
1227 @ ');
1228 @ REPLACE INTO config(name,mtime,value)
1229 @ VALUES('footer',now(),'<div class="footer">
1230 @ <th1>
1231 @ proc getTclVersion {} {
1232 @ if {[catch {tclEval info patchlevel} tclVersion] == 0} {
1233 @ return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
1234 @ }
1235 @ return ""
1236 @ }
1237 @ proc getVersion { version } {
1238 @ set length [string length $version]
1239 @ return [string range $version 1 [expr {$length - 2}]]
1240 @ }
1241 @ set version [getVersion $manifest_version]
1242 @ set tclVersion [getTclVersion]
1243 @ set fossilUrl http://www.fossil-scm.org
1244 @ </th1>
1245 @ This page was generated in about
1246 @ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
1247 @ <a href="$fossilUrl/">Fossil</a>
1248 @ version $release_version $tclVersion
1249 @ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
1250 @ <a href="$fossilUrl/index.html/timeline?c=$manifest_date&amp;y=ci">$manifest_date</a>
1251 @ </div>
1252 @ </body></html>
1253 @ ');
1254 ;
1255
1256 /*
1257 ** An array of available built-in skins.
 
 
 
 
 
 
 
 
 
 
 
 
1258 */
1259 static struct BuiltinSkin {
1260 const char *zName;
1261 const char *zValue;
 
1262 } aBuiltinSkin[] = {
1263 { "Default", 0 /* Filled in at runtime */ },
1264 { "Plain Gray, No Logo", zBuiltinSkin1 },
1265 { "Khaki, No Logo", zBuiltinSkin2 },
1266 { "Black & White, Menu on Left", zBuiltinSkin3 },
1267 { "Shadow boxes & Rounded Corners", zBuiltinSkin4 },
1268 { "Enhanced Default", zBuiltinSkin5 },
 
 
1269 };
1270
1271 /*
1272 ** For a skin named zSkinName, compute the name of the CONFIG table
1273 ** entry where that skin is stored and return it.
@@ -1286,57 +69,158 @@
1286 }
1287 return z;
1288 }
1289
1290 /*
1291 ** Construct and return a string that represents the current skin if
1292 ** useDefault==0 or a string for the default skin if useDefault==1.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1293 **
1294 ** Memory to hold the returned string is obtained from malloc.
1295 */
1296 static char *getSkin(int useDefault){
 
 
 
 
1297 Blob val;
1298 blob_zero(&val);
1299 blob_appendf(&val,
1300 "REPLACE INTO config(name,value,mtime) VALUES('css',%Q,now());\n",
1301 useDefault ? zDefaultCSS : db_get("css", (char*)zDefaultCSS)
1302 );
1303 blob_appendf(&val,
1304 "REPLACE INTO config(name,value,mtime) VALUES('header',%Q,now());\n",
1305 useDefault ? zDefaultHeader : db_get("header", (char*)zDefaultHeader)
1306 );
1307 blob_appendf(&val,
1308 "REPLACE INTO config(name,value,mtime) VALUES('footer',%Q,now());\n",
1309 useDefault ? zDefaultFooter : db_get("footer", (char*)zDefaultFooter)
1310 );
 
 
 
 
 
 
1311 return blob_str(&val);
1312 }
1313
1314 /*
1315 ** Construct the default skin string and fill in the corresponding
1316 ** entry in aBuildinSkin[]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1317 */
1318 static void setDefaultSkin(void){
1319 aBuiltinSkin[0].zValue = getSkin(1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1320 }
1321
1322 /*
1323 ** WEBPAGE: setup_skin
1324 */
1325 void setup_skin(void){
1326 const char *z;
1327 char *zName;
1328 char *zErr = 0;
1329 const char *zCurrent; /* Current skin */
1330 int i; /* Loop counter */
1331 Stmt q;
 
1332
1333 login_check_credentials();
1334 if( !g.perm.Setup ){
1335 login_needed();
1336 }
1337 db_begin_transaction();
 
 
 
 
1338
1339 /* Process requests to delete a user-defined skin */
1340 if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
1341 style_header("Confirm Custom Skin Delete");
1342 @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
@@ -1351,51 +235,42 @@
1351 return;
1352 }
1353 if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
1354 db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
1355 }
1356
1357 setDefaultSkin();
1358 zCurrent = getSkin(0);
1359
1360 if( P("save")!=0 && (zName = skinVarName(P("save"),0))!=0 ){
1361 if( db_exists("SELECT 1 FROM config WHERE name=%Q", zName)
1362 || fossil_strcmp(zName, "Default")==0 ){
1363 zErr = mprintf("Skin name \"%h\" already exists. "
1364 "Choose a different name.", P("sn"));
1365 }else{
1366 db_multi_exec("INSERT INTO config(name,value,mtime) VALUES(%Q,%Q,now())",
1367 zName, zCurrent
1368 );
1369 }
1370 }
1371
1372 /* The user pressed the "Use This Skin" button. */
1373 if( P("load") && (z = P("sn"))!=0 && z[0] ){
1374 int seen = 0;
 
 
 
 
1375 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
1376 if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
1377 seen = 1;
1378 break;
1379 }
1380 }
1381 if( !seen ){
1382 seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
1383 " AND value=%Q", zCurrent);
1384 }
1385 if( !seen ){
1386 db_multi_exec(
1387 "INSERT INTO config(name,value,mtime) VALUES("
1388 " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
1389 " %Q,now())", zCurrent
1390 );
1391 }
1392 seen = 0;
1393 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
1394 if( fossil_strcmp(aBuiltinSkin[i].zName, z)==0 ){
1395 seen = 1;
1396 zCurrent = aBuiltinSkin[i].zValue;
1397 db_multi_exec("%s", zCurrent/*safe-for-%s*/);
1398 break;
1399 }
1400 }
1401 if( !seen ){
@@ -1409,48 +284,59 @@
1409 if( zErr ){
1410 @ <p><font color="red">%h(zErr)</font></p>
1411 }
1412 @ <p>A "skin" is a combination of
1413 @ <a href="setup_editcss">CSS</a>,
1414 @ <a href="setup_header">Header</a>,
1415 @ <a href="setup_footer">Footer</a>, and
1416 @ <a href="setup_logo">Logo</a> that determines the look and feel
1417 @ of the web interface.</p>
1418 @
1419 @ <h2>Available Skins:</h2>
1420 @ <ol>
1421 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
1422 z = aBuiltinSkin[i].zName;
1423 if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
1424 @ <li><p>%h(z).&nbsp;&nbsp; <b>Currently In Use</b></p>
 
 
1425 }else{
1426 @ <li><form action="%s(g.zTop)/setup_skin" method="post"><div>
1427 @ %h(z).&nbsp;&nbsp;
1428 @ <input type="hidden" name="sn" value="%h(z)" />
1429 @ <input type="submit" name="load" value="Use This Skin" />
1430 @ </div></form></li>
1431 }
 
1432 }
1433 db_prepare(&q,
1434 "SELECT substr(name, 6), value FROM config"
1435 " WHERE name GLOB 'skin:*'"
1436 " ORDER BY name"
1437 );
1438 while( db_step(&q)==SQLITE_ROW ){
1439 const char *zN = db_column_text(&q, 0);
1440 const char *zV = db_column_text(&q, 1);
1441 if( fossil_strcmp(zV, zCurrent)==0 ){
1442 @ <li><p>%h(zN).&nbsp;&nbsp; <b>Currently In Use</b></p>
1443 }else{
1444 @ <li><form action="%s(g.zTop)/setup_skin" method="post">
1445 @ %h(zN).&nbsp;&nbsp;
1446 @ <input type="hidden" name="sn" value="%h(zN)">
1447 @ <input type="submit" name="load" value="Use This Skin">
1448 @ <input type="submit" name="del1" value="Delete This Skin">
1449 @ </form></li>
1450 }
 
 
 
1451 }
1452 db_finalize(&q);
1453 @ </ol>
 
 
 
 
 
 
 
1454 style_footer();
1455 db_end_transaction(0);
1456 }
1457
--- src/skins.c
+++ src/skins.c
@@ -19,1255 +19,38 @@
19 */
20 #include "config.h"
21 #include <assert.h>
22 #include "skins.h"
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24 /*
25 ** An array of available built-in skins.
26 **
27 ** To add new built-in skins:
28 **
29 ** 1. Pick a name for the new skin. (Here we use "xyzzy").
30 **
31 ** 2. Install files skins/xyzzy/css.txt, skins/xyzzy/header.txt,
32 ** and skins/xyzzy/footer.txt into the source tree.
33 **
34 ** 3. Rerun "tclsh makemake.tcl" in the src/ folder in order to
35 ** rebuild the makefiles to reference the new CSS, headers, and footers.
36 **
37 ** 4. Make an entry in the following array for the new skin.
38 */
39 static struct BuiltinSkin {
40 const char *zDesc; /* Description of this skin */
41 const char *zLabel; /* The directory under skins/ holding this skin */
42 char *zSQL; /* Filled in at run-time with SQL to insert this skin */
43 } aBuiltinSkin[] = {
44 { "Default", "default", 0 },
45 { "Plain Gray, No Logo", "plain_gray", 0 },
46 { "Khaki, No Logo", "khaki", 0 },
47 { "Black & White, Menu on Left", "black_and_white", 0 },
48 { "Shadow boxes & Rounded Corners", "rounded1", 0 },
49 { "Enhanced Default", "enhanced1", 0 },
50 { "San Francisco Modern", "etienne1", 0 },
51 { "Eagle", "eagle", 0 },
52 };
53
54 /*
55 ** For a skin named zSkinName, compute the name of the CONFIG table
56 ** entry where that skin is stored and return it.
@@ -1286,57 +69,158 @@
69 }
70 return z;
71 }
72
73 /*
74 ** Return true if there exists a skin name "zSkinName".
75 */
76 static int skinExists(const char *zSkinName){
77 int i;
78 if( zSkinName==0 ) return 0;
79 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
80 if( fossil_strcmp(zSkinName, aBuiltinSkin[i].zDesc)==0 ) return 1;
81 }
82 return db_exists("SELECT 1 FROM config WHERE name='skin:%q'", zSkinName);
83 }
84
85 /*
86 ** Construct and return an string of SQL statements that represents
87 ** a "skin" setting. If zName==0 then return the skin currently
88 ** installed. Otherwise, return one of the built-in skins designated
89 ** by zName.
90 **
91 ** Memory to hold the returned string is obtained from malloc.
92 */
93 static char *getSkin(const char *zName){
94 const char *z;
95 char *zLabel;
96 static const char *azType[] = { "css", "header", "footer" };
97 int i;
98 Blob val;
99 blob_zero(&val);
100 for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
101 if( zName ){
102 zLabel = mprintf("skins/%s/%s.txt", zName, azType[i]);
103 z = builtin_text(zLabel);
104 fossil_free(zLabel);
105 }else{
106 z = db_get(azType[i], 0);
107 if( z==0 ){
108 zLabel = mprintf("skins/default/%s.txt", azType[i]);
109 z = builtin_text(zLabel);
110 fossil_free(zLabel);
111 }
112 }
113 blob_appendf(&val,
114 "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now());\n",
115 azType[i], z
116 );
117 }
118 return blob_str(&val);
119 }
120
121 /*
122 ** Respond to a Rename button press. Return TRUE if a dialog was painted.
123 ** Return FALSE to continue with the main Skins page.
124 */
125 static int skinRename(void){
126 const char *zOldName;
127 const char *zNewName;
128 int ex = 0;
129 if( P("rename")==0 ) return 0;
130 zOldName = P("sn");
131 zNewName = P("newname");
132 if( zOldName==0 ) return 0;
133 if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){
134 if( zNewName==0 ) zNewName = zOldName;
135 style_header("Rename A Skin");
136 if( ex ){
137 @ <p><span class="generalError">There is already another skin
138 @ named "%h(zNewName)". Choose a different name.</span></p>
139 }
140 @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
141 @ <table border="0"><tr>
142 @ <tr><td align="right">Current name:<td align="left"><b>%h(zOldName)</b>
143 @ <tr><td align="right">New name:<td align="left">
144 @ <input type="text" size="35" name="newname" value="%h(zNewName)">
145 @ <tr><td><td>
146 @ <input type="hidden" name="sn" value="%h(zOldName)">
147 @ <input type="submit" name="rename" value="Rename">
148 @ <input type="submit" name="canren" value="Cancel">
149 @ </table>
150 login_insert_csrf_secret();
151 @ </div></form>
152 style_footer();
153 return 1;
154 }
155 db_multi_exec(
156 "UPDATE config SET name='skin:%q' WHERE name='skin:%q';",
157 zNewName, zOldName
158 );
159 return 0;
160 }
161
162 /*
163 ** Respond to a Save button press. Return TRUE if a dialog was painted.
164 ** Return FALSE to continue with the main Skins page.
165 */
166 static int skinSave(const char *zCurrent){
167 const char *zNewName;
168 int ex = 0;
169 if( P("save")==0 ) return 0;
170 zNewName = P("svname");
171 if( zNewName && zNewName[0]!=0 ){
172 }
173 if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){
174 if( zNewName==0 ) zNewName = "";
175 style_header("Save Current Skin");
176 if( ex ){
177 @ <p><span class="generalError">There is already another skin
178 @ named "%h(zNewName)". Choose a different name.</span></p>
179 }
180 @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
181 @ <table border="0"><tr>
182 @ <tr><td align="right">Name for this skin:<td align="left">
183 @ <input type="text" size="35" name="svname" value="%h(zNewName)">
184 @ <tr><td><td>
185 @ <input type="submit" name="save" value="Save">
186 @ <input type="submit" name="cansave" value="Cancel">
187 @ </table>
188 login_insert_csrf_secret();
189 @ </div></form>
190 style_footer();
191 return 1;
192 }
193 db_multi_exec(
194 "INSERT OR IGNORE INTO config(name, value, mtime)"
195 "VALUES('skin:%q',%Q,now())",
196 zNewName, zCurrent
197 );
198 return 0;
199 }
200
201 /*
202 ** WEBPAGE: setup_skin
203 */
204 void setup_skin(void){
205 const char *z;
206 char *zName;
207 char *zErr = 0;
208 const char *zCurrent = 0; /* Current skin */
209 int i; /* Loop counter */
210 Stmt q;
211 int seenCurrent = 0;
212
213 login_check_credentials();
214 if( !g.perm.Setup ){
215 login_needed();
216 }
217 db_begin_transaction();
218 zCurrent = getSkin(0);
219 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
220 aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
221 }
222
223 /* Process requests to delete a user-defined skin */
224 if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
225 style_header("Confirm Custom Skin Delete");
226 @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
@@ -1351,51 +235,42 @@
235 return;
236 }
237 if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
238 db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
239 }
240 if( skinRename() ) return;
241 if( skinSave(zCurrent) ) return;
242
243 /* The user pressed one of the "Install" buttons. */
 
 
 
 
 
 
 
 
 
 
 
 
 
244 if( P("load") && (z = P("sn"))!=0 && z[0] ){
245 int seen = 0;
246
247 /* Check to see if the current skin is already saved. If it is, there
248 ** is no need to create a backup */
249 zCurrent = getSkin(0);
250 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
251 if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
252 seen = 1;
253 break;
254 }
255 }
256 if( !seen ){
257 seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
258 " AND value=%Q", zCurrent);
259 if( !seen ){
260 db_multi_exec(
261 "INSERT INTO config(name,value,mtime) VALUES("
262 " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
263 " %Q,now())", zCurrent
264 );
265 }
266 }
267 seen = 0;
268 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
269 if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){
270 seen = 1;
271 zCurrent = aBuiltinSkin[i].zSQL;
272 db_multi_exec("%s", zCurrent/*safe-for-%s*/);
273 break;
274 }
275 }
276 if( !seen ){
@@ -1409,48 +284,59 @@
284 if( zErr ){
285 @ <p><font color="red">%h(zErr)</font></p>
286 }
287 @ <p>A "skin" is a combination of
288 @ <a href="setup_editcss">CSS</a>,
289 @ <a href="setup_header">Header</a>, and
290 @ <a href="setup_footer">Footer</a> that determines the look and feel
 
291 @ of the web interface.</p>
292 @
293 @ <h2>Available Skins:</h2>
294 @ <table border="0">
295 for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
296 z = aBuiltinSkin[i].zDesc;
297 @ <tr><td>%d(i+1).<td>%h(z)<td>&nbsp;&nbsp;<td>
298 if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
299 @ (Currently In Use)
300 seenCurrent = 1;
301 }else{
302 @ <form action="%s(g.zTop)/setup_skin" method="post">
 
303 @ <input type="hidden" name="sn" value="%h(z)" />
304 @ <input type="submit" name="load" value="Install" />
305 @ </form>
306 }
307 @ </tr>
308 }
309 db_prepare(&q,
310 "SELECT substr(name, 6), value FROM config"
311 " WHERE name GLOB 'skin:*'"
312 " ORDER BY name"
313 );
314 while( db_step(&q)==SQLITE_ROW ){
315 const char *zN = db_column_text(&q, 0);
316 const char *zV = db_column_text(&q, 1);
317 i++;
318 @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
319 @ <form action="%s(g.zTop)/setup_skin" method="post">
320 if( fossil_strcmp(zV, zCurrent)==0 ){
321 @ (Currently In Use)
322 seenCurrent = 1;
323 }else{
324 @ <input type="submit" name="load" value="Install">
325 @ <input type="submit" name="del1" value="Delete">
326 }
327 @ <input type="submit" name="rename" value="Rename">
328 @ <input type="hidden" name="sn" value="%h(zN)">
329 @ </form></tr>
330 }
331 db_finalize(&q);
332 if( !seenCurrent ){
333 i++;
334 @ <tr><td>%d(i).<td><i>Current Configuration</i><td>&nbsp;&nbsp;<td>
335 @ <form action="%s(g.zTop)/setup_skin" method="post">
336 @ <input type="submit" name="save" value="Save">
337 @ </form>
338 }
339 @ </table>
340 style_footer();
341 db_end_transaction(0);
342 }
343
+34 -2
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -108,11 +108,11 @@
108108
sqlite3_result_error(context, "input is not zlib compressed", -1);
109109
}
110110
}
111111
112112
/*
113
-** Add the content(), compress(), and decompress() SQL functions to
113
+** Add the content(), compress(), and decompress() SQL functions to
114114
** database connection db.
115115
*/
116116
int add_content_sql_commands(sqlite3 *db){
117117
sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
118118
sqlcmd_content, 0, 0);
@@ -132,11 +132,13 @@
132132
sqlite3 *db,
133133
const char **pzErrMsg,
134134
const void *notUsed
135135
){
136136
add_content_sql_commands(db);
137
+ db_add_aux_functions(db);
137138
re_add_sql_func(db);
139
+ search_sql_setup(db);
138140
g.zMainDbType = "repository";
139141
foci_register(db);
140142
g.repositoryOpen = 1;
141143
g.db = db;
142144
return SQLITE_OK;
@@ -147,15 +149,45 @@
147149
**
148150
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
149151
**
150152
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
151153
** If DATABASE is omitted, then the repository that serves the working
152
-** directory is opened.
154
+** directory is opened. See https://www.sqlite.org/cli.html for additional
155
+** information.
153156
**
154157
** WARNING: Careless use of this command can corrupt a Fossil repository
155158
** in ways that are unrecoverable. Be sure you know what you are doing before
156159
** running any SQL commands that modifies the repository database.
160
+**
161
+** The following extensions to the usual SQLite commands are provided:
162
+**
163
+** content(X) Return the contenxt of artifact X. X can be a
164
+** SHA1 hash or prefix or a tag.
165
+**
166
+** compress(X) Compress text X.
167
+**
168
+** decompress(X) Decompress text X. Undoes the work of
169
+** compress(X).
170
+**
171
+** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID)
172
+** found in check-in X (another BLOB.RID value).
173
+**
174
+** symbolic_name_to_rid(X) Return a the BLOB.RID corresponding to symbolic
175
+** name X.
176
+**
177
+** now() Return the number of seconds since 1970.
178
+**
179
+** REGEXP The REGEXP operator works, unlike in
180
+** standard SQLite.
181
+**
182
+** files_of_checkin The "files_of_check" virtual table is
183
+** available for decoding manifests.
184
+**
185
+** Usage example for files_of_checkin:
186
+**
187
+** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
188
+** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
157189
*/
158190
void cmd_sqlite3(void){
159191
extern int sqlite3_shell(int, char**);
160192
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
161193
db_close(1);
162194
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -108,11 +108,11 @@
108 sqlite3_result_error(context, "input is not zlib compressed", -1);
109 }
110 }
111
112 /*
113 ** Add the content(), compress(), and decompress() SQL functions to
114 ** database connection db.
115 */
116 int add_content_sql_commands(sqlite3 *db){
117 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
118 sqlcmd_content, 0, 0);
@@ -132,11 +132,13 @@
132 sqlite3 *db,
133 const char **pzErrMsg,
134 const void *notUsed
135 ){
136 add_content_sql_commands(db);
 
137 re_add_sql_func(db);
 
138 g.zMainDbType = "repository";
139 foci_register(db);
140 g.repositoryOpen = 1;
141 g.db = db;
142 return SQLITE_OK;
@@ -147,15 +149,45 @@
147 **
148 ** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
149 **
150 ** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
151 ** If DATABASE is omitted, then the repository that serves the working
152 ** directory is opened.
 
153 **
154 ** WARNING: Careless use of this command can corrupt a Fossil repository
155 ** in ways that are unrecoverable. Be sure you know what you are doing before
156 ** running any SQL commands that modifies the repository database.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157 */
158 void cmd_sqlite3(void){
159 extern int sqlite3_shell(int, char**);
160 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
161 db_close(1);
162
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -108,11 +108,11 @@
108 sqlite3_result_error(context, "input is not zlib compressed", -1);
109 }
110 }
111
112 /*
113 ** Add the content(), compress(), and decompress() SQL functions to
114 ** database connection db.
115 */
116 int add_content_sql_commands(sqlite3 *db){
117 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
118 sqlcmd_content, 0, 0);
@@ -132,11 +132,13 @@
132 sqlite3 *db,
133 const char **pzErrMsg,
134 const void *notUsed
135 ){
136 add_content_sql_commands(db);
137 db_add_aux_functions(db);
138 re_add_sql_func(db);
139 search_sql_setup(db);
140 g.zMainDbType = "repository";
141 foci_register(db);
142 g.repositoryOpen = 1;
143 g.db = db;
144 return SQLITE_OK;
@@ -147,15 +149,45 @@
149 **
150 ** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
151 **
152 ** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
153 ** If DATABASE is omitted, then the repository that serves the working
154 ** directory is opened. See https://www.sqlite.org/cli.html for additional
155 ** information.
156 **
157 ** WARNING: Careless use of this command can corrupt a Fossil repository
158 ** in ways that are unrecoverable. Be sure you know what you are doing before
159 ** running any SQL commands that modifies the repository database.
160 **
161 ** The following extensions to the usual SQLite commands are provided:
162 **
163 ** content(X) Return the contenxt of artifact X. X can be a
164 ** SHA1 hash or prefix or a tag.
165 **
166 ** compress(X) Compress text X.
167 **
168 ** decompress(X) Decompress text X. Undoes the work of
169 ** compress(X).
170 **
171 ** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID)
172 ** found in check-in X (another BLOB.RID value).
173 **
174 ** symbolic_name_to_rid(X) Return a the BLOB.RID corresponding to symbolic
175 ** name X.
176 **
177 ** now() Return the number of seconds since 1970.
178 **
179 ** REGEXP The REGEXP operator works, unlike in
180 ** standard SQLite.
181 **
182 ** files_of_checkin The "files_of_check" virtual table is
183 ** available for decoding manifests.
184 **
185 ** Usage example for files_of_checkin:
186 **
187 ** CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
188 ** SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
189 */
190 void cmd_sqlite3(void){
191 extern int sqlite3_shell(int, char**);
192 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
193 db_close(1);
194
+759 -522
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
11
/******************************************************************************
22
** This file is an amalgamation of many separate C source files from SQLite
3
-** version 3.8.8. By combining all the individual C code files into this
3
+** version 3.8.8.2. By combining all the individual C code files into this
44
** single large file, the entire code can be compiled as a single translation
55
** unit. This allows many compilers to do optimizations that would not be
66
** possible if the files were compiled separately. Performance improvements
77
** of 5% or more are commonly seen when SQLite is compiled as a single
88
** translation unit.
@@ -41,10 +41,57 @@
4141
**
4242
*/
4343
#ifndef _SQLITEINT_H_
4444
#define _SQLITEINT_H_
4545
46
+/*
47
+** Include the header file used to customize the compiler options for MSVC.
48
+** This should be done first so that it can successfully prevent spurious
49
+** compiler warnings due to subsequent content in this file and other files
50
+** that are included by this file.
51
+*/
52
+/************** Include msvc.h in the middle of sqliteInt.h ******************/
53
+/************** Begin file msvc.h ********************************************/
54
+/*
55
+** 2015 January 12
56
+**
57
+** The author disclaims copyright to this source code. In place of
58
+** a legal notice, here is a blessing:
59
+**
60
+** May you do good and not evil.
61
+** May you find forgiveness for yourself and forgive others.
62
+** May you share freely, never taking more than you give.
63
+**
64
+******************************************************************************
65
+**
66
+** This file contains code that is specific to MSVC.
67
+*/
68
+#ifndef _MSVC_H_
69
+#define _MSVC_H_
70
+
71
+#if defined(_MSC_VER)
72
+#pragma warning(disable : 4054)
73
+#pragma warning(disable : 4055)
74
+#pragma warning(disable : 4100)
75
+#pragma warning(disable : 4127)
76
+#pragma warning(disable : 4152)
77
+#pragma warning(disable : 4189)
78
+#pragma warning(disable : 4206)
79
+#pragma warning(disable : 4210)
80
+#pragma warning(disable : 4232)
81
+#pragma warning(disable : 4244)
82
+#pragma warning(disable : 4305)
83
+#pragma warning(disable : 4306)
84
+#pragma warning(disable : 4702)
85
+#pragma warning(disable : 4706)
86
+#endif /* defined(_MSC_VER) */
87
+
88
+#endif /* _MSVC_H_ */
89
+
90
+/************** End of msvc.h ************************************************/
91
+/************** Continuing where we left off in sqliteInt.h ******************/
92
+
4693
/*
4794
** These #defines should enable >2GB file support on POSIX if the
4895
** underlying operating system supports it. If the OS lacks
4996
** large file support, or if the OS is windows, these should be no-ops.
5097
**
@@ -229,13 +276,13 @@
229276
**
230277
** See also: [sqlite3_libversion()],
231278
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
232279
** [sqlite_version()] and [sqlite_source_id()].
233280
*/
234
-#define SQLITE_VERSION "3.8.8"
281
+#define SQLITE_VERSION "3.8.8.2"
235282
#define SQLITE_VERSION_NUMBER 3008008
236
-#define SQLITE_SOURCE_ID "2014-12-10 04:58:43 3528f8dd39acace8eeb7337994c8617313f4b04b"
283
+#define SQLITE_SOURCE_ID "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
237284
238285
/*
239286
** CAPI3REF: Run-Time Library Version Numbers
240287
** KEYWORDS: sqlite3_version, sqlite3_sourceid
241288
**
@@ -323,11 +370,11 @@
323370
** This interface only reports on the compile-time mutex setting
324371
** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
325372
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
326373
** can be fully or partially disabled using a call to [sqlite3_config()]
327374
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
328
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
375
+** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
329376
** sqlite3_threadsafe() function shows only the compile-time setting of
330377
** thread safety, not any run-time changes to that setting made by
331378
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
332379
** is unchanged by calls to sqlite3_config().)^
333380
**
@@ -1692,11 +1739,11 @@
16921739
** configuration option.
16931740
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
16941741
** 8-byte aligned
16951742
** memory, the size of each page buffer (sz), and the number of pages (N).
16961743
** The sz argument should be the size of the largest database page
1697
-** (a power of two between 512 and 32768) plus some extra bytes for each
1744
+** (a power of two between 512 and 65536) plus some extra bytes for each
16981745
** page header. ^The number of extra bytes needed by the page header
16991746
** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
17001747
** to [sqlite3_config()].
17011748
** ^It is harmless, apart from the wasted memory,
17021749
** for the sz parameter to be larger than necessary. The first
@@ -1872,10 +1919,21 @@
18721919
** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
18731920
** is a pointer to an integer and writes into that integer the number of extra
18741921
** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
18751922
** The amount of extra space required can change depending on the compiler,
18761923
** target platform, and SQLite version.
1924
+**
1925
+** [[SQLITE_CONFIG_PMASZ]]
1926
+** <dt>SQLITE_CONFIG_PMASZ
1927
+** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
1928
+** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
1929
+** sorter to that integer. The default minimum PMA Size is set by the
1930
+** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
1931
+** to help with sort operations when multithreaded sorting
1932
+** is enabled (using the [PRAGMA threads] command) and the amount of content
1933
+** to be sorted exceeds the page size times the minimum of the
1934
+** [PRAGMA cache_size] setting and this value.
18771935
** </dl>
18781936
*/
18791937
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
18801938
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
18811939
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1898,10 +1956,11 @@
18981956
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
18991957
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
19001958
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
19011959
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
19021960
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
1961
+#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
19031962
19041963
/*
19051964
** CAPI3REF: Database Connection Configuration Options
19061965
**
19071966
** These constants are the available integer configuration options that
@@ -7307,16 +7366,14 @@
73077366
73087367
/*
73097368
** CAPI3REF: Write-Ahead Log Commit Hook
73107369
**
73117370
** ^The [sqlite3_wal_hook()] function is used to register a callback that
7312
-** will be invoked each time a database connection commits data to a
7313
-** [write-ahead log] (i.e. whenever a transaction is committed in
7314
-** [journal_mode | journal_mode=WAL mode]).
7371
+** is invoked each time data is committed to a database in wal mode.
73157372
**
7316
-** ^The callback is invoked by SQLite after the commit has taken place and
7317
-** the associated write-lock on the database released, so the implementation
7373
+** ^(The callback is invoked by SQLite after the commit has taken place and
7374
+** the associated write-lock on the database released)^, so the implementation
73187375
** may read, write or [checkpoint] the database as required.
73197376
**
73207377
** ^The first parameter passed to the callback function when it is invoked
73217378
** is a copy of the third parameter passed to sqlite3_wal_hook() when
73227379
** registering the callback. ^The second is a copy of the database handle.
@@ -7603,10 +7660,14 @@
76037660
**
76047661
** The following constants can be used for the T parameter to the
76057662
** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
76067663
** different metric for sqlite3_stmt_scanstatus() to return.
76077664
**
7665
+** When the value returned to V is a string, space to hold that string is
7666
+** managed by the prepared statement S and will be automatically freed when
7667
+** S is finalized.
7668
+**
76087669
** <dl>
76097670
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
76107671
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
76117672
** set to the total number of times that the X-th loop has run.</dd>
76127673
**
@@ -7648,11 +7709,18 @@
76487709
#define SQLITE_SCANSTAT_SELECTID 5
76497710
76507711
/*
76517712
** CAPI3REF: Prepared Statement Scan Status
76527713
**
7653
-** Return status data for a single loop within query pStmt.
7714
+** This interface returns information about the predicted and measured
7715
+** performance for pStmt. Advanced applications can use this
7716
+** interface to compare the predicted and the measured performance and
7717
+** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
7718
+**
7719
+** Since this interface is expected to be rarely used, it is only
7720
+** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
7721
+** compile-time option.
76547722
**
76557723
** The "iScanStatusOp" parameter determines which status information to return.
76567724
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
76577725
** of this interface is undefined.
76587726
** ^The requested measurement is written into a variable pointed to by
@@ -7666,13 +7734,10 @@
76667734
** ^Statistics might not be available for all loops in all statements. ^In cases
76677735
** where there exist loops with no available statistics, this function behaves
76687736
** as if the loop did not exist - it returns non-zero and leave the variable
76697737
** that pOut points to unchanged.
76707738
**
7671
-** This API is only available if the library is built with pre-processor
7672
-** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
7673
-**
76747739
** See also: [sqlite3_stmt_scanstatus_reset()]
76757740
*/
76767741
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
76777742
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
76787743
int idx, /* Index of loop to report on */
@@ -9100,11 +9165,11 @@
91009165
#define _BTREE_H_
91019166
91029167
/* TODO: This definition is just included so other modules compile. It
91039168
** needs to be revisited.
91049169
*/
9105
-#define SQLITE_N_BTREE_META 10
9170
+#define SQLITE_N_BTREE_META 16
91069171
91079172
/*
91089173
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
91099174
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
91109175
*/
@@ -9215,10 +9280,15 @@
92159280
** offset = 36 + (idx * 4)
92169281
**
92179282
** For example, the free-page-count field is located at byte offset 36 of
92189283
** the database file header. The incr-vacuum-flag field is located at
92199284
** byte offset 64 (== 36+4*7).
9285
+**
9286
+** The BTREE_DATA_VERSION value is not really a value stored in the header.
9287
+** It is a read-only number computed by the pager. But we merge it with
9288
+** the header value access routines since its access pattern is the same.
9289
+** Call it a "virtual meta value".
92209290
*/
92219291
#define BTREE_FREE_PAGE_COUNT 0
92229292
#define BTREE_SCHEMA_VERSION 1
92239293
#define BTREE_FILE_FORMAT 2
92249294
#define BTREE_DEFAULT_CACHE_SIZE 3
@@ -9225,10 +9295,11 @@
92259295
#define BTREE_LARGEST_ROOT_PAGE 4
92269296
#define BTREE_TEXT_ENCODING 5
92279297
#define BTREE_USER_VERSION 6
92289298
#define BTREE_INCR_VACUUM 7
92299299
#define BTREE_APPLICATION_ID 8
9300
+#define BTREE_DATA_VERSION 15 /* A virtual meta-value */
92309301
92319302
/*
92329303
** Values that may be OR'd together to form the second argument of an
92339304
** sqlite3BtreeCursorHints() call.
92349305
*/
@@ -10006,10 +10077,11 @@
1000610077
SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
1000710078
#endif
1000810079
1000910080
/* Functions used to query pager state and configuration. */
1001010081
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
10082
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
1001110083
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
1001210084
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
1001310085
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
1001410086
SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
1001510087
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
@@ -10747,10 +10819,11 @@
1074710819
i64 szMmap; /* Default mmap_size setting */
1074810820
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
1074910821
int errCode; /* Most recent error code (SQLITE_*) */
1075010822
int errMask; /* & result codes with this before returning */
1075110823
u16 dbOptFlags; /* Flags to enable/disable optimizations */
10824
+ u8 enc; /* Text encoding */
1075210825
u8 autoCommit; /* The auto-commit flag. */
1075310826
u8 temp_store; /* 1: file 2: memory 0: default */
1075410827
u8 mallocFailed; /* True if we have seen a malloc failure */
1075510828
u8 dfltLockMode; /* Default locking-mode for attached dbs */
1075610829
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
@@ -10848,11 +10921,12 @@
1084810921
};
1084910922
1085010923
/*
1085110924
** A macro to discover the encoding of a database.
1085210925
*/
10853
-#define ENC(db) ((db)->aDb[0].pSchema->enc)
10926
+#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
10927
+#define ENC(db) ((db)->enc)
1085410928
1085510929
/*
1085610930
** Possible values for the sqlite3.flags.
1085710931
*/
1085810932
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
@@ -11472,11 +11546,10 @@
1147211546
Index *pNext; /* The next index associated with the same table */
1147311547
Schema *pSchema; /* Schema containing this index */
1147411548
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
1147511549
char **azColl; /* Array of collation sequence names for index */
1147611550
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
11477
- KeyInfo *pKeyInfo; /* A KeyInfo object suitable for this index */
1147811551
int tnum; /* DB Page containing root of this index */
1147911552
LogEst szIdxRow; /* Estimated average row size in bytes */
1148011553
u16 nKeyCol; /* Number of columns forming the key */
1148111554
u16 nColumn; /* Number of columns stored in the index */
1148211555
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
@@ -12036,11 +12109,11 @@
1203612109
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
1203712110
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
1203812111
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
1203912112
#define SF_Compound 0x0040 /* Part of a compound query */
1204012113
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
12041
- /* 0x0100 NOT USED */
12114
+#define SF_AllValues 0x0100 /* All terms of compound are VALUES */
1204212115
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
1204312116
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
1204412117
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
1204512118
#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
1204612119
@@ -12526,10 +12599,11 @@
1252612599
void *pPage; /* Page cache memory */
1252712600
int szPage; /* Size of each page in pPage[] */
1252812601
int nPage; /* Number of pages in pPage[] */
1252912602
int mxParserStack; /* maximum depth of the parser stack */
1253012603
int sharedCacheEnabled; /* true if shared-cache mode enabled */
12604
+ u32 szPma; /* Maximum Sorter PMA size */
1253112605
/* The above might be initialized to non-zero. The following need to always
1253212606
** initially be zero, however. */
1253312607
int isInit; /* True after initialization has finished */
1253412608
int inProgress; /* True while initialization in progress */
1253512609
int isMutexInit; /* True after mutexes are initialized */
@@ -12663,11 +12737,11 @@
1266312737
** FTS4 is really an extension for FTS3. It is enabled using the
1266412738
** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call
1266512739
** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
1266612740
*/
1266712741
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
12668
-# define SQLITE_ENABLE_FTS3
12742
+# define SQLITE_ENABLE_FTS3 1
1266912743
#endif
1267012744
1267112745
/*
1267212746
** The ctype.h header is needed for non-ASCII systems. It is also
1267312747
** needed by FTS3 when FTS3 is included in the amalgamation.
@@ -13448,11 +13522,11 @@
1344813522
** print I/O tracing messages.
1344913523
*/
1345013524
#ifdef SQLITE_ENABLE_IOTRACE
1345113525
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
1345213526
SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*);
13453
-SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
13527
+void (*sqlite3IoTrace)(const char*,...);
1345413528
#else
1345513529
# define IOTRACE(A)
1345613530
# define sqlite3VdbeIOTraceSql(X)
1345713531
#endif
1345813532
@@ -13661,10 +13735,17 @@
1366113735
*/
1366213736
#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
1366313737
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
1366413738
#endif
1366513739
13740
+/* The minimum PMA size is set to this value multiplied by the database
13741
+** page size in bytes.
13742
+*/
13743
+#ifndef SQLITE_SORTER_PMASZ
13744
+# define SQLITE_SORTER_PMASZ 250
13745
+#endif
13746
+
1366613747
/*
1366713748
** The following singleton contains the global configuration for
1366813749
** the SQLite library.
1366913750
*/
1367013751
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
@@ -13691,10 +13772,11 @@
1369113772
(void*)0, /* pPage */
1369213773
0, /* szPage */
1369313774
0, /* nPage */
1369413775
0, /* mxParserStack */
1369513776
0, /* sharedCacheEnabled */
13777
+ SQLITE_SORTER_PMASZ, /* szPma */
1369613778
/* All the rest should always be initialized to zero */
1369713779
0, /* isInit */
1369813780
0, /* inProgress */
1369913781
0, /* isMutexInit */
1370013782
0, /* isMallocInit */
@@ -13797,355 +13879,355 @@
1379713879
/* These macros are provided to "stringify" the value of the define
1379813880
** for those options in which the value is meaningful. */
1379913881
#define CTIMEOPT_VAL_(opt) #opt
1380013882
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
1380113883
13802
-#ifdef SQLITE_32BIT_ROWID
13884
+#if SQLITE_32BIT_ROWID
1380313885
"32BIT_ROWID",
1380413886
#endif
13805
-#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
13887
+#if SQLITE_4_BYTE_ALIGNED_MALLOC
1380613888
"4_BYTE_ALIGNED_MALLOC",
1380713889
#endif
13808
-#ifdef SQLITE_CASE_SENSITIVE_LIKE
13890
+#if SQLITE_CASE_SENSITIVE_LIKE
1380913891
"CASE_SENSITIVE_LIKE",
1381013892
#endif
13811
-#ifdef SQLITE_CHECK_PAGES
13893
+#if SQLITE_CHECK_PAGES
1381213894
"CHECK_PAGES",
1381313895
#endif
13814
-#ifdef SQLITE_COVERAGE_TEST
13896
+#if SQLITE_COVERAGE_TEST
1381513897
"COVERAGE_TEST",
1381613898
#endif
13817
-#ifdef SQLITE_DEBUG
13899
+#if SQLITE_DEBUG
1381813900
"DEBUG",
1381913901
#endif
13820
-#ifdef SQLITE_DEFAULT_LOCKING_MODE
13902
+#if SQLITE_DEFAULT_LOCKING_MODE
1382113903
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
1382213904
#endif
1382313905
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
1382413906
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
1382513907
#endif
13826
-#ifdef SQLITE_DISABLE_DIRSYNC
13908
+#if SQLITE_DISABLE_DIRSYNC
1382713909
"DISABLE_DIRSYNC",
1382813910
#endif
13829
-#ifdef SQLITE_DISABLE_LFS
13911
+#if SQLITE_DISABLE_LFS
1383013912
"DISABLE_LFS",
1383113913
#endif
13832
-#ifdef SQLITE_ENABLE_API_ARMOR
13914
+#if SQLITE_ENABLE_API_ARMOR
1383313915
"ENABLE_API_ARMOR",
1383413916
#endif
13835
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
13917
+#if SQLITE_ENABLE_ATOMIC_WRITE
1383613918
"ENABLE_ATOMIC_WRITE",
1383713919
#endif
13838
-#ifdef SQLITE_ENABLE_CEROD
13920
+#if SQLITE_ENABLE_CEROD
1383913921
"ENABLE_CEROD",
1384013922
#endif
13841
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
13923
+#if SQLITE_ENABLE_COLUMN_METADATA
1384213924
"ENABLE_COLUMN_METADATA",
1384313925
#endif
13844
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
13926
+#if SQLITE_ENABLE_EXPENSIVE_ASSERT
1384513927
"ENABLE_EXPENSIVE_ASSERT",
1384613928
#endif
13847
-#ifdef SQLITE_ENABLE_FTS1
13929
+#if SQLITE_ENABLE_FTS1
1384813930
"ENABLE_FTS1",
1384913931
#endif
13850
-#ifdef SQLITE_ENABLE_FTS2
13932
+#if SQLITE_ENABLE_FTS2
1385113933
"ENABLE_FTS2",
1385213934
#endif
13853
-#ifdef SQLITE_ENABLE_FTS3
13935
+#if SQLITE_ENABLE_FTS3
1385413936
"ENABLE_FTS3",
1385513937
#endif
13856
-#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
13938
+#if SQLITE_ENABLE_FTS3_PARENTHESIS
1385713939
"ENABLE_FTS3_PARENTHESIS",
1385813940
#endif
13859
-#ifdef SQLITE_ENABLE_FTS4
13941
+#if SQLITE_ENABLE_FTS4
1386013942
"ENABLE_FTS4",
1386113943
#endif
13862
-#ifdef SQLITE_ENABLE_ICU
13944
+#if SQLITE_ENABLE_ICU
1386313945
"ENABLE_ICU",
1386413946
#endif
13865
-#ifdef SQLITE_ENABLE_IOTRACE
13947
+#if SQLITE_ENABLE_IOTRACE
1386613948
"ENABLE_IOTRACE",
1386713949
#endif
13868
-#ifdef SQLITE_ENABLE_LOAD_EXTENSION
13950
+#if SQLITE_ENABLE_LOAD_EXTENSION
1386913951
"ENABLE_LOAD_EXTENSION",
1387013952
#endif
13871
-#ifdef SQLITE_ENABLE_LOCKING_STYLE
13953
+#if SQLITE_ENABLE_LOCKING_STYLE
1387213954
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
1387313955
#endif
13874
-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
13956
+#if SQLITE_ENABLE_MEMORY_MANAGEMENT
1387513957
"ENABLE_MEMORY_MANAGEMENT",
1387613958
#endif
13877
-#ifdef SQLITE_ENABLE_MEMSYS3
13959
+#if SQLITE_ENABLE_MEMSYS3
1387813960
"ENABLE_MEMSYS3",
1387913961
#endif
13880
-#ifdef SQLITE_ENABLE_MEMSYS5
13962
+#if SQLITE_ENABLE_MEMSYS5
1388113963
"ENABLE_MEMSYS5",
1388213964
#endif
13883
-#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
13965
+#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
1388413966
"ENABLE_OVERSIZE_CELL_CHECK",
1388513967
#endif
13886
-#ifdef SQLITE_ENABLE_RTREE
13968
+#if SQLITE_ENABLE_RTREE
1388713969
"ENABLE_RTREE",
1388813970
#endif
1388913971
#if defined(SQLITE_ENABLE_STAT4)
1389013972
"ENABLE_STAT4",
1389113973
#elif defined(SQLITE_ENABLE_STAT3)
1389213974
"ENABLE_STAT3",
1389313975
#endif
13894
-#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
13976
+#if SQLITE_ENABLE_UNLOCK_NOTIFY
1389513977
"ENABLE_UNLOCK_NOTIFY",
1389613978
#endif
13897
-#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
13979
+#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
1389813980
"ENABLE_UPDATE_DELETE_LIMIT",
1389913981
#endif
13900
-#ifdef SQLITE_HAS_CODEC
13982
+#if SQLITE_HAS_CODEC
1390113983
"HAS_CODEC",
1390213984
#endif
13903
-#ifdef SQLITE_HAVE_ISNAN
13985
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
1390413986
"HAVE_ISNAN",
1390513987
#endif
13906
-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
13988
+#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
1390713989
"HOMEGROWN_RECURSIVE_MUTEX",
1390813990
#endif
13909
-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
13991
+#if SQLITE_IGNORE_AFP_LOCK_ERRORS
1391013992
"IGNORE_AFP_LOCK_ERRORS",
1391113993
#endif
13912
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
13994
+#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
1391313995
"IGNORE_FLOCK_LOCK_ERRORS",
1391413996
#endif
1391513997
#ifdef SQLITE_INT64_TYPE
1391613998
"INT64_TYPE",
1391713999
#endif
13918
-#ifdef SQLITE_LOCK_TRACE
14000
+#if SQLITE_LOCK_TRACE
1391914001
"LOCK_TRACE",
1392014002
#endif
1392114003
#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
1392214004
"MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
1392314005
#endif
1392414006
#ifdef SQLITE_MAX_SCHEMA_RETRY
1392514007
"MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
1392614008
#endif
13927
-#ifdef SQLITE_MEMDEBUG
14009
+#if SQLITE_MEMDEBUG
1392814010
"MEMDEBUG",
1392914011
#endif
13930
-#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
14012
+#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
1393114013
"MIXED_ENDIAN_64BIT_FLOAT",
1393214014
#endif
13933
-#ifdef SQLITE_NO_SYNC
14015
+#if SQLITE_NO_SYNC
1393414016
"NO_SYNC",
1393514017
#endif
13936
-#ifdef SQLITE_OMIT_ALTERTABLE
14018
+#if SQLITE_OMIT_ALTERTABLE
1393714019
"OMIT_ALTERTABLE",
1393814020
#endif
13939
-#ifdef SQLITE_OMIT_ANALYZE
14021
+#if SQLITE_OMIT_ANALYZE
1394014022
"OMIT_ANALYZE",
1394114023
#endif
13942
-#ifdef SQLITE_OMIT_ATTACH
14024
+#if SQLITE_OMIT_ATTACH
1394314025
"OMIT_ATTACH",
1394414026
#endif
13945
-#ifdef SQLITE_OMIT_AUTHORIZATION
14027
+#if SQLITE_OMIT_AUTHORIZATION
1394614028
"OMIT_AUTHORIZATION",
1394714029
#endif
13948
-#ifdef SQLITE_OMIT_AUTOINCREMENT
14030
+#if SQLITE_OMIT_AUTOINCREMENT
1394914031
"OMIT_AUTOINCREMENT",
1395014032
#endif
13951
-#ifdef SQLITE_OMIT_AUTOINIT
14033
+#if SQLITE_OMIT_AUTOINIT
1395214034
"OMIT_AUTOINIT",
1395314035
#endif
13954
-#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
14036
+#if SQLITE_OMIT_AUTOMATIC_INDEX
1395514037
"OMIT_AUTOMATIC_INDEX",
1395614038
#endif
13957
-#ifdef SQLITE_OMIT_AUTORESET
14039
+#if SQLITE_OMIT_AUTORESET
1395814040
"OMIT_AUTORESET",
1395914041
#endif
13960
-#ifdef SQLITE_OMIT_AUTOVACUUM
14042
+#if SQLITE_OMIT_AUTOVACUUM
1396114043
"OMIT_AUTOVACUUM",
1396214044
#endif
13963
-#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
14045
+#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
1396414046
"OMIT_BETWEEN_OPTIMIZATION",
1396514047
#endif
13966
-#ifdef SQLITE_OMIT_BLOB_LITERAL
14048
+#if SQLITE_OMIT_BLOB_LITERAL
1396714049
"OMIT_BLOB_LITERAL",
1396814050
#endif
13969
-#ifdef SQLITE_OMIT_BTREECOUNT
14051
+#if SQLITE_OMIT_BTREECOUNT
1397014052
"OMIT_BTREECOUNT",
1397114053
#endif
13972
-#ifdef SQLITE_OMIT_BUILTIN_TEST
14054
+#if SQLITE_OMIT_BUILTIN_TEST
1397314055
"OMIT_BUILTIN_TEST",
1397414056
#endif
13975
-#ifdef SQLITE_OMIT_CAST
14057
+#if SQLITE_OMIT_CAST
1397614058
"OMIT_CAST",
1397714059
#endif
13978
-#ifdef SQLITE_OMIT_CHECK
14060
+#if SQLITE_OMIT_CHECK
1397914061
"OMIT_CHECK",
1398014062
#endif
13981
-#ifdef SQLITE_OMIT_COMPLETE
14063
+#if SQLITE_OMIT_COMPLETE
1398214064
"OMIT_COMPLETE",
1398314065
#endif
13984
-#ifdef SQLITE_OMIT_COMPOUND_SELECT
14066
+#if SQLITE_OMIT_COMPOUND_SELECT
1398514067
"OMIT_COMPOUND_SELECT",
1398614068
#endif
13987
-#ifdef SQLITE_OMIT_CTE
14069
+#if SQLITE_OMIT_CTE
1398814070
"OMIT_CTE",
1398914071
#endif
13990
-#ifdef SQLITE_OMIT_DATETIME_FUNCS
14072
+#if SQLITE_OMIT_DATETIME_FUNCS
1399114073
"OMIT_DATETIME_FUNCS",
1399214074
#endif
13993
-#ifdef SQLITE_OMIT_DECLTYPE
14075
+#if SQLITE_OMIT_DECLTYPE
1399414076
"OMIT_DECLTYPE",
1399514077
#endif
13996
-#ifdef SQLITE_OMIT_DEPRECATED
14078
+#if SQLITE_OMIT_DEPRECATED
1399714079
"OMIT_DEPRECATED",
1399814080
#endif
13999
-#ifdef SQLITE_OMIT_DISKIO
14081
+#if SQLITE_OMIT_DISKIO
1400014082
"OMIT_DISKIO",
1400114083
#endif
14002
-#ifdef SQLITE_OMIT_EXPLAIN
14084
+#if SQLITE_OMIT_EXPLAIN
1400314085
"OMIT_EXPLAIN",
1400414086
#endif
14005
-#ifdef SQLITE_OMIT_FLAG_PRAGMAS
14087
+#if SQLITE_OMIT_FLAG_PRAGMAS
1400614088
"OMIT_FLAG_PRAGMAS",
1400714089
#endif
14008
-#ifdef SQLITE_OMIT_FLOATING_POINT
14090
+#if SQLITE_OMIT_FLOATING_POINT
1400914091
"OMIT_FLOATING_POINT",
1401014092
#endif
14011
-#ifdef SQLITE_OMIT_FOREIGN_KEY
14093
+#if SQLITE_OMIT_FOREIGN_KEY
1401214094
"OMIT_FOREIGN_KEY",
1401314095
#endif
14014
-#ifdef SQLITE_OMIT_GET_TABLE
14096
+#if SQLITE_OMIT_GET_TABLE
1401514097
"OMIT_GET_TABLE",
1401614098
#endif
14017
-#ifdef SQLITE_OMIT_INCRBLOB
14099
+#if SQLITE_OMIT_INCRBLOB
1401814100
"OMIT_INCRBLOB",
1401914101
#endif
14020
-#ifdef SQLITE_OMIT_INTEGRITY_CHECK
14102
+#if SQLITE_OMIT_INTEGRITY_CHECK
1402114103
"OMIT_INTEGRITY_CHECK",
1402214104
#endif
14023
-#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
14105
+#if SQLITE_OMIT_LIKE_OPTIMIZATION
1402414106
"OMIT_LIKE_OPTIMIZATION",
1402514107
#endif
14026
-#ifdef SQLITE_OMIT_LOAD_EXTENSION
14108
+#if SQLITE_OMIT_LOAD_EXTENSION
1402714109
"OMIT_LOAD_EXTENSION",
1402814110
#endif
14029
-#ifdef SQLITE_OMIT_LOCALTIME
14111
+#if SQLITE_OMIT_LOCALTIME
1403014112
"OMIT_LOCALTIME",
1403114113
#endif
14032
-#ifdef SQLITE_OMIT_LOOKASIDE
14114
+#if SQLITE_OMIT_LOOKASIDE
1403314115
"OMIT_LOOKASIDE",
1403414116
#endif
14035
-#ifdef SQLITE_OMIT_MEMORYDB
14117
+#if SQLITE_OMIT_MEMORYDB
1403614118
"OMIT_MEMORYDB",
1403714119
#endif
14038
-#ifdef SQLITE_OMIT_OR_OPTIMIZATION
14120
+#if SQLITE_OMIT_OR_OPTIMIZATION
1403914121
"OMIT_OR_OPTIMIZATION",
1404014122
#endif
14041
-#ifdef SQLITE_OMIT_PAGER_PRAGMAS
14123
+#if SQLITE_OMIT_PAGER_PRAGMAS
1404214124
"OMIT_PAGER_PRAGMAS",
1404314125
#endif
14044
-#ifdef SQLITE_OMIT_PRAGMA
14126
+#if SQLITE_OMIT_PRAGMA
1404514127
"OMIT_PRAGMA",
1404614128
#endif
14047
-#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
14129
+#if SQLITE_OMIT_PROGRESS_CALLBACK
1404814130
"OMIT_PROGRESS_CALLBACK",
1404914131
#endif
14050
-#ifdef SQLITE_OMIT_QUICKBALANCE
14132
+#if SQLITE_OMIT_QUICKBALANCE
1405114133
"OMIT_QUICKBALANCE",
1405214134
#endif
14053
-#ifdef SQLITE_OMIT_REINDEX
14135
+#if SQLITE_OMIT_REINDEX
1405414136
"OMIT_REINDEX",
1405514137
#endif
14056
-#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
14138
+#if SQLITE_OMIT_SCHEMA_PRAGMAS
1405714139
"OMIT_SCHEMA_PRAGMAS",
1405814140
#endif
14059
-#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
14141
+#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
1406014142
"OMIT_SCHEMA_VERSION_PRAGMAS",
1406114143
#endif
14062
-#ifdef SQLITE_OMIT_SHARED_CACHE
14144
+#if SQLITE_OMIT_SHARED_CACHE
1406314145
"OMIT_SHARED_CACHE",
1406414146
#endif
14065
-#ifdef SQLITE_OMIT_SUBQUERY
14147
+#if SQLITE_OMIT_SUBQUERY
1406614148
"OMIT_SUBQUERY",
1406714149
#endif
14068
-#ifdef SQLITE_OMIT_TCL_VARIABLE
14150
+#if SQLITE_OMIT_TCL_VARIABLE
1406914151
"OMIT_TCL_VARIABLE",
1407014152
#endif
14071
-#ifdef SQLITE_OMIT_TEMPDB
14153
+#if SQLITE_OMIT_TEMPDB
1407214154
"OMIT_TEMPDB",
1407314155
#endif
14074
-#ifdef SQLITE_OMIT_TRACE
14156
+#if SQLITE_OMIT_TRACE
1407514157
"OMIT_TRACE",
1407614158
#endif
14077
-#ifdef SQLITE_OMIT_TRIGGER
14159
+#if SQLITE_OMIT_TRIGGER
1407814160
"OMIT_TRIGGER",
1407914161
#endif
14080
-#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
14162
+#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
1408114163
"OMIT_TRUNCATE_OPTIMIZATION",
1408214164
#endif
14083
-#ifdef SQLITE_OMIT_UTF16
14165
+#if SQLITE_OMIT_UTF16
1408414166
"OMIT_UTF16",
1408514167
#endif
14086
-#ifdef SQLITE_OMIT_VACUUM
14168
+#if SQLITE_OMIT_VACUUM
1408714169
"OMIT_VACUUM",
1408814170
#endif
14089
-#ifdef SQLITE_OMIT_VIEW
14171
+#if SQLITE_OMIT_VIEW
1409014172
"OMIT_VIEW",
1409114173
#endif
14092
-#ifdef SQLITE_OMIT_VIRTUALTABLE
14174
+#if SQLITE_OMIT_VIRTUALTABLE
1409314175
"OMIT_VIRTUALTABLE",
1409414176
#endif
14095
-#ifdef SQLITE_OMIT_WAL
14177
+#if SQLITE_OMIT_WAL
1409614178
"OMIT_WAL",
1409714179
#endif
14098
-#ifdef SQLITE_OMIT_WSD
14180
+#if SQLITE_OMIT_WSD
1409914181
"OMIT_WSD",
1410014182
#endif
14101
-#ifdef SQLITE_OMIT_XFER_OPT
14183
+#if SQLITE_OMIT_XFER_OPT
1410214184
"OMIT_XFER_OPT",
1410314185
#endif
14104
-#ifdef SQLITE_PERFORMANCE_TRACE
14186
+#if SQLITE_PERFORMANCE_TRACE
1410514187
"PERFORMANCE_TRACE",
1410614188
#endif
14107
-#ifdef SQLITE_PROXY_DEBUG
14189
+#if SQLITE_PROXY_DEBUG
1410814190
"PROXY_DEBUG",
1410914191
#endif
14110
-#ifdef SQLITE_RTREE_INT_ONLY
14192
+#if SQLITE_RTREE_INT_ONLY
1411114193
"RTREE_INT_ONLY",
1411214194
#endif
14113
-#ifdef SQLITE_SECURE_DELETE
14195
+#if SQLITE_SECURE_DELETE
1411414196
"SECURE_DELETE",
1411514197
#endif
14116
-#ifdef SQLITE_SMALL_STACK
14198
+#if SQLITE_SMALL_STACK
1411714199
"SMALL_STACK",
1411814200
#endif
14119
-#ifdef SQLITE_SOUNDEX
14201
+#if SQLITE_SOUNDEX
1412014202
"SOUNDEX",
1412114203
#endif
14122
-#ifdef SQLITE_SYSTEM_MALLOC
14204
+#if SQLITE_SYSTEM_MALLOC
1412314205
"SYSTEM_MALLOC",
1412414206
#endif
14125
-#ifdef SQLITE_TCL
14207
+#if SQLITE_TCL
1412614208
"TCL",
1412714209
#endif
1412814210
#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
1412914211
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
1413014212
#endif
14131
-#ifdef SQLITE_TEST
14213
+#if SQLITE_TEST
1413214214
"TEST",
1413314215
#endif
1413414216
#if defined(SQLITE_THREADSAFE)
1413514217
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
1413614218
#endif
14137
-#ifdef SQLITE_USE_ALLOCA
14219
+#if SQLITE_USE_ALLOCA
1413814220
"USE_ALLOCA",
1413914221
#endif
14140
-#ifdef SQLITE_USER_AUTHENTICATION
14222
+#if SQLITE_USER_AUTHENTICATION
1414114223
"USER_AUTHENTICATION",
1414214224
#endif
14143
-#ifdef SQLITE_WIN32_MALLOC
14225
+#if SQLITE_WIN32_MALLOC
1414414226
"WIN32_MALLOC",
1414514227
#endif
14146
-#ifdef SQLITE_ZERO_MALLOC
14228
+#if SQLITE_ZERO_MALLOC
1414714229
"ZERO_MALLOC"
1414814230
#endif
1414914231
};
1415014232
1415114233
/*
@@ -14156,11 +14238,11 @@
1415614238
** is not required for a match.
1415714239
*/
1415814240
SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
1415914241
int i, n;
1416014242
14161
-#ifdef SQLITE_ENABLE_API_ARMOR
14243
+#if SQLITE_ENABLE_API_ARMOR
1416214244
if( zOptName==0 ){
1416314245
(void)SQLITE_MISUSE_BKPT;
1416414246
return 0;
1416514247
}
1416614248
#endif
@@ -15384,12 +15466,13 @@
1538415466
**
1538515467
** If the user has not indicated to use localtime_r() or localtime_s()
1538615468
** already, check for an MSVC build environment that provides
1538715469
** localtime_s().
1538815470
*/
15389
-#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
15390
- defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
15471
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
15472
+ && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
15473
+#undef HAVE_LOCALTIME_S
1539115474
#define HAVE_LOCALTIME_S 1
1539215475
#endif
1539315476
1539415477
#ifndef SQLITE_OMIT_LOCALTIME
1539515478
/*
@@ -15405,12 +15488,11 @@
1540515488
** library function localtime_r() is used to assist in the calculation of
1540615489
** local time.
1540715490
*/
1540815491
static int osLocaltime(time_t *t, struct tm *pTm){
1540915492
int rc;
15410
-#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
15411
- && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
15493
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
1541215494
struct tm *pX;
1541315495
#if SQLITE_THREADSAFE>0
1541415496
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
1541515497
#endif
1541615498
sqlite3_mutex_enter(mutex);
@@ -15423,11 +15505,11 @@
1542315505
rc = pX==0;
1542415506
#else
1542515507
#ifndef SQLITE_OMIT_BUILTIN_TEST
1542615508
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
1542715509
#endif
15428
-#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
15510
+#if HAVE_LOCALTIME_R
1542915511
rc = localtime_r(t, pTm)==0;
1543015512
#else
1543115513
rc = localtime_s(pTm, t);
1543215514
#endif /* HAVE_LOCALTIME_R */
1543315515
#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
@@ -15867,12 +15949,14 @@
1586715949
DateTime x;
1586815950
u64 n;
1586915951
size_t i,j;
1587015952
char *z;
1587115953
sqlite3 *db;
15872
- const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
15954
+ const char *zFmt;
1587315955
char zBuf[100];
15956
+ if( argc==0 ) return;
15957
+ zFmt = (const char*)sqlite3_value_text(argv[0]);
1587415958
if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
1587515959
db = sqlite3_context_db_handle(context);
1587615960
for(i=0, n=1; zFmt[i]; i++, n++){
1587715961
if( zFmt[i]=='%' ){
1587815962
switch( zFmt[i+1] ){
@@ -16062,11 +16146,11 @@
1606216146
UNUSED_PARAMETER(argv);
1606316147
1606416148
iT = sqlite3StmtCurrentTime(context);
1606516149
if( iT<=0 ) return;
1606616150
t = iT/1000 - 10000*(sqlite3_int64)21086676;
16067
-#ifdef HAVE_GMTIME_R
16151
+#if HAVE_GMTIME_R
1606816152
pTm = gmtime_r(&t, &sNow);
1606916153
#else
1607016154
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
1607116155
pTm = gmtime(&t);
1607216156
if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
@@ -16736,13 +16820,13 @@
1673616820
1673716821
/*
1673816822
** The malloc.h header file is needed for malloc_usable_size() function
1673916823
** on some systems (e.g. Linux).
1674016824
*/
16741
-#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE)
16742
-# define SQLITE_USE_MALLOC_H
16743
-# define SQLITE_USE_MALLOC_USABLE_SIZE
16825
+#if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE
16826
+# define SQLITE_USE_MALLOC_H 1
16827
+# define SQLITE_USE_MALLOC_USABLE_SIZE 1
1674416828
/*
1674516829
** The MSVCRT has malloc_usable_size(), but it is called _msize(). The
1674616830
** use of _msize() is automatic, but can be disabled by compiling with
1674716831
** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires
1674816832
** the malloc.h header file.
@@ -19976,10 +20060,16 @@
1997620060
#endif
1997720061
}
1997820062
break;
1997920063
}
1998020064
default: {
20065
+#ifdef SQLITE_ENABLE_API_ARMOR
20066
+ if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){
20067
+ (void)SQLITE_MISUSE_BKPT;
20068
+ return 0;
20069
+ }
20070
+#endif
1998120071
assert( iType-2 >= 0 );
1998220072
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
1998320073
assert( winMutex_isInit==1 );
1998420074
p = &winMutex_staticMutexes[iType-2];
1998520075
#ifdef SQLITE_DEBUG
@@ -20971,21 +21061,10 @@
2097121061
** This file contains code for a set of "printf"-like routines. These
2097221062
** routines format strings much like the printf() from the standard C
2097321063
** library, though the implementation here has enhancements to support
2097421064
** SQLlite.
2097521065
*/
20976
-
20977
-/*
20978
-** If the strchrnul() library function is available, then set
20979
-** HAVE_STRCHRNUL. If that routine is not available, this module
20980
-** will supply its own. The built-in version is slower than
20981
-** the glibc version so the glibc version is definitely preferred.
20982
-*/
20983
-#if !defined(HAVE_STRCHRNUL)
20984
-# define HAVE_STRCHRNUL 0
20985
-#endif
20986
-
2098721066
2098821067
/*
2098921068
** Conversion types fall into various categories as defined by the
2099021069
** following enumeration.
2099121070
*/
@@ -22280,10 +22359,12 @@
2228022359
** single threaded systems. Nothing in SQLite requires multiple threads.
2228122360
** This interface exists so that applications that want to take advantage
2228222361
** of multiple cores can do so, while also allowing applications to stay
2228322362
** single-threaded if desired.
2228422363
*/
22364
+#if SQLITE_OS_WIN
22365
+#endif
2228522366
2228622367
#if SQLITE_MAX_WORKER_THREADS>0
2228722368
2228822369
/********************************* Unix Pthreads ****************************/
2228922370
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
@@ -23066,11 +23147,11 @@
2306623147
** This file contains functions for allocating memory, comparing
2306723148
** strings, and stuff like that.
2306823149
**
2306923150
*/
2307023151
/* #include <stdarg.h> */
23071
-#ifdef SQLITE_HAVE_ISNAN
23152
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
2307223153
# include <math.h>
2307323154
#endif
2307423155
2307523156
/*
2307623157
** Routine needed to support the testcase() macro.
@@ -23107,11 +23188,11 @@
2310723188
** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
2310823189
** Otherwise, we have our own implementation that works on most systems.
2310923190
*/
2311023191
SQLITE_PRIVATE int sqlite3IsNaN(double x){
2311123192
int rc; /* The value return */
23112
-#if !defined(SQLITE_HAVE_ISNAN)
23193
+#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
2311323194
/*
2311423195
** Systems that support the isnan() library function should probably
2311523196
** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
2311623197
** found that many systems do not have a working isnan() function so
2311723198
** this implementation is provided as an alternative.
@@ -23137,13 +23218,13 @@
2313723218
# error SQLite will not work correctly with the -ffast-math option of GCC.
2313823219
#endif
2313923220
volatile double y = x;
2314023221
volatile double z = y;
2314123222
rc = (y!=z);
23142
-#else /* if defined(SQLITE_HAVE_ISNAN) */
23223
+#else /* if HAVE_ISNAN */
2314323224
rc = isnan(x);
23144
-#endif /* SQLITE_HAVE_ISNAN */
23225
+#endif /* HAVE_ISNAN */
2314523226
testcase( rc );
2314623227
return rc;
2314723228
}
2314823229
#endif /* SQLITE_OMIT_FLOATING_POINT */
2314923230
@@ -28460,13 +28541,13 @@
2846028541
2846128542
/*
2846228543
** We do not trust systems to provide a working fdatasync(). Some do.
2846328544
** Others do no. To be safe, we will stick with the (slightly slower)
2846428545
** fsync(). If you know that your system does support fdatasync() correctly,
28465
-** then simply compile with -Dfdatasync=fdatasync
28546
+** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
2846628547
*/
28467
-#if !defined(fdatasync)
28548
+#if !defined(fdatasync) && !HAVE_FDATASYNC
2846828549
# define fdatasync fsync
2846928550
#endif
2847028551
2847128552
/*
2847228553
** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
@@ -28783,28 +28864,32 @@
2878328864
do{
2878428865
err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
2878528866
}while( err==EINTR );
2878628867
if( err ) return SQLITE_IOERR_WRITE;
2878728868
#else
28788
- /* If the OS does not have posix_fallocate(), fake it. First use
28789
- ** ftruncate() to set the file size, then write a single byte to
28790
- ** the last byte in each block within the extended region. This
28791
- ** is the same technique used by glibc to implement posix_fallocate()
28792
- ** on systems that do not have a real fallocate() system call.
28869
+ /* If the OS does not have posix_fallocate(), fake it. Write a
28870
+ ** single byte to the last byte in each block that falls entirely
28871
+ ** within the extended region. Then, if required, a single byte
28872
+ ** at offset (nSize-1), to set the size of the file correctly.
28873
+ ** This is a similar technique to that used by glibc on systems
28874
+ ** that do not have a real fallocate() call.
2879328875
*/
2879428876
int nBlk = buf.st_blksize; /* File-system block size */
28877
+ int nWrite = 0; /* Number of bytes written by seekAndWrite */
2879528878
i64 iWrite; /* Next offset to write to */
2879628879
28797
- if( robust_ftruncate(pFile->h, nSize) ){
28798
- pFile->lastErrno = errno;
28799
- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
28800
- }
2880128880
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
28802
- while( iWrite<nSize ){
28803
- int nWrite = seekAndWrite(pFile, iWrite, "", 1);
28881
+ assert( iWrite>=buf.st_size );
28882
+ assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
28883
+ assert( ((iWrite+1)%nBlk)==0 );
28884
+ for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
28885
+ nWrite = seekAndWrite(pFile, iWrite, "", 1);
2880428886
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
28805
- iWrite += nBlk;
28887
+ }
28888
+ if( nWrite==0 || (nSize%nBlk) ){
28889
+ nWrite = seekAndWrite(pFile, nSize-1, "", 1);
28890
+ if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
2880628891
}
2880728892
#endif
2880828893
}
2880928894
}
2881028895
@@ -34018,12 +34103,12 @@
3401834103
*/
3401934104
SQLITE_API int sqlite3_win32_reset_heap(){
3402034105
int rc;
3402134106
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
3402234107
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
34023
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
34024
- MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
34108
+ MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
34109
+ MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
3402534110
sqlite3_mutex_enter(pMaster);
3402634111
sqlite3_mutex_enter(pMem);
3402734112
winMemAssertMagic();
3402834113
if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
3402934114
/*
@@ -35294,11 +35379,11 @@
3529435379
sqlite3_file *id, /* File to read from */
3529535380
void *pBuf, /* Write content into this buffer */
3529635381
int amt, /* Number of bytes to read */
3529735382
sqlite3_int64 offset /* Begin reading at this offset */
3529835383
){
35299
-#if !SQLITE_OS_WINCE
35384
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
3530035385
OVERLAPPED overlapped; /* The offset for ReadFile. */
3530135386
#endif
3530235387
winFile *pFile = (winFile*)id; /* file handle */
3530335388
DWORD nRead; /* Number of bytes actually read from file */
3530435389
int nRetry = 0; /* Number of retrys */
@@ -35326,11 +35411,11 @@
3532635411
offset += nCopy;
3532735412
}
3532835413
}
3532935414
#endif
3533035415
35331
-#if SQLITE_OS_WINCE
35416
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
3533235417
if( winSeekFile(pFile, offset) ){
3533335418
OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
3533435419
return SQLITE_FULL;
3533535420
}
3533635421
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -35398,32 +35483,32 @@
3539835483
offset += nCopy;
3539935484
}
3540035485
}
3540135486
#endif
3540235487
35403
-#if SQLITE_OS_WINCE
35488
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
3540435489
rc = winSeekFile(pFile, offset);
3540535490
if( rc==0 ){
3540635491
#else
3540735492
{
3540835493
#endif
35409
-#if !SQLITE_OS_WINCE
35494
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
3541035495
OVERLAPPED overlapped; /* The offset for WriteFile. */
3541135496
#endif
3541235497
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
3541335498
int nRem = amt; /* Number of bytes yet to be written */
3541435499
DWORD nWrite; /* Bytes written by each WriteFile() call */
3541535500
DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
3541635501
35417
-#if !SQLITE_OS_WINCE
35502
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
3541835503
memset(&overlapped, 0, sizeof(OVERLAPPED));
3541935504
overlapped.Offset = (LONG)(offset & 0xffffffff);
3542035505
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
3542135506
#endif
3542235507
3542335508
while( nRem>0 ){
35424
-#if SQLITE_OS_WINCE
35509
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
3542535510
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
3542635511
#else
3542735512
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
3542835513
#endif
3542935514
if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
@@ -35432,11 +35517,11 @@
3543235517
assert( nWrite==0 || nWrite<=(DWORD)nRem );
3543335518
if( nWrite==0 || nWrite>(DWORD)nRem ){
3543435519
lastErrno = osGetLastError();
3543535520
break;
3543635521
}
35437
-#if !SQLITE_OS_WINCE
35522
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
3543835523
offset += nWrite;
3543935524
overlapped.Offset = (LONG)(offset & 0xffffffff);
3544035525
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
3544135526
#endif
3544235527
aRem += nWrite;
@@ -38813,22 +38898,10 @@
3881338898
void *pStress; /* Argument to xStress */
3881438899
sqlite3_pcache *pCache; /* Pluggable cache module */
3881538900
PgHdr *pPage1; /* Reference to page 1 */
3881638901
};
3881738902
38818
-/*
38819
-** Some of the assert() macros in this code are too expensive to run
38820
-** even during normal debugging. Use them only rarely on long-running
38821
-** tests. Enable the expensive asserts using the
38822
-** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
38823
-*/
38824
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
38825
-# define expensive_assert(X) assert(X)
38826
-#else
38827
-# define expensive_assert(X)
38828
-#endif
38829
-
3883038903
/********************************** Linked List Management ********************/
3883138904
3883238905
/* Allowed values for second argument to pcacheManageDirtyList() */
3883338906
#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
3883438907
#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
@@ -38978,11 +39051,12 @@
3897839051
SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
3897939052
assert( pCache->nRef==0 && pCache->pDirty==0 );
3898039053
if( pCache->szPage ){
3898139054
sqlite3_pcache *pNew;
3898239055
pNew = sqlite3GlobalConfig.pcache2.xCreate(
38983
- szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
39056
+ szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
39057
+ pCache->bPurgeable
3898439058
);
3898539059
if( pNew==0 ) return SQLITE_NOMEM;
3898639060
sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
3898739061
if( pCache->pCache ){
3898839062
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
@@ -39437,11 +39511,11 @@
3943739511
3943839512
/*
3943939513
** Return the size of the header added by this middleware layer
3944039514
** in the page-cache hierarchy.
3944139515
*/
39442
-SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return sizeof(PgHdr); }
39516
+SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
3944339517
3944439518
3944539519
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
3944639520
/*
3944739521
** For all dirty pages currently in the cache, invoke the specified
@@ -39753,11 +39827,11 @@
3975339827
pcache1Free(pPg);
3975439828
sqlite3_free(p);
3975539829
pPg = 0;
3975639830
}
3975739831
#else
39758
- pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
39832
+ pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
3975939833
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
3976039834
#endif
3976139835
pcache1EnterMutex(pCache->pGroup);
3976239836
3976339837
if( pPg ){
@@ -40441,11 +40515,11 @@
4044140515
}
4044240516
4044340517
/*
4044440518
** Return the size of the header on each page of this PCACHE implementation.
4044540519
*/
40446
-SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return sizeof(PgHdr1); }
40520
+SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
4044740521
4044840522
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
4044940523
/*
4045040524
** This function is called to free superfluous dynamically allocated memory
4045140525
** held by the pager system. Memory in use by any SQLite pager allocated
@@ -41799,10 +41873,12 @@
4179941873
u8 eLock; /* Current lock held on database file */
4180041874
u8 changeCountDone; /* Set after incrementing the change-counter */
4180141875
u8 setMaster; /* True if a m-j name has been written to jrnl */
4180241876
u8 doNotSpill; /* Do not spill the cache when non-zero */
4180341877
u8 subjInMemory; /* True to use in-memory sub-journals */
41878
+ u8 bUseFetch; /* True to use xFetch() */
41879
+ u8 hasBeenUsed; /* True if any content previously read from this pager*/
4180441880
Pgno dbSize; /* Number of pages in the database */
4180541881
Pgno dbOrigSize; /* dbSize before the current transaction */
4180641882
Pgno dbFileSize; /* Number of pages in the database file */
4180741883
Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */
4180841884
int errCode; /* One of several kinds of errors */
@@ -41816,13 +41892,13 @@
4181641892
i64 journalOff; /* Current write offset in the journal file */
4181741893
i64 journalHdr; /* Byte offset to previous journal header */
4181841894
sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
4181941895
PagerSavepoint *aSavepoint; /* Array of active savepoints */
4182041896
int nSavepoint; /* Number of elements in aSavepoint[] */
41897
+ u32 iDataVersion; /* Changes whenever database content changes */
4182141898
char dbFileVers[16]; /* Changes whenever database file changes */
4182241899
41823
- u8 bUseFetch; /* True to use xFetch() */
4182441900
int nMmapOut; /* Number of mmap pages currently outstanding */
4182541901
sqlite3_int64 szMmap; /* Desired maximum mmap size */
4182641902
PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
4182741903
/*
4182841904
** End of the routinely-changing class members
@@ -42834,13 +42910,22 @@
4283442910
4283542911
/*
4283642912
** Discard the entire contents of the in-memory page-cache.
4283742913
*/
4283842914
static void pager_reset(Pager *pPager){
42915
+ pPager->iDataVersion++;
4283942916
sqlite3BackupRestart(pPager->pBackup);
4284042917
sqlite3PcacheClear(pPager->pPCache);
4284142918
}
42919
+
42920
+/*
42921
+** Return the pPager->iDataVersion value
42922
+*/
42923
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
42924
+ assert( pPager->eState>PAGER_OPEN );
42925
+ return pPager->iDataVersion;
42926
+}
4284242927
4284342928
/*
4284442929
** Free all structures in the Pager.aSavepoint[] array and set both
4284542930
** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
4284642931
** if it is open and the pager is not in exclusive mode.
@@ -45040,11 +45125,11 @@
4504045125
Pgno pgno, /* Page number */
4504145126
void *pData, /* xFetch()'d data for this page */
4504245127
PgHdr **ppPage /* OUT: Acquired page object */
4504345128
){
4504445129
PgHdr *p; /* Memory mapped page to return */
45045
-
45130
+
4504645131
if( pPager->pMmapFreelist ){
4504745132
*ppPage = p = pPager->pMmapFreelist;
4504845133
pPager->pMmapFreelist = p->pDirty;
4504945134
p->pDirty = 0;
4505045135
memset(p->pExtra, 0, pPager->nExtra);
@@ -46271,20 +46356,16 @@
4627146356
assert( (pPager->eLock==SHARED_LOCK)
4627246357
|| (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
4627346358
);
4627446359
}
4627546360
46276
- if( !pPager->tempFile && (
46277
- pPager->pBackup
46278
- || sqlite3PcachePagecount(pPager->pPCache)>0
46279
- || USEFETCH(pPager)
46280
- )){
46281
- /* The shared-lock has just been acquired on the database file
46282
- ** and there are already pages in the cache (from a previous
46283
- ** read or write transaction). Check to see if the database
46284
- ** has been modified. If the database has changed, flush the
46285
- ** cache.
46361
+ if( !pPager->tempFile && pPager->hasBeenUsed ){
46362
+ /* The shared-lock has just been acquired then check to
46363
+ ** see if the database has been modified. If the database has changed,
46364
+ ** flush the cache. The pPager->hasBeenUsed flag prevents this from
46365
+ ** occurring on the very first access to a file, in order to save a
46366
+ ** single unnecessary sqlite3OsRead() call at the start-up.
4628646367
**
4628746368
** Database changes is detected by looking at 15 bytes beginning
4628846369
** at offset 24 into the file. The first 4 of these 16 bytes are
4628946370
** a 32-bit counter that is incremented with each change. The
4629046371
** other bytes change randomly with each file change when
@@ -46445,10 +46526,11 @@
4644546526
assert( noContent==0 || bMmapOk==0 );
4644646527
4644746528
if( pgno==0 ){
4644846529
return SQLITE_CORRUPT_BKPT;
4644946530
}
46531
+ pPager->hasBeenUsed = 1;
4645046532
4645146533
/* If the pager is in the error state, return an error immediately.
4645246534
** Otherwise, request the page from the PCache layer. */
4645346535
if( pPager->errCode!=SQLITE_OK ){
4645446536
rc = pPager->errCode;
@@ -46594,10 +46676,11 @@
4659446676
sqlite3_pcache_page *pPage;
4659546677
assert( pPager!=0 );
4659646678
assert( pgno!=0 );
4659746679
assert( pPager->pPCache!=0 );
4659846680
pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
46681
+ assert( pPage==0 || pPager->hasBeenUsed );
4659946682
return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
4660046683
}
4660146684
4660246685
/*
4660346686
** Release a page reference.
@@ -47460,10 +47543,11 @@
4746047543
pPager->eState = PAGER_READER;
4746147544
return SQLITE_OK;
4746247545
}
4746347546
4746447547
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
47548
+ pPager->iDataVersion++;
4746547549
rc = pager_end_transaction(pPager, pPager->setMaster, 1);
4746647550
return pager_error(pPager, rc);
4746747551
}
4746847552
4746947553
/*
@@ -50111,11 +50195,11 @@
5011150195
int (*xBusy)(void*), /* Function to call when busy */
5011250196
void *pBusyArg, /* Context argument for xBusyHandler */
5011350197
int sync_flags, /* Flags for OsSync() (or 0) */
5011450198
u8 *zBuf /* Temporary buffer to use */
5011550199
){
50116
- int rc; /* Return code */
50200
+ int rc = SQLITE_OK; /* Return code */
5011750201
int szPage; /* Database page-size */
5011850202
WalIterator *pIter = 0; /* Wal iterator context */
5011950203
u32 iDbpage = 0; /* Next database page to write */
5012050204
u32 iFrame = 0; /* Wal frame containing data for iDbpage */
5012150205
u32 mxSafeFrame; /* Max frame that can be backfilled */
@@ -50125,108 +50209,111 @@
5012550209
5012650210
szPage = walPagesize(pWal);
5012750211
testcase( szPage<=32768 );
5012850212
testcase( szPage>=65536 );
5012950213
pInfo = walCkptInfo(pWal);
50130
- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
50131
-
50132
- /* Allocate the iterator */
50133
- rc = walIteratorInit(pWal, &pIter);
50134
- if( rc!=SQLITE_OK ){
50135
- return rc;
50136
- }
50137
- assert( pIter );
50138
-
50139
- /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
50140
- ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
50141
- assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
50142
-
50143
- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
50144
- ** safe to write into the database. Frames beyond mxSafeFrame might
50145
- ** overwrite database pages that are in use by active readers and thus
50146
- ** cannot be backfilled from the WAL.
50147
- */
50148
- mxSafeFrame = pWal->hdr.mxFrame;
50149
- mxPage = pWal->hdr.nPage;
50150
- for(i=1; i<WAL_NREADER; i++){
50151
- u32 y = pInfo->aReadMark[i];
50152
- if( mxSafeFrame>y ){
50153
- assert( y<=pWal->hdr.mxFrame );
50154
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
50155
- if( rc==SQLITE_OK ){
50156
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
50157
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
50158
- }else if( rc==SQLITE_BUSY ){
50159
- mxSafeFrame = y;
50160
- xBusy = 0;
50161
- }else{
50162
- goto walcheckpoint_out;
50163
- }
50164
- }
50165
- }
50166
-
50167
- if( pInfo->nBackfill<mxSafeFrame
50168
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
50169
- ){
50170
- i64 nSize; /* Current size of database file */
50171
- u32 nBackfill = pInfo->nBackfill;
50172
-
50173
- /* Sync the WAL to disk */
50174
- if( sync_flags ){
50175
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
50176
- }
50177
-
50178
- /* If the database may grow as a result of this checkpoint, hint
50179
- ** about the eventual size of the db file to the VFS layer.
50180
- */
50181
- if( rc==SQLITE_OK ){
50182
- i64 nReq = ((i64)mxPage * szPage);
50183
- rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
50184
- if( rc==SQLITE_OK && nSize<nReq ){
50185
- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
50186
- }
50187
- }
50188
-
50189
-
50190
- /* Iterate through the contents of the WAL, copying data to the db file. */
50191
- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
50192
- i64 iOffset;
50193
- assert( walFramePgno(pWal, iFrame)==iDbpage );
50194
- if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
50195
- iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
50196
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
50197
- rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
50198
- if( rc!=SQLITE_OK ) break;
50199
- iOffset = (iDbpage-1)*(i64)szPage;
50200
- testcase( IS_BIG_INT(iOffset) );
50201
- rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
50202
- if( rc!=SQLITE_OK ) break;
50203
- }
50204
-
50205
- /* If work was actually accomplished... */
50206
- if( rc==SQLITE_OK ){
50207
- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
50208
- i64 szDb = pWal->hdr.nPage*(i64)szPage;
50209
- testcase( IS_BIG_INT(szDb) );
50210
- rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
50211
- if( rc==SQLITE_OK && sync_flags ){
50212
- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
50213
- }
50214
- }
50215
- if( rc==SQLITE_OK ){
50216
- pInfo->nBackfill = mxSafeFrame;
50217
- }
50218
- }
50219
-
50220
- /* Release the reader lock held while backfilling */
50221
- walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
50222
- }
50223
-
50224
- if( rc==SQLITE_BUSY ){
50225
- /* Reset the return code so as not to report a checkpoint failure
50226
- ** just because there are active readers. */
50227
- rc = SQLITE_OK;
50214
+ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
50215
+
50216
+ /* Allocate the iterator */
50217
+ rc = walIteratorInit(pWal, &pIter);
50218
+ if( rc!=SQLITE_OK ){
50219
+ return rc;
50220
+ }
50221
+ assert( pIter );
50222
+
50223
+ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
50224
+ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
50225
+ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
50226
+
50227
+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
50228
+ ** safe to write into the database. Frames beyond mxSafeFrame might
50229
+ ** overwrite database pages that are in use by active readers and thus
50230
+ ** cannot be backfilled from the WAL.
50231
+ */
50232
+ mxSafeFrame = pWal->hdr.mxFrame;
50233
+ mxPage = pWal->hdr.nPage;
50234
+ for(i=1; i<WAL_NREADER; i++){
50235
+ u32 y = pInfo->aReadMark[i];
50236
+ if( mxSafeFrame>y ){
50237
+ assert( y<=pWal->hdr.mxFrame );
50238
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
50239
+ if( rc==SQLITE_OK ){
50240
+ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
50241
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
50242
+ }else if( rc==SQLITE_BUSY ){
50243
+ mxSafeFrame = y;
50244
+ xBusy = 0;
50245
+ }else{
50246
+ goto walcheckpoint_out;
50247
+ }
50248
+ }
50249
+ }
50250
+
50251
+ if( pInfo->nBackfill<mxSafeFrame
50252
+ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
50253
+ ){
50254
+ i64 nSize; /* Current size of database file */
50255
+ u32 nBackfill = pInfo->nBackfill;
50256
+
50257
+ /* Sync the WAL to disk */
50258
+ if( sync_flags ){
50259
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
50260
+ }
50261
+
50262
+ /* If the database may grow as a result of this checkpoint, hint
50263
+ ** about the eventual size of the db file to the VFS layer.
50264
+ */
50265
+ if( rc==SQLITE_OK ){
50266
+ i64 nReq = ((i64)mxPage * szPage);
50267
+ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
50268
+ if( rc==SQLITE_OK && nSize<nReq ){
50269
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
50270
+ }
50271
+ }
50272
+
50273
+
50274
+ /* Iterate through the contents of the WAL, copying data to the db file */
50275
+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
50276
+ i64 iOffset;
50277
+ assert( walFramePgno(pWal, iFrame)==iDbpage );
50278
+ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
50279
+ continue;
50280
+ }
50281
+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
50282
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
50283
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
50284
+ if( rc!=SQLITE_OK ) break;
50285
+ iOffset = (iDbpage-1)*(i64)szPage;
50286
+ testcase( IS_BIG_INT(iOffset) );
50287
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
50288
+ if( rc!=SQLITE_OK ) break;
50289
+ }
50290
+
50291
+ /* If work was actually accomplished... */
50292
+ if( rc==SQLITE_OK ){
50293
+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
50294
+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
50295
+ testcase( IS_BIG_INT(szDb) );
50296
+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
50297
+ if( rc==SQLITE_OK && sync_flags ){
50298
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
50299
+ }
50300
+ }
50301
+ if( rc==SQLITE_OK ){
50302
+ pInfo->nBackfill = mxSafeFrame;
50303
+ }
50304
+ }
50305
+
50306
+ /* Release the reader lock held while backfilling */
50307
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
50308
+ }
50309
+
50310
+ if( rc==SQLITE_BUSY ){
50311
+ /* Reset the return code so as not to report a checkpoint failure
50312
+ ** just because there are active readers. */
50313
+ rc = SQLITE_OK;
50314
+ }
5022850315
}
5022950316
5023050317
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
5023150318
** entire wal file has been copied into the database file, then block
5023250319
** until all readers have finished using the wal file. This ensures that
@@ -50237,11 +50324,11 @@
5023750324
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
5023850325
rc = SQLITE_BUSY;
5023950326
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
5024050327
u32 salt1;
5024150328
sqlite3_randomness(4, &salt1);
50242
- assert( mxSafeFrame==pWal->hdr.mxFrame );
50329
+ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
5024350330
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
5024450331
if( rc==SQLITE_OK ){
5024550332
if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
5024650333
/* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
5024750334
** SQLITE_CHECKPOINT_RESTART with the addition that it also
@@ -50829,11 +50916,11 @@
5082950916
}
5083050917
nCollide = HASHTABLE_NSLOT;
5083150918
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
5083250919
u32 iFrame = aHash[iKey] + iZero;
5083350920
if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
50834
- /* assert( iFrame>iRead ); -- not true if there is corruption */
50921
+ assert( iFrame>iRead || CORRUPT_DB );
5083550922
iRead = iFrame;
5083650923
}
5083750924
if( (nCollide--)==0 ){
5083850925
return SQLITE_CORRUPT_BKPT;
5083950926
}
@@ -51935,10 +52022,11 @@
5193552022
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
5193652023
u8 sharable; /* True if we can share pBt with another db */
5193752024
u8 locked; /* True if db currently has pBt locked */
5193852025
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
5193952026
int nBackup; /* Number of backup operations reading this btree */
52027
+ u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
5194052028
Btree *pNext; /* List of other sharable Btrees from the same db */
5194152029
Btree *pPrev; /* Back pointer of the same list */
5194252030
#ifndef SQLITE_OMIT_SHARED_CACHE
5194352031
BtLock lock; /* Object used to lock page 1 */
5194452032
#endif
@@ -56098,10 +56186,11 @@
5609856186
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
5609956187
if( rc!=SQLITE_OK && bCleanup==0 ){
5610056188
sqlite3BtreeLeave(p);
5610156189
return rc;
5610256190
}
56191
+ p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
5610356192
pBt->inTransaction = TRANS_READ;
5610456193
btreeClearHasContent(pBt);
5610556194
}
5610656195
5610756196
btreeEndTransaction(p);
@@ -56461,11 +56550,11 @@
5646156550
}
5646256551
for(i=0; i<=pCur->iPage; i++){
5646356552
releasePage(pCur->apPage[i]);
5646456553
}
5646556554
unlockBtreeIfUnused(pBt);
56466
- sqlite3DbFree(pBtree->db, pCur->aOverflow);
56555
+ sqlite3_free(pCur->aOverflow);
5646756556
/* sqlite3_free(pCur); */
5646856557
sqlite3BtreeLeave(pBtree);
5646956558
}
5647056559
return SQLITE_OK;
5647156560
}
@@ -56755,10 +56844,11 @@
5675556844
pBuf += a;
5675656845
amt -= a;
5675756846
}else{
5675856847
offset -= pCur->info.nLocal;
5675956848
}
56849
+
5676056850
5676156851
if( rc==SQLITE_OK && amt>0 ){
5676256852
const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
5676356853
Pgno nextPage;
5676456854
@@ -56773,12 +56863,12 @@
5677356863
** means "not yet known" (the cache is lazily populated).
5677456864
*/
5677556865
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
5677656866
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
5677756867
if( nOvfl>pCur->nOvflAlloc ){
56778
- Pgno *aNew = (Pgno*)sqlite3DbRealloc(
56779
- pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
56868
+ Pgno *aNew = (Pgno*)sqlite3Realloc(
56869
+ pCur->aOverflow, nOvfl*2*sizeof(Pgno)
5678056870
);
5678156871
if( aNew==0 ){
5678256872
rc = SQLITE_NOMEM;
5678356873
}else{
5678456874
pCur->nOvflAlloc = nOvfl*2;
@@ -56821,10 +56911,11 @@
5682156911
** Note that the aOverflow[] array must be allocated because eOp!=2
5682256912
** here. If eOp==2, then offset==0 and this branch is never taken.
5682356913
*/
5682456914
assert( eOp!=2 );
5682556915
assert( pCur->curFlags & BTCF_ValidOvfl );
56916
+ assert( pCur->pBtree->db==pBt->db );
5682656917
if( pCur->aOverflow[iIdx+1] ){
5682756918
nextPage = pCur->aOverflow[iIdx+1];
5682856919
}else{
5682956920
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
5683056921
}
@@ -59410,12 +59501,12 @@
5941059501
assert( leafCorrection==4 );
5941159502
if( szCell[nCell]<4 ){
5941259503
/* Do not allow any cells smaller than 4 bytes. If a smaller cell
5941359504
** does exist, pad it with 0x00 bytes. */
5941459505
assert( szCell[nCell]==3 );
59415
- assert( apCell[nCell]==&pTemp[iSpace1-3] );
59416
- pTemp[iSpace1++] = 0x00;
59506
+ assert( apCell[nCell]==&aSpace1[iSpace1-3] );
59507
+ aSpace1[iSpace1++] = 0x00;
5941759508
szCell[nCell] = 4;
5941859509
}
5941959510
}
5942059511
nCell++;
5942159512
}
@@ -60723,10 +60814,17 @@
6072360814
** is read-only, the others are read/write.
6072460815
**
6072560816
** The schema layer numbers meta values differently. At the schema
6072660817
** layer (and the SetCookie and ReadCookie opcodes) the number of
6072760818
** free pages is not visible. So Cookie[0] is the same as Meta[1].
60819
+**
60820
+** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead
60821
+** of reading the value out of the header, it instead loads the "DataVersion"
60822
+** from the pager. The BTREE_DATA_VERSION value is not actually stored in the
60823
+** database file. It is a number computed by the pager. But its access
60824
+** pattern is the same as header meta values, and so it is convenient to
60825
+** read it from this routine.
6072860826
*/
6072960827
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
6073060828
BtShared *pBt = p->pBt;
6073160829
6073260830
sqlite3BtreeEnter(p);
@@ -60733,11 +60831,15 @@
6073360831
assert( p->inTrans>TRANS_NONE );
6073460832
assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
6073560833
assert( pBt->pPage1 );
6073660834
assert( idx>=0 && idx<=15 );
6073760835
60738
- *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
60836
+ if( idx==BTREE_DATA_VERSION ){
60837
+ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
60838
+ }else{
60839
+ *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
60840
+ }
6073960841
6074060842
/* If auto-vacuum is disabled in this build and this is an auto-vacuum
6074160843
** database, mark the database as read-only. */
6074260844
#ifdef SQLITE_OMIT_AUTOVACUUM
6074360845
if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){
@@ -60824,11 +60926,11 @@
6082460926
if( pPage->leaf ){
6082560927
do {
6082660928
if( pCur->iPage==0 ){
6082760929
/* All pages of the b-tree have been visited. Return successfully. */
6082860930
*pnEntry = nEntry;
60829
- return SQLITE_OK;
60931
+ return moveToRoot(pCur);
6083060932
}
6083160933
moveToParent(pCur);
6083260934
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
6083360935
6083460936
pCur->aiIdx[pCur->iPage]++;
@@ -61680,11 +61782,11 @@
6168061782
}
6168161783
6168261784
/*
6168361785
** Return the size of the header added to each page by this module.
6168461786
*/
61685
-SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return sizeof(MemPage); }
61787
+SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
6168661788
6168761789
/************** End of btree.c ***********************************************/
6168861790
/************** Begin file backup.c ******************************************/
6168961791
/*
6169061792
** 2009 January 28
@@ -64444,36 +64546,39 @@
6444464546
**
6444564547
** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) );
6444664548
*/
6444764549
SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
6444864550
int hasAbort = 0;
64551
+ int hasFkCounter = 0;
6444964552
Op *pOp;
6445064553
VdbeOpIter sIter;
6445164554
memset(&sIter, 0, sizeof(sIter));
6445264555
sIter.v = v;
6445364556
6445464557
while( (pOp = opIterNext(&sIter))!=0 ){
6445564558
int opcode = pOp->opcode;
6445664559
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
64457
-#ifndef SQLITE_OMIT_FOREIGN_KEY
64458
- || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
64459
-#endif
6446064560
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
6446164561
&& ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
6446264562
){
6446364563
hasAbort = 1;
6446464564
break;
6446564565
}
64566
+#ifndef SQLITE_OMIT_FOREIGN_KEY
64567
+ if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
64568
+ hasFkCounter = 1;
64569
+ }
64570
+#endif
6446664571
}
6446764572
sqlite3DbFree(v->db, sIter.apSub);
6446864573
6446964574
/* Return true if hasAbort==mayAbort. Or if a malloc failure occurred.
6447064575
** If malloc failed, then the while() loop above may not have iterated
6447164576
** through all opcodes and hasAbort may be set incorrectly. Return
6447264577
** true for this case to prevent the assert() in the callers frame
6447364578
** from failing. */
64474
- return ( v->db->mallocFailed || hasAbort==mayAbort );
64579
+ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
6447564580
}
6447664581
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
6447764582
6447864583
/*
6447964584
** Loop through the program looking for P2 values that are negative
@@ -67394,10 +67499,45 @@
6739467499
if( pKeyInfo->db->mallocFailed ) return 1;
6739567500
return 0;
6739667501
}
6739767502
#endif
6739867503
67504
+#if SQLITE_DEBUG
67505
+/*
67506
+** Count the number of fields (a.k.a. columns) in the record given by
67507
+** pKey,nKey. The verify that this count is less than or equal to the
67508
+** limit given by pKeyInfo->nField + pKeyInfo->nXField.
67509
+**
67510
+** If this constraint is not satisfied, it means that the high-speed
67511
+** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
67512
+** not work correctly. If this assert() ever fires, it probably means
67513
+** that the KeyInfo.nField or KeyInfo.nXField values were computed
67514
+** incorrectly.
67515
+*/
67516
+static void vdbeAssertFieldCountWithinLimits(
67517
+ int nKey, const void *pKey, /* The record to verify */
67518
+ const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
67519
+){
67520
+ int nField = 0;
67521
+ u32 szHdr;
67522
+ u32 idx;
67523
+ u32 notUsed;
67524
+ const unsigned char *aKey = (const unsigned char*)pKey;
67525
+
67526
+ if( CORRUPT_DB ) return;
67527
+ idx = getVarint32(aKey, szHdr);
67528
+ assert( szHdr<=nKey );
67529
+ while( idx<szHdr ){
67530
+ idx += getVarint32(aKey+idx, notUsed);
67531
+ nField++;
67532
+ }
67533
+ assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
67534
+}
67535
+#else
67536
+# define vdbeAssertFieldCountWithinLimits(A,B,C)
67537
+#endif
67538
+
6739967539
/*
6740067540
** Both *pMem1 and *pMem2 contain string values. Compare the two values
6740167541
** using the collation sequence pColl. As usual, return a negative , zero
6740267542
** or positive value if *pMem1 is less than, equal to or greater than
6740367543
** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
@@ -67805,10 +67945,11 @@
6780567945
u32 y;
6780667946
u64 x;
6780767947
i64 v = pPKey2->aMem[0].u.i;
6780867948
i64 lhs;
6780967949
67950
+ vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
6781067951
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
6781167952
switch( serial_type ){
6781267953
case 1: { /* 1-byte signed integer */
6781367954
lhs = ONE_BYTE_INT(aKey);
6781467955
testcase( lhs<0 );
@@ -67892,10 +68033,11 @@
6789268033
){
6789368034
const u8 *aKey1 = (const u8*)pKey1;
6789468035
int serial_type;
6789568036
int res;
6789668037
68038
+ vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
6789768039
getVarint32(&aKey1[1], serial_type);
6789868040
if( serial_type<12 ){
6789968041
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
6790068042
}else if( !(serial_type & 0x01) ){
6790168043
res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
@@ -68593,11 +68735,14 @@
6859368735
#ifndef SQLITE_OMIT_WAL
6859468736
int i;
6859568737
for(i=0; i<db->nDb; i++){
6859668738
Btree *pBt = db->aDb[i].pBt;
6859768739
if( pBt ){
68598
- int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
68740
+ int nEntry;
68741
+ sqlite3BtreeEnter(pBt);
68742
+ nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
68743
+ sqlite3BtreeLeave(pBt);
6859968744
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
6860068745
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
6860168746
}
6860268747
}
6860368748
}
@@ -68773,11 +68918,10 @@
6877368918
** program counter to 0 to ensure that when the statement is
6877468919
** finalized or reset the parser error message is available via
6877568920
** sqlite3_errmsg() and sqlite3_errcode().
6877668921
*/
6877768922
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
68778
- assert( zErr!=0 || db->mallocFailed );
6877968923
sqlite3DbFree(db, v->zErrMsg);
6878068924
if( !db->mallocFailed ){
6878168925
v->zErrMsg = sqlite3DbStrDup(db, zErr);
6878268926
v->rc = rc2;
6878368927
} else {
@@ -73838,12 +73982,12 @@
7383873982
pIdxKey->default_rc = 0;
7383973983
if( pOp->opcode==OP_NoConflict ){
7384073984
/* For the OP_NoConflict opcode, take the jump if any of the
7384173985
** input fields are NULL, since any key with a NULL will not
7384273986
** conflict */
73843
- for(ii=0; ii<r.nField; ii++){
73844
- if( r.aMem[ii].flags & MEM_Null ){
73987
+ for(ii=0; ii<pIdxKey->nField; ii++){
73988
+ if( pIdxKey->aMem[ii].flags & MEM_Null ){
7384573989
pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
7384673990
break;
7384773991
}
7384873992
}
7384973993
}
@@ -77135,11 +77279,11 @@
7713577279
/*
7713677280
** Hard-coded maximum amount of data to accumulate in memory before flushing
7713777281
** to a level 0 PMA. The purpose of this limit is to prevent various integer
7713877282
** overflows. 512MiB.
7713977283
*/
77140
-#define SQLITE_MAX_MXPMASIZE (1<<29)
77284
+#define SQLITE_MAX_PMASZ (1<<29)
7714177285
7714277286
/*
7714377287
** Private objects used by the sorter
7714477288
*/
7714577289
typedef struct MergeEngine MergeEngine; /* Merge PMAs together */
@@ -77431,15 +77575,10 @@
7743177575
**
7743277576
** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; }
7743377577
*/
7743477578
#define SRVAL(p) ((void*)((SorterRecord*)(p) + 1))
7743577579
77436
-/* The minimum PMA size is set to this value multiplied by the database
77437
-** page size in bytes. */
77438
-#ifndef SQLITE_SORTER_PMASZ
77439
-# define SQLITE_SORTER_PMASZ 10
77440
-#endif
7744177580
7744277581
/* Maximum number of PMAs that a single MergeEngine can merge */
7744377582
#define SORTER_MAX_MERGE_COUNT 16
7744477583
7744577584
static int vdbeIncrSwap(IncrMerger*);
@@ -77834,14 +77973,15 @@
7783477973
SortSubtask *pTask = &pSorter->aTask[i];
7783577974
pTask->pSorter = pSorter;
7783677975
}
7783777976
7783877977
if( !sqlite3TempInMemory(db) ){
77839
- pSorter->mnPmaSize = SQLITE_SORTER_PMASZ * pgsz;
77978
+ u32 szPma = sqlite3GlobalConfig.szPma;
77979
+ pSorter->mnPmaSize = szPma * pgsz;
7784077980
mxCache = db->aDb[0].pSchema->cache_size;
77841
- if( mxCache<SQLITE_SORTER_PMASZ ) mxCache = SQLITE_SORTER_PMASZ;
77842
- pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_MXPMASIZE);
77981
+ if( mxCache<(int)szPma ) mxCache = (int)szPma;
77982
+ pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
7784377983
7784477984
/* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
7784577985
** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
7784677986
** large heap allocations.
7784777987
*/
@@ -78115,16 +78255,16 @@
7811578255
** Whether or not the file does end up memory mapped of course depends on
7811678256
** the specific VFS implementation.
7811778257
*/
7811878258
static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
7811978259
if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
78120
- int rc = sqlite3OsTruncate(pFd, nByte);
78121
- if( rc==SQLITE_OK ){
78122
- void *p = 0;
78123
- sqlite3OsFetch(pFd, 0, (int)nByte, &p);
78124
- sqlite3OsUnfetch(pFd, 0, p);
78125
- }
78260
+ void *p = 0;
78261
+ int chunksize = 4*1024;
78262
+ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
78263
+ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
78264
+ sqlite3OsFetch(pFd, 0, (int)nByte, &p);
78265
+ sqlite3OsUnfetch(pFd, 0, p);
7812678266
}
7812778267
}
7812878268
#else
7812978269
# define vdbeSorterExtendFile(x,y,z)
7813078270
#endif
@@ -79401,10 +79541,11 @@
7940179541
rc = vdbePmaReaderNext(pSorter->pReader);
7940279542
*pbEof = (pSorter->pReader->pFd==0);
7940379543
}else
7940479544
#endif
7940579545
/*if( !pSorter->bUseThreads )*/ {
79546
+ assert( pSorter->pMerger!=0 );
7940679547
assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
7940779548
rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
7940879549
}
7940979550
}else{
7941079551
SorterRecord *pFree = pSorter->list.pList;
@@ -82167,11 +82308,11 @@
8216782308
Expr *pLeft, /* Left operand */
8216882309
Expr *pRight, /* Right operand */
8216982310
const Token *pToken /* Argument token */
8217082311
){
8217182312
Expr *p;
82172
- if( op==TK_AND && pLeft && pRight ){
82313
+ if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
8217382314
/* Take advantage of short-circuit false optimization for AND */
8217482315
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
8217582316
}else{
8217682317
p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
8217782318
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
@@ -85721,14 +85862,15 @@
8572185862
** NEVER() will need to be removed. */
8572285863
if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){
8572385864
int i;
8572485865
struct SrcCount *p = pWalker->u.pSrcCount;
8572585866
SrcList *pSrc = p->pSrc;
85726
- for(i=0; i<pSrc->nSrc; i++){
85867
+ int nSrc = pSrc ? pSrc->nSrc : 0;
85868
+ for(i=0; i<nSrc; i++){
8572785869
if( pExpr->iTable==pSrc->a[i].iCursor ) break;
8572885870
}
85729
- if( i<pSrc->nSrc ){
85871
+ if( i<nSrc ){
8573085872
p->nThis++;
8573185873
}else{
8573285874
p->nOther++;
8573385875
}
8573485876
}
@@ -87302,11 +87444,11 @@
8730287444
8730387445
p->iGet = -1;
8730487446
p->mxSample = mxSample;
8730587447
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
8730687448
p->current.anLt = &p->current.anEq[nColUp];
87307
- p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565;
87449
+ p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
8730887450
8730987451
/* Set up the Stat4Accum.a[] and aBest[] arrays */
8731087452
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
8731187453
p->aBest = &p->a[mxSample];
8731287454
pSpace = (u8*)(&p->a[mxSample+nCol]);
@@ -88895,17 +89037,19 @@
8889589037
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
8889689038
zErrDyn = sqlite3MPrintf(db,
8889789039
"attached databases must use the same text encoding as main database");
8889889040
rc = SQLITE_ERROR;
8889989041
}
89042
+ sqlite3BtreeEnter(aNew->pBt);
8890089043
pPager = sqlite3BtreePager(aNew->pBt);
8890189044
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
8890289045
sqlite3BtreeSecureDelete(aNew->pBt,
8890389046
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
8890489047
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
8890589048
sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
8890689049
#endif
89050
+ sqlite3BtreeLeave(aNew->pBt);
8890789051
}
8890889052
aNew->safety_level = 3;
8890989053
aNew->zName = sqlite3DbStrDup(db, zName);
8891089054
if( rc==SQLITE_OK && aNew->zName==0 ){
8891189055
rc = SQLITE_NOMEM;
@@ -90027,11 +90171,10 @@
9002790171
*/
9002890172
static void freeIndex(sqlite3 *db, Index *p){
9002990173
#ifndef SQLITE_OMIT_ANALYZE
9003090174
sqlite3DeleteIndexSamples(db, p);
9003190175
#endif
90032
- if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
9003390176
sqlite3ExprDelete(db, p->pPartIdxWhere);
9003490177
sqlite3DbFree(db, p->zColAff);
9003590178
if( p->isResized ) sqlite3DbFree(db, p->azColl);
9003690179
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
9003790180
sqlite3_free(p->aiRowEst);
@@ -91306,10 +91449,23 @@
9130691449
if( pPk==0 ) return;
9130791450
pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
9130891451
pTab->iPKey = -1;
9130991452
}else{
9131091453
pPk = sqlite3PrimaryKeyIndex(pTab);
91454
+ /*
91455
+ ** Remove all redundant columns from the PRIMARY KEY. For example, change
91456
+ ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
91457
+ ** code assumes the PRIMARY KEY contains no repeated columns.
91458
+ */
91459
+ for(i=j=1; i<pPk->nKeyCol; i++){
91460
+ if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
91461
+ pPk->nColumn--;
91462
+ }else{
91463
+ pPk->aiColumn[j++] = pPk->aiColumn[i];
91464
+ }
91465
+ }
91466
+ pPk->nKeyCol = j;
9131191467
}
9131291468
pPk->isCovering = 1;
9131391469
assert( pPk!=0 );
9131491470
nPk = pPk->nKeyCol;
9131591471
@@ -93782,44 +93938,35 @@
9378293938
**
9378393939
** The caller should invoke sqlite3KeyInfoUnref() on the returned object
9378493940
** when it has finished using it.
9378593941
*/
9378693942
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
93943
+ int i;
93944
+ int nCol = pIdx->nColumn;
93945
+ int nKey = pIdx->nKeyCol;
93946
+ KeyInfo *pKey;
9378793947
if( pParse->nErr ) return 0;
93788
-#ifndef SQLITE_OMIT_SHARED_CACHE
93789
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){
93790
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
93791
- pIdx->pKeyInfo = 0;
93792
- }
93793
-#endif
93794
- if( pIdx->pKeyInfo==0 ){
93795
- int i;
93796
- int nCol = pIdx->nColumn;
93797
- int nKey = pIdx->nKeyCol;
93798
- KeyInfo *pKey;
93799
- if( pIdx->uniqNotNull ){
93800
- pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
93801
- }else{
93802
- pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
93803
- }
93804
- if( pKey ){
93805
- assert( sqlite3KeyInfoIsWriteable(pKey) );
93806
- for(i=0; i<nCol; i++){
93807
- char *zColl = pIdx->azColl[i];
93808
- assert( zColl!=0 );
93809
- pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
93810
- sqlite3LocateCollSeq(pParse, zColl);
93811
- pKey->aSortOrder[i] = pIdx->aSortOrder[i];
93812
- }
93813
- if( pParse->nErr ){
93814
- sqlite3KeyInfoUnref(pKey);
93815
- }else{
93816
- pIdx->pKeyInfo = pKey;
93817
- }
93818
- }
93819
- }
93820
- return sqlite3KeyInfoRef(pIdx->pKeyInfo);
93948
+ if( pIdx->uniqNotNull ){
93949
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
93950
+ }else{
93951
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
93952
+ }
93953
+ if( pKey ){
93954
+ assert( sqlite3KeyInfoIsWriteable(pKey) );
93955
+ for(i=0; i<nCol; i++){
93956
+ char *zColl = pIdx->azColl[i];
93957
+ assert( zColl!=0 );
93958
+ pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
93959
+ sqlite3LocateCollSeq(pParse, zColl);
93960
+ pKey->aSortOrder[i] = pIdx->aSortOrder[i];
93961
+ }
93962
+ if( pParse->nErr ){
93963
+ sqlite3KeyInfoUnref(pKey);
93964
+ pKey = 0;
93965
+ }
93966
+ }
93967
+ return pKey;
9382193968
}
9382293969
9382393970
#ifndef SQLITE_OMIT_CTE
9382493971
/*
9382593972
** This routine is invoked once per CTE by the parser while parsing a
@@ -94596,12 +94743,12 @@
9459694743
const char *zDb; /* Name of database holding pTab */
9459794744
int i; /* Loop counter */
9459894745
WhereInfo *pWInfo; /* Information about the WHERE clause */
9459994746
Index *pIdx; /* For looping over indices of the table */
9460094747
int iTabCur; /* Cursor number for the table */
94601
- int iDataCur; /* VDBE cursor for the canonical data source */
94602
- int iIdxCur; /* Cursor number of the first index */
94748
+ int iDataCur = 0; /* VDBE cursor for the canonical data source */
94749
+ int iIdxCur = 0; /* Cursor number of the first index */
9460394750
int nIdx; /* Number of indices */
9460494751
sqlite3 *db; /* Main database structure */
9460594752
AuthContext sContext; /* Authorization context */
9460694753
NameContext sNC; /* Name context to resolve expressions in */
9460794754
int iDb; /* Database number */
@@ -97436,11 +97583,11 @@
9743697583
assert( nIncr==1 );
9743797584
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
9743897585
OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
9743997586
}else{
9744097587
if( nIncr>0 && pFKey->isDeferred==0 ){
97441
- sqlite3ParseToplevel(pParse)->mayAbort = 1;
97588
+ sqlite3MayAbort(pParse);
9744297589
}
9744397590
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
9744497591
}
9744597592
9744697593
sqlite3VdbeResolveLabel(v, iOk);
@@ -97507,10 +97654,14 @@
9750797654
** This function is called to generate code executed when a row is deleted
9750897655
** from the parent table of foreign key constraint pFKey and, if pFKey is
9750997656
** deferred, when a row is inserted into the same table. When generating
9751097657
** code for an SQL UPDATE operation, this function may be called twice -
9751197658
** once to "delete" the old row and once to "insert" the new row.
97659
+**
97660
+** Parameter nIncr is passed -1 when inserting a row (as this may decrease
97661
+** the number of FK violations in the db) or +1 when deleting one (as this
97662
+** may increase the number of FK constraint problems).
9751297663
**
9751397664
** The code generated by this function scans through the rows in the child
9751497665
** table that correspond to the parent table row being deleted or inserted.
9751597666
** For each child row found, one of the following actions is taken:
9751697667
**
@@ -97624,17 +97775,13 @@
9762497775
sNameContext.pSrcList = pSrc;
9762597776
sNameContext.pParse = pParse;
9762697777
sqlite3ResolveExprNames(&sNameContext, pWhere);
9762797778
9762897779
/* Create VDBE to loop through the entries in pSrc that match the WHERE
97629
- ** clause. If the constraint is not deferred, throw an exception for
97630
- ** each row found. Otherwise, for deferred constraints, increment the
97631
- ** deferred constraint counter by nIncr for each row selected. */
97780
+ ** clause. For each row found, increment either the deferred or immediate
97781
+ ** foreign key constraint counter. */
9763297782
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
97633
- if( nIncr>0 && pFKey->isDeferred==0 ){
97634
- sqlite3ParseToplevel(pParse)->mayAbort = 1;
97635
- }
9763697783
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
9763797784
if( pWInfo ){
9763897785
sqlite3WhereEnd(pWInfo);
9763997786
}
9764097787
@@ -97808,10 +97955,28 @@
9780897955
}
9780997956
}
9781097957
}
9781197958
return 0;
9781297959
}
97960
+
97961
+/*
97962
+** Return true if the parser passed as the first argument is being
97963
+** used to code a trigger that is really a "SET NULL" action belonging
97964
+** to trigger pFKey.
97965
+*/
97966
+static int isSetNullAction(Parse *pParse, FKey *pFKey){
97967
+ Parse *pTop = sqlite3ParseToplevel(pParse);
97968
+ if( pTop->pTriggerPrg ){
97969
+ Trigger *p = pTop->pTriggerPrg->pTrigger;
97970
+ if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
97971
+ || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
97972
+ ){
97973
+ return 1;
97974
+ }
97975
+ }
97976
+ return 0;
97977
+}
9781397978
9781497979
/*
9781597980
** This function is called when inserting, deleting or updating a row of
9781697981
** table pTab to generate VDBE code to perform foreign key constraint
9781797982
** processing for the operation.
@@ -97861,11 +98026,11 @@
9786198026
Index *pIdx = 0; /* Index on key columns in pTo */
9786298027
int *aiFree = 0;
9786398028
int *aiCol;
9786498029
int iCol;
9786598030
int i;
97866
- int isIgnore = 0;
98031
+ int bIgnore = 0;
9786798032
9786898033
if( aChange
9786998034
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
9787098035
&& fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
9787198036
){
@@ -97920,11 +98085,11 @@
9792098085
** values read from the parent table are NULL. */
9792198086
if( db->xAuth ){
9792298087
int rcauth;
9792398088
char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
9792498089
rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
97925
- isIgnore = (rcauth==SQLITE_IGNORE);
98090
+ bIgnore = (rcauth==SQLITE_IGNORE);
9792698091
}
9792798092
#endif
9792898093
}
9792998094
9793098095
/* Take a shared-cache advisory read-lock on the parent table. Allocate
@@ -97935,16 +98100,22 @@
9793598100
9793698101
if( regOld!=0 ){
9793798102
/* A row is being removed from the child table. Search for the parent.
9793898103
** If the parent does not exist, removing the child row resolves an
9793998104
** outstanding foreign key constraint violation. */
97940
- fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore);
98105
+ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
9794198106
}
97942
- if( regNew!=0 ){
98107
+ if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
9794398108
/* A row is being added to the child table. If a parent row cannot
97944
- ** be found, adding the child row has violated the FK constraint. */
97945
- fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore);
98109
+ ** be found, adding the child row has violated the FK constraint.
98110
+ **
98111
+ ** If this operation is being performed as part of a trigger program
98112
+ ** that is actually a "SET NULL" action belonging to this very
98113
+ ** foreign key, then omit this scan altogether. As all child key
98114
+ ** values are guaranteed to be NULL, it is not possible for adding
98115
+ ** this row to cause an FK violation. */
98116
+ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore);
9794698117
}
9794798118
9794898119
sqlite3DbFree(db, aiFree);
9794998120
}
9795098121
@@ -97961,12 +98132,12 @@
9796198132
9796298133
if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
9796398134
&& !pParse->pToplevel && !pParse->isMultiWrite
9796498135
){
9796598136
assert( regOld==0 && regNew!=0 );
97966
- /* Inserting a single row into a parent table cannot cause an immediate
97967
- ** foreign key violation. So do nothing in this case. */
98137
+ /* Inserting a single row into a parent table cannot cause (or fix)
98138
+ ** an immediate foreign key violation. So do nothing in this case. */
9796898139
continue;
9796998140
}
9797098141
9797198142
if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
9797298143
if( !isIgnoreErrors || db->mallocFailed ) return;
@@ -97986,17 +98157,32 @@
9798698157
9798798158
if( regNew!=0 ){
9798898159
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
9798998160
}
9799098161
if( regOld!=0 ){
97991
- /* If there is a RESTRICT action configured for the current operation
97992
- ** on the parent table of this FK, then throw an exception
97993
- ** immediately if the FK constraint is violated, even if this is a
97994
- ** deferred trigger. That's what RESTRICT means. To defer checking
97995
- ** the constraint, the FK should specify NO ACTION (represented
97996
- ** using OE_None). NO ACTION is the default. */
98162
+ int eAction = pFKey->aAction[aChange!=0];
9799798163
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
98164
+ /* If this is a deferred FK constraint, or a CASCADE or SET NULL
98165
+ ** action applies, then any foreign key violations caused by
98166
+ ** removing the parent key will be rectified by the action trigger.
98167
+ ** So do not set the "may-abort" flag in this case.
98168
+ **
98169
+ ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the
98170
+ ** may-abort flag will eventually be set on this statement anyway
98171
+ ** (when this function is called as part of processing the UPDATE
98172
+ ** within the action trigger).
98173
+ **
98174
+ ** Note 2: At first glance it may seem like SQLite could simply omit
98175
+ ** all OP_FkCounter related scans when either CASCADE or SET NULL
98176
+ ** applies. The trouble starts if the CASCADE or SET NULL action
98177
+ ** trigger causes other triggers or action rules attached to the
98178
+ ** child table to fire. In these cases the fk constraint counters
98179
+ ** might be set incorrectly if any OP_FkCounter related scans are
98180
+ ** omitted. */
98181
+ if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
98182
+ sqlite3MayAbort(pParse);
98183
+ }
9799898184
}
9799998185
pItem->zName = 0;
9800098186
sqlite3SrcListDelete(db, pSrc);
9800198187
}
9800298188
sqlite3DbFree(db, aiCol);
@@ -101895,10 +102081,11 @@
101895102081
#define PragTyp_KEY 38
101896102082
#define PragTyp_REKEY 39
101897102083
#define PragTyp_LOCK_STATUS 40
101898102084
#define PragTyp_PARSER_TRACE 41
101899102085
#define PragFlag_NeedSchema 0x01
102086
+#define PragFlag_ReadOnly 0x02
101900102087
static const struct sPragmaNames {
101901102088
const char *const zName; /* Name of pragma */
101902102089
u8 ePragTyp; /* PragTyp_XXX value */
101903102090
u8 mPragFlag; /* Zero or more PragFlag_XXX values */
101904102091
u32 iArg; /* Extra argument */
@@ -101911,11 +102098,11 @@
101911102098
#endif
101912102099
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
101913102100
{ /* zName: */ "application_id",
101914102101
/* ePragTyp: */ PragTyp_HEADER_VALUE,
101915102102
/* ePragFlag: */ 0,
101916
- /* iArg: */ 0 },
102103
+ /* iArg: */ BTREE_APPLICATION_ID },
101917102104
#endif
101918102105
#if !defined(SQLITE_OMIT_AUTOVACUUM)
101919102106
{ /* zName: */ "auto_vacuum",
101920102107
/* ePragTyp: */ PragTyp_AUTO_VACUUM,
101921102108
/* ePragFlag: */ PragFlag_NeedSchema,
@@ -101977,10 +102164,16 @@
101977102164
{ /* zName: */ "data_store_directory",
101978102165
/* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
101979102166
/* ePragFlag: */ 0,
101980102167
/* iArg: */ 0 },
101981102168
#endif
102169
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102170
+ { /* zName: */ "data_version",
102171
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
102172
+ /* ePragFlag: */ PragFlag_ReadOnly,
102173
+ /* iArg: */ BTREE_DATA_VERSION },
102174
+#endif
101982102175
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
101983102176
{ /* zName: */ "database_list",
101984102177
/* ePragTyp: */ PragTyp_DATABASE_LIST,
101985102178
/* ePragFlag: */ PragFlag_NeedSchema,
101986102179
/* iArg: */ 0 },
@@ -102032,12 +102225,12 @@
102032102225
#endif
102033102226
#endif
102034102227
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102035102228
{ /* zName: */ "freelist_count",
102036102229
/* ePragTyp: */ PragTyp_HEADER_VALUE,
102037
- /* ePragFlag: */ 0,
102038
- /* iArg: */ 0 },
102230
+ /* ePragFlag: */ PragFlag_ReadOnly,
102231
+ /* iArg: */ BTREE_FREE_PAGE_COUNT },
102039102232
#endif
102040102233
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
102041102234
{ /* zName: */ "full_column_names",
102042102235
/* ePragTyp: */ PragTyp_FLAG,
102043102236
/* ePragFlag: */ 0,
@@ -102185,11 +102378,11 @@
102185102378
#endif
102186102379
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102187102380
{ /* zName: */ "schema_version",
102188102381
/* ePragTyp: */ PragTyp_HEADER_VALUE,
102189102382
/* ePragFlag: */ 0,
102190
- /* iArg: */ 0 },
102383
+ /* iArg: */ BTREE_SCHEMA_VERSION },
102191102384
#endif
102192102385
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
102193102386
{ /* zName: */ "secure_delete",
102194102387
/* ePragTyp: */ PragTyp_SECURE_DELETE,
102195102388
/* ePragFlag: */ 0,
@@ -102251,11 +102444,11 @@
102251102444
/* iArg: */ 0 },
102252102445
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102253102446
{ /* zName: */ "user_version",
102254102447
/* ePragTyp: */ PragTyp_HEADER_VALUE,
102255102448
/* ePragFlag: */ 0,
102256
- /* iArg: */ 0 },
102449
+ /* iArg: */ BTREE_USER_VERSION },
102257102450
#endif
102258102451
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
102259102452
#if defined(SQLITE_DEBUG)
102260102453
{ /* zName: */ "vdbe_addoptrace",
102261102454
/* ePragTyp: */ PragTyp_FLAG,
@@ -102294,11 +102487,11 @@
102294102487
/* ePragTyp: */ PragTyp_FLAG,
102295102488
/* ePragFlag: */ 0,
102296102489
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
102297102490
#endif
102298102491
};
102299
-/* Number of pragmas: 57 on by default, 70 total. */
102492
+/* Number of pragmas: 58 on by default, 71 total. */
102300102493
/* End of the automatically generated pragma table.
102301102494
***************************************************************************/
102302102495
102303102496
/*
102304102497
** Interpret the given string as a safety level. Return 0 for OFF,
@@ -102544,11 +102737,11 @@
102544102737
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
102545102738
const char *zDb = 0; /* The database name */
102546102739
Token *pId; /* Pointer to <id> token */
102547102740
char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
102548102741
int iDb; /* Database index for <database> */
102549
- int lwr, upr, mid; /* Binary search bounds */
102742
+ int lwr, upr, mid = 0; /* Binary search bounds */
102550102743
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
102551102744
sqlite3 *db = pParse->db; /* The database connection */
102552102745
Db *pDb; /* The specific database being pragmaed */
102553102746
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
102554102747
@@ -103904,11 +104097,12 @@
103904104097
!(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
103905104098
DbHasProperty(db, 0, DB_Empty)
103906104099
){
103907104100
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
103908104101
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
103909
- ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
104102
+ SCHEMA_ENC(db) = ENC(db) =
104103
+ pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
103910104104
break;
103911104105
}
103912104106
}
103913104107
if( !pEnc->zName ){
103914104108
sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
@@ -103949,28 +104143,13 @@
103949104143
**
103950104144
** The user-version is not used internally by SQLite. It may be used by
103951104145
** applications for any purpose.
103952104146
*/
103953104147
case PragTyp_HEADER_VALUE: {
103954
- int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
104148
+ int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */
103955104149
sqlite3VdbeUsesBtree(v, iDb);
103956
- switch( zLeft[0] ){
103957
- case 'a': case 'A':
103958
- iCookie = BTREE_APPLICATION_ID;
103959
- break;
103960
- case 'f': case 'F':
103961
- iCookie = BTREE_FREE_PAGE_COUNT;
103962
- break;
103963
- case 's': case 'S':
103964
- iCookie = BTREE_SCHEMA_VERSION;
103965
- break;
103966
- default:
103967
- iCookie = BTREE_USER_VERSION;
103968
- break;
103969
- }
103970
-
103971
- if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){
104150
+ if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){
103972104151
/* Write the specified cookie value */
103973104152
static const VdbeOpList setCookie[] = {
103974104153
{ OP_Transaction, 0, 1, 0}, /* 0 */
103975104154
{ OP_Integer, 0, 1, 0}, /* 1 */
103976104155
{ OP_SetCookie, 0, 0, 1}, /* 2 */
@@ -104612,13 +104791,15 @@
104612104791
SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
104613104792
int i, rc;
104614104793
int commit_internal = !(db->flags&SQLITE_InternChanges);
104615104794
104616104795
assert( sqlite3_mutex_held(db->mutex) );
104796
+ assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
104617104797
assert( db->init.busy==0 );
104618104798
rc = SQLITE_OK;
104619104799
db->init.busy = 1;
104800
+ ENC(db) = SCHEMA_ENC(db);
104620104801
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
104621104802
if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
104622104803
rc = sqlite3InitOne(db, i, pzErrMsg);
104623104804
if( rc ){
104624104805
sqlite3ResetOneSchema(db, i);
@@ -105169,24 +105350,29 @@
105169105350
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
105170105351
};
105171105352
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
105172105353
105173105354
/*
105174
-** Delete all the content of a Select structure but do not deallocate
105175
-** the select structure itself.
105355
+** Delete all the content of a Select structure. Deallocate the structure
105356
+** itself only if bFree is true.
105176105357
*/
105177
-static void clearSelect(sqlite3 *db, Select *p){
105178
- sqlite3ExprListDelete(db, p->pEList);
105179
- sqlite3SrcListDelete(db, p->pSrc);
105180
- sqlite3ExprDelete(db, p->pWhere);
105181
- sqlite3ExprListDelete(db, p->pGroupBy);
105182
- sqlite3ExprDelete(db, p->pHaving);
105183
- sqlite3ExprListDelete(db, p->pOrderBy);
105184
- sqlite3SelectDelete(db, p->pPrior);
105185
- sqlite3ExprDelete(db, p->pLimit);
105186
- sqlite3ExprDelete(db, p->pOffset);
105187
- sqlite3WithDelete(db, p->pWith);
105358
+static void clearSelect(sqlite3 *db, Select *p, int bFree){
105359
+ while( p ){
105360
+ Select *pPrior = p->pPrior;
105361
+ sqlite3ExprListDelete(db, p->pEList);
105362
+ sqlite3SrcListDelete(db, p->pSrc);
105363
+ sqlite3ExprDelete(db, p->pWhere);
105364
+ sqlite3ExprListDelete(db, p->pGroupBy);
105365
+ sqlite3ExprDelete(db, p->pHaving);
105366
+ sqlite3ExprListDelete(db, p->pOrderBy);
105367
+ sqlite3ExprDelete(db, p->pLimit);
105368
+ sqlite3ExprDelete(db, p->pOffset);
105369
+ sqlite3WithDelete(db, p->pWith);
105370
+ if( bFree ) sqlite3DbFree(db, p);
105371
+ p = pPrior;
105372
+ bFree = 1;
105373
+ }
105188105374
}
105189105375
105190105376
/*
105191105377
** Initialize a SelectDest structure.
105192105378
*/
@@ -105241,12 +105427,11 @@
105241105427
pNew->pOffset = pOffset;
105242105428
assert( pOffset==0 || pLimit!=0 );
105243105429
pNew->addrOpenEphm[0] = -1;
105244105430
pNew->addrOpenEphm[1] = -1;
105245105431
if( db->mallocFailed ) {
105246
- clearSelect(db, pNew);
105247
- if( pNew!=&standin ) sqlite3DbFree(db, pNew);
105432
+ clearSelect(db, pNew, pNew!=&standin);
105248105433
pNew = 0;
105249105434
}else{
105250105435
assert( pNew->pSrc!=0 || pParse->nErr>0 );
105251105436
}
105252105437
assert( pNew!=&standin );
@@ -105267,14 +105452,11 @@
105267105452
105268105453
/*
105269105454
** Delete the given Select structure and all of its substructures.
105270105455
*/
105271105456
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
105272
- if( p ){
105273
- clearSelect(db, p);
105274
- sqlite3DbFree(db, p);
105275
- }
105457
+ clearSelect(db, p, 1);
105276105458
}
105277105459
105278105460
/*
105279105461
** Return a pointer to the right-most SELECT statement in a compound.
105280105462
*/
@@ -105653,11 +105835,13 @@
105653105835
if( pParse->db->mallocFailed ) return;
105654105836
pOp->p2 = nKey + nData;
105655105837
pKI = pOp->p4.pKeyInfo;
105656105838
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
105657105839
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
105658
- pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
105840
+ testcase( pKI->nXField>2 );
105841
+ pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
105842
+ pKI->nXField-1);
105659105843
addrJmp = sqlite3VdbeCurrentAddr(v);
105660105844
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
105661105845
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
105662105846
pSort->regReturn = ++pParse->nMem;
105663105847
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
@@ -106164,11 +106348,11 @@
106164106348
struct ExprList_item *pItem;
106165106349
sqlite3 *db = pParse->db;
106166106350
int i;
106167106351
106168106352
nExpr = pList->nExpr;
106169
- pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
106353
+ pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1);
106170106354
if( pInfo ){
106171106355
assert( sqlite3KeyInfoIsWriteable(pInfo) );
106172106356
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
106173106357
CollSeq *pColl;
106174106358
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
@@ -107186,10 +107370,70 @@
107186107370
Parse *pParse, /* Parsing context */
107187107371
Select *p, /* The right-most of SELECTs to be coded */
107188107372
SelectDest *pDest /* What to do with query results */
107189107373
);
107190107374
107375
+/*
107376
+** Error message for when two or more terms of a compound select have different
107377
+** size result sets.
107378
+*/
107379
+static void selectWrongNumTermsError(Parse *pParse, Select *p){
107380
+ if( p->selFlags & SF_Values ){
107381
+ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
107382
+ }else{
107383
+ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
107384
+ " do not have the same number of result columns", selectOpName(p->op));
107385
+ }
107386
+}
107387
+
107388
+/*
107389
+** Handle the special case of a compound-select that originates from a
107390
+** VALUES clause. By handling this as a special case, we avoid deep
107391
+** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
107392
+** on a VALUES clause.
107393
+**
107394
+** Because the Select object originates from a VALUES clause:
107395
+** (1) It has no LIMIT or OFFSET
107396
+** (2) All terms are UNION ALL
107397
+** (3) There is no ORDER BY clause
107398
+*/
107399
+static int multiSelectValues(
107400
+ Parse *pParse, /* Parsing context */
107401
+ Select *p, /* The right-most of SELECTs to be coded */
107402
+ SelectDest *pDest /* What to do with query results */
107403
+){
107404
+ Select *pPrior;
107405
+ int nExpr = p->pEList->nExpr;
107406
+ int nRow = 1;
107407
+ int rc = 0;
107408
+ assert( p->pNext==0 );
107409
+ assert( p->selFlags & SF_AllValues );
107410
+ do{
107411
+ assert( p->selFlags & SF_Values );
107412
+ assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
107413
+ assert( p->pLimit==0 );
107414
+ assert( p->pOffset==0 );
107415
+ if( p->pEList->nExpr!=nExpr ){
107416
+ selectWrongNumTermsError(pParse, p);
107417
+ return 1;
107418
+ }
107419
+ if( p->pPrior==0 ) break;
107420
+ assert( p->pPrior->pNext==p );
107421
+ p = p->pPrior;
107422
+ nRow++;
107423
+ }while(1);
107424
+ while( p ){
107425
+ pPrior = p->pPrior;
107426
+ p->pPrior = 0;
107427
+ rc = sqlite3Select(pParse, p, pDest);
107428
+ p->pPrior = pPrior;
107429
+ if( rc ) break;
107430
+ p->nSelectRow = nRow;
107431
+ p = p->pNext;
107432
+ }
107433
+ return rc;
107434
+}
107191107435
107192107436
/*
107193107437
** This routine is called to process a compound query form from
107194107438
** two or more separate queries using UNION, UNION ALL, EXCEPT, or
107195107439
** INTERSECT
@@ -107266,22 +107510,24 @@
107266107510
assert( p->pEList );
107267107511
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
107268107512
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
107269107513
dest.eDest = SRT_Table;
107270107514
}
107515
+
107516
+ /* Special handling for a compound-select that originates as a VALUES clause.
107517
+ */
107518
+ if( p->selFlags & SF_AllValues ){
107519
+ rc = multiSelectValues(pParse, p, &dest);
107520
+ goto multi_select_end;
107521
+ }
107271107522
107272107523
/* Make sure all SELECTs in the statement have the same number of elements
107273107524
** in their result sets.
107274107525
*/
107275107526
assert( p->pEList && pPrior->pEList );
107276107527
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
107277
- if( p->selFlags & SF_Values ){
107278
- sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
107279
- }else{
107280
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
107281
- " do not have the same number of result columns", selectOpName(p->op));
107282
- }
107528
+ selectWrongNumTermsError(pParse, p);
107283107529
rc = 1;
107284107530
goto multi_select_end;
107285107531
}
107286107532
107287107533
#ifndef SQLITE_OMIT_CTE
@@ -109163,11 +109409,13 @@
109163109409
if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
109164109410
return WRC_Prune;
109165109411
}
109166109412
pTabList = p->pSrc;
109167109413
pEList = p->pEList;
109168
- sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
109414
+ if( pWalker->xSelectCallback2==selectPopWith ){
109415
+ sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
109416
+ }
109169109417
109170109418
/* Make sure cursor numbers have been assigned to all entries in
109171109419
** the FROM clause of the SELECT statement.
109172109420
*/
109173109421
sqlite3SrcListAssignCursors(pParse, pTabList);
@@ -109454,11 +109702,13 @@
109454109702
if( pParse->hasCompound ){
109455109703
w.xSelectCallback = convertCompoundSelectToSubquery;
109456109704
sqlite3WalkSelect(&w, pSelect);
109457109705
}
109458109706
w.xSelectCallback = selectExpander;
109459
- w.xSelectCallback2 = selectPopWith;
109707
+ if( (pSelect->selFlags & SF_AllValues)==0 ){
109708
+ w.xSelectCallback2 = selectPopWith;
109709
+ }
109460109710
sqlite3WalkSelect(&w, pSelect);
109461109711
}
109462109712
109463109713
109464109714
#ifndef SQLITE_OMIT_SUBQUERY
@@ -109968,11 +110218,11 @@
109968110218
** we figure out that the sorting index is not needed. The addrSortIndex
109969110219
** variable is used to facilitate that change.
109970110220
*/
109971110221
if( sSort.pOrderBy ){
109972110222
KeyInfo *pKeyInfo;
109973
- pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
110223
+ pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
109974110224
sSort.iECursor = pParse->nTab++;
109975110225
sSort.addrSortIndex =
109976110226
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
109977110227
sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
109978110228
(char*)pKeyInfo, P4_KEYINFO
@@ -110142,11 +110392,11 @@
110142110392
** implement it. Allocate that sorting index now. If it turns out
110143110393
** that we do not need it after all, the OP_SorterOpen instruction
110144110394
** will be converted into a Noop.
110145110395
*/
110146110396
sAggInfo.sortingIdx = pParse->nTab++;
110147
- pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
110397
+ pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
110148110398
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
110149110399
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
110150110400
0, (char*)pKeyInfo, P4_KEYINFO);
110151110401
110152110402
/* Initialize memory locations used by GROUP BY aggregate processing
@@ -110756,11 +111006,11 @@
110756111006
){
110757111007
int rc;
110758111008
TabResult res;
110759111009
110760111010
#ifdef SQLITE_ENABLE_API_ARMOR
110761
- if( pazResult==0 ) return SQLITE_MISUSE_BKPT;
111011
+ if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT;
110762111012
#endif
110763111013
*pazResult = 0;
110764111014
if( pnColumn ) *pnColumn = 0;
110765111015
if( pnRow ) *pnRow = 0;
110766111016
if( pzErrMsg ) *pzErrMsg = 0;
@@ -118626,11 +118876,10 @@
118626118876
sqlite3_free(p->u.vtab.idxStr);
118627118877
p->u.vtab.needFree = 0;
118628118878
p->u.vtab.idxStr = 0;
118629118879
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
118630118880
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
118631
- sqlite3KeyInfoUnref(p->u.btree.pIndex->pKeyInfo);
118632118881
sqlite3DbFree(db, p->u.btree.pIndex);
118633118882
p->u.btree.pIndex = 0;
118634118883
}
118635118884
}
118636118885
}
@@ -123783,17 +124032,23 @@
123783124032
Select *p = yymsp[0].minor.yy3, *pNext, *pLoop;
123784124033
if( p ){
123785124034
int cnt = 0, mxSelect;
123786124035
p->pWith = yymsp[-1].minor.yy59;
123787124036
if( p->pPrior ){
124037
+ u16 allValues = SF_Values;
123788124038
pNext = 0;
123789124039
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
123790124040
pLoop->pNext = pNext;
123791124041
pLoop->selFlags |= SF_Compound;
124042
+ allValues &= pLoop->selFlags;
123792124043
}
123793
- mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
123794
- if( mxSelect && cnt>mxSelect ){
124044
+ if( allValues ){
124045
+ p->selFlags |= SF_AllValues;
124046
+ }else if(
124047
+ (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
124048
+ && cnt>mxSelect
124049
+ ){
123795124050
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
123796124051
}
123797124052
}
123798124053
}else{
123799124054
sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
@@ -125633,10 +125888,13 @@
125633125888
u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
125634125889
sqlite3 *db = pParse->db; /* The database connection */
125635125890
int mxSqlLen; /* Max length of an SQL string */
125636125891
125637125892
125893
+#ifdef SQLITE_ENABLE_API_ARMOR
125894
+ if( zSql==0 || pzErrMsg==0 ) return SQLITE_MISUSE_BKPT;
125895
+#endif
125638125896
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
125639125897
if( db->nVdbeActive==0 ){
125640125898
db->u1.isInterrupted = 0;
125641125899
}
125642125900
pParse->rc = SQLITE_OK;
@@ -125871,17 +126129,10 @@
125871126129
*/
125872126130
SQLITE_API int sqlite3_complete(const char *zSql){
125873126131
u8 state = 0; /* Current state, using numbers defined in header comment */
125874126132
u8 token; /* Value of the next token */
125875126133
125876
-#ifdef SQLITE_ENABLE_API_ARMOR
125877
- if( zSql==0 ){
125878
- (void)SQLITE_MISUSE_BKPT;
125879
- return 0;
125880
- }
125881
-#endif
125882
-
125883126134
#ifndef SQLITE_OMIT_TRIGGER
125884126135
/* A complex statement machine used to detect the end of a CREATE TRIGGER
125885126136
** statement. This is the normal case.
125886126137
*/
125887126138
static const u8 trans[8][8] = {
@@ -125906,10 +126157,17 @@
125906126157
/* 0 INVALID: */ { 1, 0, 2, },
125907126158
/* 1 START: */ { 1, 1, 2, },
125908126159
/* 2 NORMAL: */ { 1, 2, 2, },
125909126160
};
125910126161
#endif /* SQLITE_OMIT_TRIGGER */
126162
+
126163
+#ifdef SQLITE_ENABLE_API_ARMOR
126164
+ if( zSql==0 ){
126165
+ (void)SQLITE_MISUSE_BKPT;
126166
+ return 0;
126167
+ }
126168
+#endif
125911126169
125912126170
while( *zSql ){
125913126171
switch( *zSql ){
125914126172
case ';': { /* A semicolon */
125915126173
token = tkSEMI;
@@ -126208,11 +126466,11 @@
126208126466
** If the following function pointer is not NULL and if
126209126467
** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
126210126468
** I/O active are written using this function. These messages
126211126469
** are intended for debugging activity only.
126212126470
*/
126213
-SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*, ...) = 0;
126471
+/* not-private */ void (*sqlite3IoTrace)(const char*, ...) = 0;
126214126472
#endif
126215126473
126216126474
/*
126217126475
** If the following global variable points to a string which is the
126218126476
** name of a directory, then that directory will be used to store
@@ -126417,10 +126675,17 @@
126417126675
** routine is not threadsafe. But it is safe to invoke this routine
126418126676
** on when SQLite is already shut down. If SQLite is already shut down
126419126677
** when this routine is invoked, then this routine is a harmless no-op.
126420126678
*/
126421126679
SQLITE_API int sqlite3_shutdown(void){
126680
+#ifdef SQLITE_OMIT_WSD
126681
+ int rc = sqlite3_wsd_init(4096, 24);
126682
+ if( rc!=SQLITE_OK ){
126683
+ return rc;
126684
+ }
126685
+#endif
126686
+
126422126687
if( sqlite3GlobalConfig.isInit ){
126423126688
#ifdef SQLITE_EXTRA_SHUTDOWN
126424126689
void SQLITE_EXTRA_SHUTDOWN(void);
126425126690
SQLITE_EXTRA_SHUTDOWN();
126426126691
#endif
@@ -126732,10 +126997,15 @@
126732126997
** heap. */
126733126998
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
126734126999
break;
126735127000
}
126736127001
#endif
127002
+
127003
+ case SQLITE_CONFIG_PMASZ: {
127004
+ sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int);
127005
+ break;
127006
+ }
126737127007
126738127008
default: {
126739127009
rc = SQLITE_ERROR;
126740127010
break;
126741127011
}
@@ -127178,20 +127448,10 @@
127178127448
127179127449
/* Close all database connections */
127180127450
for(j=0; j<db->nDb; j++){
127181127451
struct Db *pDb = &db->aDb[j];
127182127452
if( pDb->pBt ){
127183
- if( pDb->pSchema ){
127184
- /* Must clear the KeyInfo cache. See ticket [e4a18565a36884b00edf] */
127185
- sqlite3BtreeEnter(pDb->pBt);
127186
- for(i=sqliteHashFirst(&pDb->pSchema->idxHash); i; i=sqliteHashNext(i)){
127187
- Index *pIdx = sqliteHashData(i);
127188
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
127189
- pIdx->pKeyInfo = 0;
127190
- }
127191
- sqlite3BtreeLeave(pDb->pBt);
127192
- }
127193127453
sqlite3BtreeClose(pDb->pBt);
127194127454
pDb->pBt = 0;
127195127455
if( j!=1 ){
127196127456
pDb->pSchema = 0;
127197127457
}
@@ -127494,11 +127754,11 @@
127494127754
*/
127495127755
static int sqliteDefaultBusyCallback(
127496127756
void *ptr, /* Database connection */
127497127757
int count /* Number of times table has been busy */
127498127758
){
127499
-#if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
127759
+#if SQLITE_OS_WIN || HAVE_USLEEP
127500127760
static const u8 delays[] =
127501127761
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
127502127762
static const u8 totals[] =
127503127763
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
127504127764
# define NDELAY ArraySize(delays)
@@ -128110,10 +128370,11 @@
128110128370
}
128111128371
if( iDb<0 ){
128112128372
rc = SQLITE_ERROR;
128113128373
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
128114128374
}else{
128375
+ db->busyHandler.nBusy = 0;
128115128376
rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
128116128377
sqlite3Error(db, rc);
128117128378
}
128118128379
rc = sqlite3ApiExit(db, rc);
128119128380
sqlite3_mutex_leave(db->mutex);
@@ -128315,36 +128576,10 @@
128315128576
*/
128316128577
SQLITE_API const char *sqlite3_errstr(int rc){
128317128578
return sqlite3ErrStr(rc);
128318128579
}
128319128580
128320
-/*
128321
-** Invalidate all cached KeyInfo objects for database connection "db"
128322
-*/
128323
-static void invalidateCachedKeyInfo(sqlite3 *db){
128324
- Db *pDb; /* A single database */
128325
- int iDb; /* The database index number */
128326
- HashElem *k; /* For looping over tables in pDb */
128327
- Table *pTab; /* A table in the database */
128328
- Index *pIdx; /* Each index */
128329
-
128330
- for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
128331
- if( pDb->pBt==0 ) continue;
128332
- sqlite3BtreeEnter(pDb->pBt);
128333
- for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
128334
- pTab = (Table*)sqliteHashData(k);
128335
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
128336
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){
128337
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
128338
- pIdx->pKeyInfo = 0;
128339
- }
128340
- }
128341
- }
128342
- sqlite3BtreeLeave(pDb->pBt);
128343
- }
128344
-}
128345
-
128346128581
/*
128347128582
** Create a new collating function for database "db". The name is zName
128348128583
** and the encoding is enc.
128349128584
*/
128350128585
static int createCollation(
@@ -128384,11 +128619,10 @@
128384128619
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
128385128620
"unable to delete/modify collation sequence due to active statements");
128386128621
return SQLITE_BUSY;
128387128622
}
128388128623
sqlite3ExpirePreparedStatements(db);
128389
- invalidateCachedKeyInfo(db);
128390128624
128391128625
/* If collation sequence pColl was created directly by a call to
128392128626
** sqlite3_create_collation, and not generated by synthCollSeq(),
128393128627
** then any copies made by synthCollSeq() need to be invalidated.
128394128628
** Also, collation destructor - CollSeq.xDel() - function may need
@@ -128941,10 +129175,11 @@
128941129175
sqlite3Error(db, rc);
128942129176
goto opendb_out;
128943129177
}
128944129178
sqlite3BtreeEnter(db->aDb[0].pBt);
128945129179
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
129180
+ if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
128946129181
sqlite3BtreeLeave(db->aDb[0].pBt);
128947129182
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
128948129183
128949129184
/* The default safety_level for the main database is 'full'; for the temp
128950129185
** database it is 'NONE'. This matches the pager layer defaults.
@@ -129099,11 +129334,11 @@
129099129334
if( zFilename8 ){
129100129335
rc = openDatabase(zFilename8, ppDb,
129101129336
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
129102129337
assert( *ppDb || rc==SQLITE_NOMEM );
129103129338
if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
129104
- ENC(*ppDb) = SQLITE_UTF16NATIVE;
129339
+ SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
129105129340
}
129106129341
}else{
129107129342
rc = SQLITE_NOMEM;
129108129343
}
129109129344
sqlite3ValueFree(pVal);
@@ -129310,11 +129545,11 @@
129310129545
){
129311129546
int rc;
129312129547
char *zErrMsg = 0;
129313129548
Table *pTab = 0;
129314129549
Column *pCol = 0;
129315
- int iCol;
129550
+ int iCol = 0;
129316129551
129317129552
char const *zDataType = 0;
129318129553
char const *zCollSeq = 0;
129319129554
int notnull = 0;
129320129555
int primarykey = 0;
@@ -129841,32 +130076,34 @@
129841130076
/*
129842130077
** Return the filename of the database associated with a database
129843130078
** connection.
129844130079
*/
129845130080
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
130081
+ Btree *pBt;
129846130082
#ifdef SQLITE_ENABLE_API_ARMOR
129847130083
if( !sqlite3SafetyCheckOk(db) ){
129848130084
(void)SQLITE_MISUSE_BKPT;
129849130085
return 0;
129850130086
}
129851130087
#endif
129852
- Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
130088
+ pBt = sqlite3DbNameToBtree(db, zDbName);
129853130089
return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
129854130090
}
129855130091
129856130092
/*
129857130093
** Return 1 if database is read-only or 0 if read/write. Return -1 if
129858130094
** no such database exists.
129859130095
*/
129860130096
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
130097
+ Btree *pBt;
129861130098
#ifdef SQLITE_ENABLE_API_ARMOR
129862130099
if( !sqlite3SafetyCheckOk(db) ){
129863130100
(void)SQLITE_MISUSE_BKPT;
129864130101
return -1;
129865130102
}
129866130103
#endif
129867
- Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
130104
+ pBt = sqlite3DbNameToBtree(db, zDbName);
129868130105
return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
129869130106
}
129870130107
129871130108
/************** End of main.c ************************************************/
129872130109
/************** Begin file notify.c ******************************************/
@@ -132931,11 +133168,11 @@
132931133168
const char *zNode, /* Buffer containing segment interior node */
132932133169
int nNode, /* Size of buffer at zNode */
132933133170
sqlite3_int64 *piLeaf, /* Selected leaf node */
132934133171
sqlite3_int64 *piLeaf2 /* Selected leaf node */
132935133172
){
132936
- int rc; /* Return code */
133173
+ int rc = SQLITE_OK; /* Return code */
132937133174
int iHeight; /* Height of this node in tree */
132938133175
132939133176
assert( piLeaf || piLeaf2 );
132940133177
132941133178
fts3GetVarint32(zNode, &iHeight);
@@ -132942,11 +133179,11 @@
132942133179
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
132943133180
assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
132944133181
132945133182
if( rc==SQLITE_OK && iHeight>1 ){
132946133183
char *zBlob = 0; /* Blob read from %_segments table */
132947
- int nBlob; /* Size of zBlob in bytes */
133184
+ int nBlob = 0; /* Size of zBlob in bytes */
132948133185
132949133186
if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
132950133187
rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
132951133188
if( rc==SQLITE_OK ){
132952133189
rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0);
@@ -134164,11 +134401,11 @@
134164134401
int idxNum, /* Strategy index */
134165134402
const char *idxStr, /* Unused */
134166134403
int nVal, /* Number of elements in apVal */
134167134404
sqlite3_value **apVal /* Arguments for the indexing scheme */
134168134405
){
134169
- int rc;
134406
+ int rc = SQLITE_OK;
134170134407
char *zSql; /* SQL statement used to access %_content */
134171134408
int eSearch;
134172134409
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
134173134410
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
134174134411
@@ -140652,11 +140889,11 @@
140652140889
int argc, /* Number of elements in argv array */
140653140890
const char * const *argv, /* xCreate/xConnect argument array */
140654140891
sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
140655140892
char **pzErr /* OUT: sqlite3_malloc'd error message */
140656140893
){
140657
- Fts3tokTable *pTab;
140894
+ Fts3tokTable *pTab = 0;
140658140895
const sqlite3_tokenizer_module *pMod = 0;
140659140896
sqlite3_tokenizer *pTok = 0;
140660140897
int rc;
140661140898
char **azDequote = 0;
140662140899
int nDequote;
@@ -144027,12 +144264,12 @@
144027144264
}
144028144265
rc = sqlite3_reset(pRange);
144029144266
144030144267
if( bOk ){
144031144268
int iIdx = 0;
144032
- sqlite3_stmt *pUpdate1;
144033
- sqlite3_stmt *pUpdate2;
144269
+ sqlite3_stmt *pUpdate1 = 0;
144270
+ sqlite3_stmt *pUpdate2 = 0;
144034144271
144035144272
if( rc==SQLITE_OK ){
144036144273
rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0);
144037144274
}
144038144275
if( rc==SQLITE_OK ){
@@ -149260,17 +149497,16 @@
149260149497
*/
149261149498
static int readInt16(u8 *p){
149262149499
return (p[0]<<8) + p[1];
149263149500
}
149264149501
static void readCoord(u8 *p, RtreeCoord *pCoord){
149265
- u32 i = (
149502
+ pCoord->u = (
149266149503
(((u32)p[0]) << 24) +
149267149504
(((u32)p[1]) << 16) +
149268149505
(((u32)p[2]) << 8) +
149269149506
(((u32)p[3]) << 0)
149270149507
);
149271
- *(u32 *)pCoord = i;
149272149508
}
149273149509
static i64 readInt64(u8 *p){
149274149510
return (
149275149511
(((i64)p[0]) << 56) +
149276149512
(((i64)p[1]) << 48) +
@@ -149295,11 +149531,11 @@
149295149531
}
149296149532
static int writeCoord(u8 *p, RtreeCoord *pCoord){
149297149533
u32 i;
149298149534
assert( sizeof(RtreeCoord)==4 );
149299149535
assert( sizeof(u32)==4 );
149300
- i = *(u32 *)pCoord;
149536
+ i = pCoord->u;
149301149537
p[0] = (i>>24)&0xFF;
149302149538
p[1] = (i>>16)&0xFF;
149303149539
p[2] = (i>> 8)&0xFF;
149304149540
p[3] = (i>> 0)&0xFF;
149305149541
return 4;
@@ -149626,18 +149862,17 @@
149626149862
RtreeNode *pNode, /* The node containing the cell to be read */
149627149863
int iCell, /* Index of the cell within the node */
149628149864
RtreeCell *pCell /* OUT: Write the cell contents here */
149629149865
){
149630149866
u8 *pData;
149631
- u8 *pEnd;
149632149867
RtreeCoord *pCoord;
149868
+ int ii;
149633149869
pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
149634149870
pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
149635
- pEnd = pData + pRtree->nDim*8;
149636149871
pCoord = pCell->aCoord;
149637
- for(; pData<pEnd; pData+=4, pCoord++){
149638
- readCoord(pData, pCoord);
149872
+ for(ii=0; ii<pRtree->nDim*2; ii++){
149873
+ readCoord(&pData[ii*4], &pCoord[ii]);
149639149874
}
149640149875
}
149641149876
149642149877
149643149878
/* Forward declaration for the function that does the work of
@@ -150073,11 +150308,11 @@
150073150308
}
150074150309
i = pCur->nPoint++;
150075150310
pNew = pCur->aPoint + i;
150076150311
pNew->rScore = rScore;
150077150312
pNew->iLevel = iLevel;
150078
- assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH );
150313
+ assert( iLevel<=RTREE_MAX_DEPTH );
150079150314
while( i>0 ){
150080150315
RtreeSearchPoint *pParent;
150081150316
j = (i-1)/2;
150082150317
pParent = pCur->aPoint + j;
150083150318
if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break;
@@ -151696,10 +151931,12 @@
151696151931
RtreeCell cell; /* New cell to insert if nData>1 */
151697151932
int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
151698151933
151699151934
rtreeReference(pRtree);
151700151935
assert(nData>=1);
151936
+
151937
+ cell.iRowid = 0; /* Used only to suppress a compiler warning */
151701151938
151702151939
/* Constraint handling. A write operation on an r-tree table may return
151703151940
** SQLITE_CONSTRAINT for two reasons:
151704151941
**
151705151942
** 1. A duplicate rowid value, or
151706151943
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.8.8. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -41,10 +41,57 @@
41 **
42 */
43 #ifndef _SQLITEINT_H_
44 #define _SQLITEINT_H_
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46 /*
47 ** These #defines should enable >2GB file support on POSIX if the
48 ** underlying operating system supports it. If the OS lacks
49 ** large file support, or if the OS is windows, these should be no-ops.
50 **
@@ -229,13 +276,13 @@
229 **
230 ** See also: [sqlite3_libversion()],
231 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
232 ** [sqlite_version()] and [sqlite_source_id()].
233 */
234 #define SQLITE_VERSION "3.8.8"
235 #define SQLITE_VERSION_NUMBER 3008008
236 #define SQLITE_SOURCE_ID "2014-12-10 04:58:43 3528f8dd39acace8eeb7337994c8617313f4b04b"
237
238 /*
239 ** CAPI3REF: Run-Time Library Version Numbers
240 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
241 **
@@ -323,11 +370,11 @@
323 ** This interface only reports on the compile-time mutex setting
324 ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
325 ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
326 ** can be fully or partially disabled using a call to [sqlite3_config()]
327 ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
328 ** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
329 ** sqlite3_threadsafe() function shows only the compile-time setting of
330 ** thread safety, not any run-time changes to that setting made by
331 ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
332 ** is unchanged by calls to sqlite3_config().)^
333 **
@@ -1692,11 +1739,11 @@
1692 ** configuration option.
1693 ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
1694 ** 8-byte aligned
1695 ** memory, the size of each page buffer (sz), and the number of pages (N).
1696 ** The sz argument should be the size of the largest database page
1697 ** (a power of two between 512 and 32768) plus some extra bytes for each
1698 ** page header. ^The number of extra bytes needed by the page header
1699 ** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
1700 ** to [sqlite3_config()].
1701 ** ^It is harmless, apart from the wasted memory,
1702 ** for the sz parameter to be larger than necessary. The first
@@ -1872,10 +1919,21 @@
1872 ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
1873 ** is a pointer to an integer and writes into that integer the number of extra
1874 ** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
1875 ** The amount of extra space required can change depending on the compiler,
1876 ** target platform, and SQLite version.
 
 
 
 
 
 
 
 
 
 
 
1877 ** </dl>
1878 */
1879 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
1880 #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
1881 #define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1898,10 +1956,11 @@
1898 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
1899 #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
1900 #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
1901 #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
1902 #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
 
1903
1904 /*
1905 ** CAPI3REF: Database Connection Configuration Options
1906 **
1907 ** These constants are the available integer configuration options that
@@ -7307,16 +7366,14 @@
7307
7308 /*
7309 ** CAPI3REF: Write-Ahead Log Commit Hook
7310 **
7311 ** ^The [sqlite3_wal_hook()] function is used to register a callback that
7312 ** will be invoked each time a database connection commits data to a
7313 ** [write-ahead log] (i.e. whenever a transaction is committed in
7314 ** [journal_mode | journal_mode=WAL mode]).
7315 **
7316 ** ^The callback is invoked by SQLite after the commit has taken place and
7317 ** the associated write-lock on the database released, so the implementation
7318 ** may read, write or [checkpoint] the database as required.
7319 **
7320 ** ^The first parameter passed to the callback function when it is invoked
7321 ** is a copy of the third parameter passed to sqlite3_wal_hook() when
7322 ** registering the callback. ^The second is a copy of the database handle.
@@ -7603,10 +7660,14 @@
7603 **
7604 ** The following constants can be used for the T parameter to the
7605 ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
7606 ** different metric for sqlite3_stmt_scanstatus() to return.
7607 **
 
 
 
 
7608 ** <dl>
7609 ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
7610 ** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
7611 ** set to the total number of times that the X-th loop has run.</dd>
7612 **
@@ -7648,11 +7709,18 @@
7648 #define SQLITE_SCANSTAT_SELECTID 5
7649
7650 /*
7651 ** CAPI3REF: Prepared Statement Scan Status
7652 **
7653 ** Return status data for a single loop within query pStmt.
 
 
 
 
 
 
 
7654 **
7655 ** The "iScanStatusOp" parameter determines which status information to return.
7656 ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
7657 ** of this interface is undefined.
7658 ** ^The requested measurement is written into a variable pointed to by
@@ -7666,13 +7734,10 @@
7666 ** ^Statistics might not be available for all loops in all statements. ^In cases
7667 ** where there exist loops with no available statistics, this function behaves
7668 ** as if the loop did not exist - it returns non-zero and leave the variable
7669 ** that pOut points to unchanged.
7670 **
7671 ** This API is only available if the library is built with pre-processor
7672 ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
7673 **
7674 ** See also: [sqlite3_stmt_scanstatus_reset()]
7675 */
7676 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
7677 sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
7678 int idx, /* Index of loop to report on */
@@ -9100,11 +9165,11 @@
9100 #define _BTREE_H_
9101
9102 /* TODO: This definition is just included so other modules compile. It
9103 ** needs to be revisited.
9104 */
9105 #define SQLITE_N_BTREE_META 10
9106
9107 /*
9108 ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
9109 ** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
9110 */
@@ -9215,10 +9280,15 @@
9215 ** offset = 36 + (idx * 4)
9216 **
9217 ** For example, the free-page-count field is located at byte offset 36 of
9218 ** the database file header. The incr-vacuum-flag field is located at
9219 ** byte offset 64 (== 36+4*7).
 
 
 
 
 
9220 */
9221 #define BTREE_FREE_PAGE_COUNT 0
9222 #define BTREE_SCHEMA_VERSION 1
9223 #define BTREE_FILE_FORMAT 2
9224 #define BTREE_DEFAULT_CACHE_SIZE 3
@@ -9225,10 +9295,11 @@
9225 #define BTREE_LARGEST_ROOT_PAGE 4
9226 #define BTREE_TEXT_ENCODING 5
9227 #define BTREE_USER_VERSION 6
9228 #define BTREE_INCR_VACUUM 7
9229 #define BTREE_APPLICATION_ID 8
 
9230
9231 /*
9232 ** Values that may be OR'd together to form the second argument of an
9233 ** sqlite3BtreeCursorHints() call.
9234 */
@@ -10006,10 +10077,11 @@
10006 SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
10007 #endif
10008
10009 /* Functions used to query pager state and configuration. */
10010 SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
 
10011 SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
10012 SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
10013 SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
10014 SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
10015 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
@@ -10747,10 +10819,11 @@
10747 i64 szMmap; /* Default mmap_size setting */
10748 unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
10749 int errCode; /* Most recent error code (SQLITE_*) */
10750 int errMask; /* & result codes with this before returning */
10751 u16 dbOptFlags; /* Flags to enable/disable optimizations */
 
10752 u8 autoCommit; /* The auto-commit flag. */
10753 u8 temp_store; /* 1: file 2: memory 0: default */
10754 u8 mallocFailed; /* True if we have seen a malloc failure */
10755 u8 dfltLockMode; /* Default locking-mode for attached dbs */
10756 signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
@@ -10848,11 +10921,12 @@
10848 };
10849
10850 /*
10851 ** A macro to discover the encoding of a database.
10852 */
10853 #define ENC(db) ((db)->aDb[0].pSchema->enc)
 
10854
10855 /*
10856 ** Possible values for the sqlite3.flags.
10857 */
10858 #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
@@ -11472,11 +11546,10 @@
11472 Index *pNext; /* The next index associated with the same table */
11473 Schema *pSchema; /* Schema containing this index */
11474 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
11475 char **azColl; /* Array of collation sequence names for index */
11476 Expr *pPartIdxWhere; /* WHERE clause for partial indices */
11477 KeyInfo *pKeyInfo; /* A KeyInfo object suitable for this index */
11478 int tnum; /* DB Page containing root of this index */
11479 LogEst szIdxRow; /* Estimated average row size in bytes */
11480 u16 nKeyCol; /* Number of columns forming the key */
11481 u16 nColumn; /* Number of columns stored in the index */
11482 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
@@ -12036,11 +12109,11 @@
12036 #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
12037 #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
12038 #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
12039 #define SF_Compound 0x0040 /* Part of a compound query */
12040 #define SF_Values 0x0080 /* Synthesized from VALUES clause */
12041 /* 0x0100 NOT USED */
12042 #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
12043 #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
12044 #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
12045 #define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
12046
@@ -12526,10 +12599,11 @@
12526 void *pPage; /* Page cache memory */
12527 int szPage; /* Size of each page in pPage[] */
12528 int nPage; /* Number of pages in pPage[] */
12529 int mxParserStack; /* maximum depth of the parser stack */
12530 int sharedCacheEnabled; /* true if shared-cache mode enabled */
 
12531 /* The above might be initialized to non-zero. The following need to always
12532 ** initially be zero, however. */
12533 int isInit; /* True after initialization has finished */
12534 int inProgress; /* True while initialization in progress */
12535 int isMutexInit; /* True after mutexes are initialized */
@@ -12663,11 +12737,11 @@
12663 ** FTS4 is really an extension for FTS3. It is enabled using the
12664 ** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call
12665 ** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
12666 */
12667 #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
12668 # define SQLITE_ENABLE_FTS3
12669 #endif
12670
12671 /*
12672 ** The ctype.h header is needed for non-ASCII systems. It is also
12673 ** needed by FTS3 when FTS3 is included in the amalgamation.
@@ -13448,11 +13522,11 @@
13448 ** print I/O tracing messages.
13449 */
13450 #ifdef SQLITE_ENABLE_IOTRACE
13451 # define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
13452 SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*);
13453 SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
13454 #else
13455 # define IOTRACE(A)
13456 # define sqlite3VdbeIOTraceSql(X)
13457 #endif
13458
@@ -13661,10 +13735,17 @@
13661 */
13662 #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
13663 # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
13664 #endif
13665
 
 
 
 
 
 
 
13666 /*
13667 ** The following singleton contains the global configuration for
13668 ** the SQLite library.
13669 */
13670 SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
@@ -13691,10 +13772,11 @@
13691 (void*)0, /* pPage */
13692 0, /* szPage */
13693 0, /* nPage */
13694 0, /* mxParserStack */
13695 0, /* sharedCacheEnabled */
 
13696 /* All the rest should always be initialized to zero */
13697 0, /* isInit */
13698 0, /* inProgress */
13699 0, /* isMutexInit */
13700 0, /* isMallocInit */
@@ -13797,355 +13879,355 @@
13797 /* These macros are provided to "stringify" the value of the define
13798 ** for those options in which the value is meaningful. */
13799 #define CTIMEOPT_VAL_(opt) #opt
13800 #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
13801
13802 #ifdef SQLITE_32BIT_ROWID
13803 "32BIT_ROWID",
13804 #endif
13805 #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
13806 "4_BYTE_ALIGNED_MALLOC",
13807 #endif
13808 #ifdef SQLITE_CASE_SENSITIVE_LIKE
13809 "CASE_SENSITIVE_LIKE",
13810 #endif
13811 #ifdef SQLITE_CHECK_PAGES
13812 "CHECK_PAGES",
13813 #endif
13814 #ifdef SQLITE_COVERAGE_TEST
13815 "COVERAGE_TEST",
13816 #endif
13817 #ifdef SQLITE_DEBUG
13818 "DEBUG",
13819 #endif
13820 #ifdef SQLITE_DEFAULT_LOCKING_MODE
13821 "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
13822 #endif
13823 #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
13824 "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
13825 #endif
13826 #ifdef SQLITE_DISABLE_DIRSYNC
13827 "DISABLE_DIRSYNC",
13828 #endif
13829 #ifdef SQLITE_DISABLE_LFS
13830 "DISABLE_LFS",
13831 #endif
13832 #ifdef SQLITE_ENABLE_API_ARMOR
13833 "ENABLE_API_ARMOR",
13834 #endif
13835 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
13836 "ENABLE_ATOMIC_WRITE",
13837 #endif
13838 #ifdef SQLITE_ENABLE_CEROD
13839 "ENABLE_CEROD",
13840 #endif
13841 #ifdef SQLITE_ENABLE_COLUMN_METADATA
13842 "ENABLE_COLUMN_METADATA",
13843 #endif
13844 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
13845 "ENABLE_EXPENSIVE_ASSERT",
13846 #endif
13847 #ifdef SQLITE_ENABLE_FTS1
13848 "ENABLE_FTS1",
13849 #endif
13850 #ifdef SQLITE_ENABLE_FTS2
13851 "ENABLE_FTS2",
13852 #endif
13853 #ifdef SQLITE_ENABLE_FTS3
13854 "ENABLE_FTS3",
13855 #endif
13856 #ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
13857 "ENABLE_FTS3_PARENTHESIS",
13858 #endif
13859 #ifdef SQLITE_ENABLE_FTS4
13860 "ENABLE_FTS4",
13861 #endif
13862 #ifdef SQLITE_ENABLE_ICU
13863 "ENABLE_ICU",
13864 #endif
13865 #ifdef SQLITE_ENABLE_IOTRACE
13866 "ENABLE_IOTRACE",
13867 #endif
13868 #ifdef SQLITE_ENABLE_LOAD_EXTENSION
13869 "ENABLE_LOAD_EXTENSION",
13870 #endif
13871 #ifdef SQLITE_ENABLE_LOCKING_STYLE
13872 "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
13873 #endif
13874 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
13875 "ENABLE_MEMORY_MANAGEMENT",
13876 #endif
13877 #ifdef SQLITE_ENABLE_MEMSYS3
13878 "ENABLE_MEMSYS3",
13879 #endif
13880 #ifdef SQLITE_ENABLE_MEMSYS5
13881 "ENABLE_MEMSYS5",
13882 #endif
13883 #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
13884 "ENABLE_OVERSIZE_CELL_CHECK",
13885 #endif
13886 #ifdef SQLITE_ENABLE_RTREE
13887 "ENABLE_RTREE",
13888 #endif
13889 #if defined(SQLITE_ENABLE_STAT4)
13890 "ENABLE_STAT4",
13891 #elif defined(SQLITE_ENABLE_STAT3)
13892 "ENABLE_STAT3",
13893 #endif
13894 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
13895 "ENABLE_UNLOCK_NOTIFY",
13896 #endif
13897 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
13898 "ENABLE_UPDATE_DELETE_LIMIT",
13899 #endif
13900 #ifdef SQLITE_HAS_CODEC
13901 "HAS_CODEC",
13902 #endif
13903 #ifdef SQLITE_HAVE_ISNAN
13904 "HAVE_ISNAN",
13905 #endif
13906 #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
13907 "HOMEGROWN_RECURSIVE_MUTEX",
13908 #endif
13909 #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
13910 "IGNORE_AFP_LOCK_ERRORS",
13911 #endif
13912 #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
13913 "IGNORE_FLOCK_LOCK_ERRORS",
13914 #endif
13915 #ifdef SQLITE_INT64_TYPE
13916 "INT64_TYPE",
13917 #endif
13918 #ifdef SQLITE_LOCK_TRACE
13919 "LOCK_TRACE",
13920 #endif
13921 #if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
13922 "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
13923 #endif
13924 #ifdef SQLITE_MAX_SCHEMA_RETRY
13925 "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
13926 #endif
13927 #ifdef SQLITE_MEMDEBUG
13928 "MEMDEBUG",
13929 #endif
13930 #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
13931 "MIXED_ENDIAN_64BIT_FLOAT",
13932 #endif
13933 #ifdef SQLITE_NO_SYNC
13934 "NO_SYNC",
13935 #endif
13936 #ifdef SQLITE_OMIT_ALTERTABLE
13937 "OMIT_ALTERTABLE",
13938 #endif
13939 #ifdef SQLITE_OMIT_ANALYZE
13940 "OMIT_ANALYZE",
13941 #endif
13942 #ifdef SQLITE_OMIT_ATTACH
13943 "OMIT_ATTACH",
13944 #endif
13945 #ifdef SQLITE_OMIT_AUTHORIZATION
13946 "OMIT_AUTHORIZATION",
13947 #endif
13948 #ifdef SQLITE_OMIT_AUTOINCREMENT
13949 "OMIT_AUTOINCREMENT",
13950 #endif
13951 #ifdef SQLITE_OMIT_AUTOINIT
13952 "OMIT_AUTOINIT",
13953 #endif
13954 #ifdef SQLITE_OMIT_AUTOMATIC_INDEX
13955 "OMIT_AUTOMATIC_INDEX",
13956 #endif
13957 #ifdef SQLITE_OMIT_AUTORESET
13958 "OMIT_AUTORESET",
13959 #endif
13960 #ifdef SQLITE_OMIT_AUTOVACUUM
13961 "OMIT_AUTOVACUUM",
13962 #endif
13963 #ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
13964 "OMIT_BETWEEN_OPTIMIZATION",
13965 #endif
13966 #ifdef SQLITE_OMIT_BLOB_LITERAL
13967 "OMIT_BLOB_LITERAL",
13968 #endif
13969 #ifdef SQLITE_OMIT_BTREECOUNT
13970 "OMIT_BTREECOUNT",
13971 #endif
13972 #ifdef SQLITE_OMIT_BUILTIN_TEST
13973 "OMIT_BUILTIN_TEST",
13974 #endif
13975 #ifdef SQLITE_OMIT_CAST
13976 "OMIT_CAST",
13977 #endif
13978 #ifdef SQLITE_OMIT_CHECK
13979 "OMIT_CHECK",
13980 #endif
13981 #ifdef SQLITE_OMIT_COMPLETE
13982 "OMIT_COMPLETE",
13983 #endif
13984 #ifdef SQLITE_OMIT_COMPOUND_SELECT
13985 "OMIT_COMPOUND_SELECT",
13986 #endif
13987 #ifdef SQLITE_OMIT_CTE
13988 "OMIT_CTE",
13989 #endif
13990 #ifdef SQLITE_OMIT_DATETIME_FUNCS
13991 "OMIT_DATETIME_FUNCS",
13992 #endif
13993 #ifdef SQLITE_OMIT_DECLTYPE
13994 "OMIT_DECLTYPE",
13995 #endif
13996 #ifdef SQLITE_OMIT_DEPRECATED
13997 "OMIT_DEPRECATED",
13998 #endif
13999 #ifdef SQLITE_OMIT_DISKIO
14000 "OMIT_DISKIO",
14001 #endif
14002 #ifdef SQLITE_OMIT_EXPLAIN
14003 "OMIT_EXPLAIN",
14004 #endif
14005 #ifdef SQLITE_OMIT_FLAG_PRAGMAS
14006 "OMIT_FLAG_PRAGMAS",
14007 #endif
14008 #ifdef SQLITE_OMIT_FLOATING_POINT
14009 "OMIT_FLOATING_POINT",
14010 #endif
14011 #ifdef SQLITE_OMIT_FOREIGN_KEY
14012 "OMIT_FOREIGN_KEY",
14013 #endif
14014 #ifdef SQLITE_OMIT_GET_TABLE
14015 "OMIT_GET_TABLE",
14016 #endif
14017 #ifdef SQLITE_OMIT_INCRBLOB
14018 "OMIT_INCRBLOB",
14019 #endif
14020 #ifdef SQLITE_OMIT_INTEGRITY_CHECK
14021 "OMIT_INTEGRITY_CHECK",
14022 #endif
14023 #ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
14024 "OMIT_LIKE_OPTIMIZATION",
14025 #endif
14026 #ifdef SQLITE_OMIT_LOAD_EXTENSION
14027 "OMIT_LOAD_EXTENSION",
14028 #endif
14029 #ifdef SQLITE_OMIT_LOCALTIME
14030 "OMIT_LOCALTIME",
14031 #endif
14032 #ifdef SQLITE_OMIT_LOOKASIDE
14033 "OMIT_LOOKASIDE",
14034 #endif
14035 #ifdef SQLITE_OMIT_MEMORYDB
14036 "OMIT_MEMORYDB",
14037 #endif
14038 #ifdef SQLITE_OMIT_OR_OPTIMIZATION
14039 "OMIT_OR_OPTIMIZATION",
14040 #endif
14041 #ifdef SQLITE_OMIT_PAGER_PRAGMAS
14042 "OMIT_PAGER_PRAGMAS",
14043 #endif
14044 #ifdef SQLITE_OMIT_PRAGMA
14045 "OMIT_PRAGMA",
14046 #endif
14047 #ifdef SQLITE_OMIT_PROGRESS_CALLBACK
14048 "OMIT_PROGRESS_CALLBACK",
14049 #endif
14050 #ifdef SQLITE_OMIT_QUICKBALANCE
14051 "OMIT_QUICKBALANCE",
14052 #endif
14053 #ifdef SQLITE_OMIT_REINDEX
14054 "OMIT_REINDEX",
14055 #endif
14056 #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
14057 "OMIT_SCHEMA_PRAGMAS",
14058 #endif
14059 #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
14060 "OMIT_SCHEMA_VERSION_PRAGMAS",
14061 #endif
14062 #ifdef SQLITE_OMIT_SHARED_CACHE
14063 "OMIT_SHARED_CACHE",
14064 #endif
14065 #ifdef SQLITE_OMIT_SUBQUERY
14066 "OMIT_SUBQUERY",
14067 #endif
14068 #ifdef SQLITE_OMIT_TCL_VARIABLE
14069 "OMIT_TCL_VARIABLE",
14070 #endif
14071 #ifdef SQLITE_OMIT_TEMPDB
14072 "OMIT_TEMPDB",
14073 #endif
14074 #ifdef SQLITE_OMIT_TRACE
14075 "OMIT_TRACE",
14076 #endif
14077 #ifdef SQLITE_OMIT_TRIGGER
14078 "OMIT_TRIGGER",
14079 #endif
14080 #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
14081 "OMIT_TRUNCATE_OPTIMIZATION",
14082 #endif
14083 #ifdef SQLITE_OMIT_UTF16
14084 "OMIT_UTF16",
14085 #endif
14086 #ifdef SQLITE_OMIT_VACUUM
14087 "OMIT_VACUUM",
14088 #endif
14089 #ifdef SQLITE_OMIT_VIEW
14090 "OMIT_VIEW",
14091 #endif
14092 #ifdef SQLITE_OMIT_VIRTUALTABLE
14093 "OMIT_VIRTUALTABLE",
14094 #endif
14095 #ifdef SQLITE_OMIT_WAL
14096 "OMIT_WAL",
14097 #endif
14098 #ifdef SQLITE_OMIT_WSD
14099 "OMIT_WSD",
14100 #endif
14101 #ifdef SQLITE_OMIT_XFER_OPT
14102 "OMIT_XFER_OPT",
14103 #endif
14104 #ifdef SQLITE_PERFORMANCE_TRACE
14105 "PERFORMANCE_TRACE",
14106 #endif
14107 #ifdef SQLITE_PROXY_DEBUG
14108 "PROXY_DEBUG",
14109 #endif
14110 #ifdef SQLITE_RTREE_INT_ONLY
14111 "RTREE_INT_ONLY",
14112 #endif
14113 #ifdef SQLITE_SECURE_DELETE
14114 "SECURE_DELETE",
14115 #endif
14116 #ifdef SQLITE_SMALL_STACK
14117 "SMALL_STACK",
14118 #endif
14119 #ifdef SQLITE_SOUNDEX
14120 "SOUNDEX",
14121 #endif
14122 #ifdef SQLITE_SYSTEM_MALLOC
14123 "SYSTEM_MALLOC",
14124 #endif
14125 #ifdef SQLITE_TCL
14126 "TCL",
14127 #endif
14128 #if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
14129 "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
14130 #endif
14131 #ifdef SQLITE_TEST
14132 "TEST",
14133 #endif
14134 #if defined(SQLITE_THREADSAFE)
14135 "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
14136 #endif
14137 #ifdef SQLITE_USE_ALLOCA
14138 "USE_ALLOCA",
14139 #endif
14140 #ifdef SQLITE_USER_AUTHENTICATION
14141 "USER_AUTHENTICATION",
14142 #endif
14143 #ifdef SQLITE_WIN32_MALLOC
14144 "WIN32_MALLOC",
14145 #endif
14146 #ifdef SQLITE_ZERO_MALLOC
14147 "ZERO_MALLOC"
14148 #endif
14149 };
14150
14151 /*
@@ -14156,11 +14238,11 @@
14156 ** is not required for a match.
14157 */
14158 SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
14159 int i, n;
14160
14161 #ifdef SQLITE_ENABLE_API_ARMOR
14162 if( zOptName==0 ){
14163 (void)SQLITE_MISUSE_BKPT;
14164 return 0;
14165 }
14166 #endif
@@ -15384,12 +15466,13 @@
15384 **
15385 ** If the user has not indicated to use localtime_r() or localtime_s()
15386 ** already, check for an MSVC build environment that provides
15387 ** localtime_s().
15388 */
15389 #if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
15390 defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
 
15391 #define HAVE_LOCALTIME_S 1
15392 #endif
15393
15394 #ifndef SQLITE_OMIT_LOCALTIME
15395 /*
@@ -15405,12 +15488,11 @@
15405 ** library function localtime_r() is used to assist in the calculation of
15406 ** local time.
15407 */
15408 static int osLocaltime(time_t *t, struct tm *pTm){
15409 int rc;
15410 #if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
15411 && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
15412 struct tm *pX;
15413 #if SQLITE_THREADSAFE>0
15414 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
15415 #endif
15416 sqlite3_mutex_enter(mutex);
@@ -15423,11 +15505,11 @@
15423 rc = pX==0;
15424 #else
15425 #ifndef SQLITE_OMIT_BUILTIN_TEST
15426 if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
15427 #endif
15428 #if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
15429 rc = localtime_r(t, pTm)==0;
15430 #else
15431 rc = localtime_s(pTm, t);
15432 #endif /* HAVE_LOCALTIME_R */
15433 #endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
@@ -15867,12 +15949,14 @@
15867 DateTime x;
15868 u64 n;
15869 size_t i,j;
15870 char *z;
15871 sqlite3 *db;
15872 const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
15873 char zBuf[100];
 
 
15874 if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
15875 db = sqlite3_context_db_handle(context);
15876 for(i=0, n=1; zFmt[i]; i++, n++){
15877 if( zFmt[i]=='%' ){
15878 switch( zFmt[i+1] ){
@@ -16062,11 +16146,11 @@
16062 UNUSED_PARAMETER(argv);
16063
16064 iT = sqlite3StmtCurrentTime(context);
16065 if( iT<=0 ) return;
16066 t = iT/1000 - 10000*(sqlite3_int64)21086676;
16067 #ifdef HAVE_GMTIME_R
16068 pTm = gmtime_r(&t, &sNow);
16069 #else
16070 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
16071 pTm = gmtime(&t);
16072 if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
@@ -16736,13 +16820,13 @@
16736
16737 /*
16738 ** The malloc.h header file is needed for malloc_usable_size() function
16739 ** on some systems (e.g. Linux).
16740 */
16741 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE)
16742 # define SQLITE_USE_MALLOC_H
16743 # define SQLITE_USE_MALLOC_USABLE_SIZE
16744 /*
16745 ** The MSVCRT has malloc_usable_size(), but it is called _msize(). The
16746 ** use of _msize() is automatic, but can be disabled by compiling with
16747 ** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires
16748 ** the malloc.h header file.
@@ -19976,10 +20060,16 @@
19976 #endif
19977 }
19978 break;
19979 }
19980 default: {
 
 
 
 
 
 
19981 assert( iType-2 >= 0 );
19982 assert( iType-2 < ArraySize(winMutex_staticMutexes) );
19983 assert( winMutex_isInit==1 );
19984 p = &winMutex_staticMutexes[iType-2];
19985 #ifdef SQLITE_DEBUG
@@ -20971,21 +21061,10 @@
20971 ** This file contains code for a set of "printf"-like routines. These
20972 ** routines format strings much like the printf() from the standard C
20973 ** library, though the implementation here has enhancements to support
20974 ** SQLlite.
20975 */
20976
20977 /*
20978 ** If the strchrnul() library function is available, then set
20979 ** HAVE_STRCHRNUL. If that routine is not available, this module
20980 ** will supply its own. The built-in version is slower than
20981 ** the glibc version so the glibc version is definitely preferred.
20982 */
20983 #if !defined(HAVE_STRCHRNUL)
20984 # define HAVE_STRCHRNUL 0
20985 #endif
20986
20987
20988 /*
20989 ** Conversion types fall into various categories as defined by the
20990 ** following enumeration.
20991 */
@@ -22280,10 +22359,12 @@
22280 ** single threaded systems. Nothing in SQLite requires multiple threads.
22281 ** This interface exists so that applications that want to take advantage
22282 ** of multiple cores can do so, while also allowing applications to stay
22283 ** single-threaded if desired.
22284 */
 
 
22285
22286 #if SQLITE_MAX_WORKER_THREADS>0
22287
22288 /********************************* Unix Pthreads ****************************/
22289 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
@@ -23066,11 +23147,11 @@
23066 ** This file contains functions for allocating memory, comparing
23067 ** strings, and stuff like that.
23068 **
23069 */
23070 /* #include <stdarg.h> */
23071 #ifdef SQLITE_HAVE_ISNAN
23072 # include <math.h>
23073 #endif
23074
23075 /*
23076 ** Routine needed to support the testcase() macro.
@@ -23107,11 +23188,11 @@
23107 ** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
23108 ** Otherwise, we have our own implementation that works on most systems.
23109 */
23110 SQLITE_PRIVATE int sqlite3IsNaN(double x){
23111 int rc; /* The value return */
23112 #if !defined(SQLITE_HAVE_ISNAN)
23113 /*
23114 ** Systems that support the isnan() library function should probably
23115 ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
23116 ** found that many systems do not have a working isnan() function so
23117 ** this implementation is provided as an alternative.
@@ -23137,13 +23218,13 @@
23137 # error SQLite will not work correctly with the -ffast-math option of GCC.
23138 #endif
23139 volatile double y = x;
23140 volatile double z = y;
23141 rc = (y!=z);
23142 #else /* if defined(SQLITE_HAVE_ISNAN) */
23143 rc = isnan(x);
23144 #endif /* SQLITE_HAVE_ISNAN */
23145 testcase( rc );
23146 return rc;
23147 }
23148 #endif /* SQLITE_OMIT_FLOATING_POINT */
23149
@@ -28460,13 +28541,13 @@
28460
28461 /*
28462 ** We do not trust systems to provide a working fdatasync(). Some do.
28463 ** Others do no. To be safe, we will stick with the (slightly slower)
28464 ** fsync(). If you know that your system does support fdatasync() correctly,
28465 ** then simply compile with -Dfdatasync=fdatasync
28466 */
28467 #if !defined(fdatasync)
28468 # define fdatasync fsync
28469 #endif
28470
28471 /*
28472 ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
@@ -28783,28 +28864,32 @@
28783 do{
28784 err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
28785 }while( err==EINTR );
28786 if( err ) return SQLITE_IOERR_WRITE;
28787 #else
28788 /* If the OS does not have posix_fallocate(), fake it. First use
28789 ** ftruncate() to set the file size, then write a single byte to
28790 ** the last byte in each block within the extended region. This
28791 ** is the same technique used by glibc to implement posix_fallocate()
28792 ** on systems that do not have a real fallocate() system call.
 
28793 */
28794 int nBlk = buf.st_blksize; /* File-system block size */
 
28795 i64 iWrite; /* Next offset to write to */
28796
28797 if( robust_ftruncate(pFile->h, nSize) ){
28798 pFile->lastErrno = errno;
28799 return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
28800 }
28801 iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
28802 while( iWrite<nSize ){
28803 int nWrite = seekAndWrite(pFile, iWrite, "", 1);
 
 
 
28804 if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
28805 iWrite += nBlk;
 
 
 
28806 }
28807 #endif
28808 }
28809 }
28810
@@ -34018,12 +34103,12 @@
34018 */
34019 SQLITE_API int sqlite3_win32_reset_heap(){
34020 int rc;
34021 MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
34022 MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
34023 MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
34024 MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
34025 sqlite3_mutex_enter(pMaster);
34026 sqlite3_mutex_enter(pMem);
34027 winMemAssertMagic();
34028 if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
34029 /*
@@ -35294,11 +35379,11 @@
35294 sqlite3_file *id, /* File to read from */
35295 void *pBuf, /* Write content into this buffer */
35296 int amt, /* Number of bytes to read */
35297 sqlite3_int64 offset /* Begin reading at this offset */
35298 ){
35299 #if !SQLITE_OS_WINCE
35300 OVERLAPPED overlapped; /* The offset for ReadFile. */
35301 #endif
35302 winFile *pFile = (winFile*)id; /* file handle */
35303 DWORD nRead; /* Number of bytes actually read from file */
35304 int nRetry = 0; /* Number of retrys */
@@ -35326,11 +35411,11 @@
35326 offset += nCopy;
35327 }
35328 }
35329 #endif
35330
35331 #if SQLITE_OS_WINCE
35332 if( winSeekFile(pFile, offset) ){
35333 OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
35334 return SQLITE_FULL;
35335 }
35336 while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -35398,32 +35483,32 @@
35398 offset += nCopy;
35399 }
35400 }
35401 #endif
35402
35403 #if SQLITE_OS_WINCE
35404 rc = winSeekFile(pFile, offset);
35405 if( rc==0 ){
35406 #else
35407 {
35408 #endif
35409 #if !SQLITE_OS_WINCE
35410 OVERLAPPED overlapped; /* The offset for WriteFile. */
35411 #endif
35412 u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
35413 int nRem = amt; /* Number of bytes yet to be written */
35414 DWORD nWrite; /* Bytes written by each WriteFile() call */
35415 DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
35416
35417 #if !SQLITE_OS_WINCE
35418 memset(&overlapped, 0, sizeof(OVERLAPPED));
35419 overlapped.Offset = (LONG)(offset & 0xffffffff);
35420 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
35421 #endif
35422
35423 while( nRem>0 ){
35424 #if SQLITE_OS_WINCE
35425 if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
35426 #else
35427 if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
35428 #endif
35429 if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
@@ -35432,11 +35517,11 @@
35432 assert( nWrite==0 || nWrite<=(DWORD)nRem );
35433 if( nWrite==0 || nWrite>(DWORD)nRem ){
35434 lastErrno = osGetLastError();
35435 break;
35436 }
35437 #if !SQLITE_OS_WINCE
35438 offset += nWrite;
35439 overlapped.Offset = (LONG)(offset & 0xffffffff);
35440 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
35441 #endif
35442 aRem += nWrite;
@@ -38813,22 +38898,10 @@
38813 void *pStress; /* Argument to xStress */
38814 sqlite3_pcache *pCache; /* Pluggable cache module */
38815 PgHdr *pPage1; /* Reference to page 1 */
38816 };
38817
38818 /*
38819 ** Some of the assert() macros in this code are too expensive to run
38820 ** even during normal debugging. Use them only rarely on long-running
38821 ** tests. Enable the expensive asserts using the
38822 ** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
38823 */
38824 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
38825 # define expensive_assert(X) assert(X)
38826 #else
38827 # define expensive_assert(X)
38828 #endif
38829
38830 /********************************** Linked List Management ********************/
38831
38832 /* Allowed values for second argument to pcacheManageDirtyList() */
38833 #define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
38834 #define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
@@ -38978,11 +39051,12 @@
38978 SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
38979 assert( pCache->nRef==0 && pCache->pDirty==0 );
38980 if( pCache->szPage ){
38981 sqlite3_pcache *pNew;
38982 pNew = sqlite3GlobalConfig.pcache2.xCreate(
38983 szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
 
38984 );
38985 if( pNew==0 ) return SQLITE_NOMEM;
38986 sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
38987 if( pCache->pCache ){
38988 sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
@@ -39437,11 +39511,11 @@
39437
39438 /*
39439 ** Return the size of the header added by this middleware layer
39440 ** in the page-cache hierarchy.
39441 */
39442 SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return sizeof(PgHdr); }
39443
39444
39445 #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
39446 /*
39447 ** For all dirty pages currently in the cache, invoke the specified
@@ -39753,11 +39827,11 @@
39753 pcache1Free(pPg);
39754 sqlite3_free(p);
39755 pPg = 0;
39756 }
39757 #else
39758 pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
39759 p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
39760 #endif
39761 pcache1EnterMutex(pCache->pGroup);
39762
39763 if( pPg ){
@@ -40441,11 +40515,11 @@
40441 }
40442
40443 /*
40444 ** Return the size of the header on each page of this PCACHE implementation.
40445 */
40446 SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return sizeof(PgHdr1); }
40447
40448 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40449 /*
40450 ** This function is called to free superfluous dynamically allocated memory
40451 ** held by the pager system. Memory in use by any SQLite pager allocated
@@ -41799,10 +41873,12 @@
41799 u8 eLock; /* Current lock held on database file */
41800 u8 changeCountDone; /* Set after incrementing the change-counter */
41801 u8 setMaster; /* True if a m-j name has been written to jrnl */
41802 u8 doNotSpill; /* Do not spill the cache when non-zero */
41803 u8 subjInMemory; /* True to use in-memory sub-journals */
 
 
41804 Pgno dbSize; /* Number of pages in the database */
41805 Pgno dbOrigSize; /* dbSize before the current transaction */
41806 Pgno dbFileSize; /* Number of pages in the database file */
41807 Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */
41808 int errCode; /* One of several kinds of errors */
@@ -41816,13 +41892,13 @@
41816 i64 journalOff; /* Current write offset in the journal file */
41817 i64 journalHdr; /* Byte offset to previous journal header */
41818 sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
41819 PagerSavepoint *aSavepoint; /* Array of active savepoints */
41820 int nSavepoint; /* Number of elements in aSavepoint[] */
 
41821 char dbFileVers[16]; /* Changes whenever database file changes */
41822
41823 u8 bUseFetch; /* True to use xFetch() */
41824 int nMmapOut; /* Number of mmap pages currently outstanding */
41825 sqlite3_int64 szMmap; /* Desired maximum mmap size */
41826 PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
41827 /*
41828 ** End of the routinely-changing class members
@@ -42834,13 +42910,22 @@
42834
42835 /*
42836 ** Discard the entire contents of the in-memory page-cache.
42837 */
42838 static void pager_reset(Pager *pPager){
 
42839 sqlite3BackupRestart(pPager->pBackup);
42840 sqlite3PcacheClear(pPager->pPCache);
42841 }
 
 
 
 
 
 
 
 
42842
42843 /*
42844 ** Free all structures in the Pager.aSavepoint[] array and set both
42845 ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
42846 ** if it is open and the pager is not in exclusive mode.
@@ -45040,11 +45125,11 @@
45040 Pgno pgno, /* Page number */
45041 void *pData, /* xFetch()'d data for this page */
45042 PgHdr **ppPage /* OUT: Acquired page object */
45043 ){
45044 PgHdr *p; /* Memory mapped page to return */
45045
45046 if( pPager->pMmapFreelist ){
45047 *ppPage = p = pPager->pMmapFreelist;
45048 pPager->pMmapFreelist = p->pDirty;
45049 p->pDirty = 0;
45050 memset(p->pExtra, 0, pPager->nExtra);
@@ -46271,20 +46356,16 @@
46271 assert( (pPager->eLock==SHARED_LOCK)
46272 || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
46273 );
46274 }
46275
46276 if( !pPager->tempFile && (
46277 pPager->pBackup
46278 || sqlite3PcachePagecount(pPager->pPCache)>0
46279 || USEFETCH(pPager)
46280 )){
46281 /* The shared-lock has just been acquired on the database file
46282 ** and there are already pages in the cache (from a previous
46283 ** read or write transaction). Check to see if the database
46284 ** has been modified. If the database has changed, flush the
46285 ** cache.
46286 **
46287 ** Database changes is detected by looking at 15 bytes beginning
46288 ** at offset 24 into the file. The first 4 of these 16 bytes are
46289 ** a 32-bit counter that is incremented with each change. The
46290 ** other bytes change randomly with each file change when
@@ -46445,10 +46526,11 @@
46445 assert( noContent==0 || bMmapOk==0 );
46446
46447 if( pgno==0 ){
46448 return SQLITE_CORRUPT_BKPT;
46449 }
 
46450
46451 /* If the pager is in the error state, return an error immediately.
46452 ** Otherwise, request the page from the PCache layer. */
46453 if( pPager->errCode!=SQLITE_OK ){
46454 rc = pPager->errCode;
@@ -46594,10 +46676,11 @@
46594 sqlite3_pcache_page *pPage;
46595 assert( pPager!=0 );
46596 assert( pgno!=0 );
46597 assert( pPager->pPCache!=0 );
46598 pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
 
46599 return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
46600 }
46601
46602 /*
46603 ** Release a page reference.
@@ -47460,10 +47543,11 @@
47460 pPager->eState = PAGER_READER;
47461 return SQLITE_OK;
47462 }
47463
47464 PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
 
47465 rc = pager_end_transaction(pPager, pPager->setMaster, 1);
47466 return pager_error(pPager, rc);
47467 }
47468
47469 /*
@@ -50111,11 +50195,11 @@
50111 int (*xBusy)(void*), /* Function to call when busy */
50112 void *pBusyArg, /* Context argument for xBusyHandler */
50113 int sync_flags, /* Flags for OsSync() (or 0) */
50114 u8 *zBuf /* Temporary buffer to use */
50115 ){
50116 int rc; /* Return code */
50117 int szPage; /* Database page-size */
50118 WalIterator *pIter = 0; /* Wal iterator context */
50119 u32 iDbpage = 0; /* Next database page to write */
50120 u32 iFrame = 0; /* Wal frame containing data for iDbpage */
50121 u32 mxSafeFrame; /* Max frame that can be backfilled */
@@ -50125,108 +50209,111 @@
50125
50126 szPage = walPagesize(pWal);
50127 testcase( szPage<=32768 );
50128 testcase( szPage>=65536 );
50129 pInfo = walCkptInfo(pWal);
50130 if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
50131
50132 /* Allocate the iterator */
50133 rc = walIteratorInit(pWal, &pIter);
50134 if( rc!=SQLITE_OK ){
50135 return rc;
50136 }
50137 assert( pIter );
50138
50139 /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
50140 ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
50141 assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
50142
50143 /* Compute in mxSafeFrame the index of the last frame of the WAL that is
50144 ** safe to write into the database. Frames beyond mxSafeFrame might
50145 ** overwrite database pages that are in use by active readers and thus
50146 ** cannot be backfilled from the WAL.
50147 */
50148 mxSafeFrame = pWal->hdr.mxFrame;
50149 mxPage = pWal->hdr.nPage;
50150 for(i=1; i<WAL_NREADER; i++){
50151 u32 y = pInfo->aReadMark[i];
50152 if( mxSafeFrame>y ){
50153 assert( y<=pWal->hdr.mxFrame );
50154 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
50155 if( rc==SQLITE_OK ){
50156 pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
50157 walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
50158 }else if( rc==SQLITE_BUSY ){
50159 mxSafeFrame = y;
50160 xBusy = 0;
50161 }else{
50162 goto walcheckpoint_out;
50163 }
50164 }
50165 }
50166
50167 if( pInfo->nBackfill<mxSafeFrame
50168 && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
50169 ){
50170 i64 nSize; /* Current size of database file */
50171 u32 nBackfill = pInfo->nBackfill;
50172
50173 /* Sync the WAL to disk */
50174 if( sync_flags ){
50175 rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
50176 }
50177
50178 /* If the database may grow as a result of this checkpoint, hint
50179 ** about the eventual size of the db file to the VFS layer.
50180 */
50181 if( rc==SQLITE_OK ){
50182 i64 nReq = ((i64)mxPage * szPage);
50183 rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
50184 if( rc==SQLITE_OK && nSize<nReq ){
50185 sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
50186 }
50187 }
50188
50189
50190 /* Iterate through the contents of the WAL, copying data to the db file. */
50191 while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
50192 i64 iOffset;
50193 assert( walFramePgno(pWal, iFrame)==iDbpage );
50194 if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
50195 iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
50196 /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
50197 rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
50198 if( rc!=SQLITE_OK ) break;
50199 iOffset = (iDbpage-1)*(i64)szPage;
50200 testcase( IS_BIG_INT(iOffset) );
50201 rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
50202 if( rc!=SQLITE_OK ) break;
50203 }
50204
50205 /* If work was actually accomplished... */
50206 if( rc==SQLITE_OK ){
50207 if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
50208 i64 szDb = pWal->hdr.nPage*(i64)szPage;
50209 testcase( IS_BIG_INT(szDb) );
50210 rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
50211 if( rc==SQLITE_OK && sync_flags ){
50212 rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
50213 }
50214 }
50215 if( rc==SQLITE_OK ){
50216 pInfo->nBackfill = mxSafeFrame;
50217 }
50218 }
50219
50220 /* Release the reader lock held while backfilling */
50221 walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
50222 }
50223
50224 if( rc==SQLITE_BUSY ){
50225 /* Reset the return code so as not to report a checkpoint failure
50226 ** just because there are active readers. */
50227 rc = SQLITE_OK;
 
 
 
50228 }
50229
50230 /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
50231 ** entire wal file has been copied into the database file, then block
50232 ** until all readers have finished using the wal file. This ensures that
@@ -50237,11 +50324,11 @@
50237 if( pInfo->nBackfill<pWal->hdr.mxFrame ){
50238 rc = SQLITE_BUSY;
50239 }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
50240 u32 salt1;
50241 sqlite3_randomness(4, &salt1);
50242 assert( mxSafeFrame==pWal->hdr.mxFrame );
50243 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
50244 if( rc==SQLITE_OK ){
50245 if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
50246 /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
50247 ** SQLITE_CHECKPOINT_RESTART with the addition that it also
@@ -50829,11 +50916,11 @@
50829 }
50830 nCollide = HASHTABLE_NSLOT;
50831 for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
50832 u32 iFrame = aHash[iKey] + iZero;
50833 if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
50834 /* assert( iFrame>iRead ); -- not true if there is corruption */
50835 iRead = iFrame;
50836 }
50837 if( (nCollide--)==0 ){
50838 return SQLITE_CORRUPT_BKPT;
50839 }
@@ -51935,10 +52022,11 @@
51935 u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
51936 u8 sharable; /* True if we can share pBt with another db */
51937 u8 locked; /* True if db currently has pBt locked */
51938 int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
51939 int nBackup; /* Number of backup operations reading this btree */
 
51940 Btree *pNext; /* List of other sharable Btrees from the same db */
51941 Btree *pPrev; /* Back pointer of the same list */
51942 #ifndef SQLITE_OMIT_SHARED_CACHE
51943 BtLock lock; /* Object used to lock page 1 */
51944 #endif
@@ -56098,10 +56186,11 @@
56098 rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
56099 if( rc!=SQLITE_OK && bCleanup==0 ){
56100 sqlite3BtreeLeave(p);
56101 return rc;
56102 }
 
56103 pBt->inTransaction = TRANS_READ;
56104 btreeClearHasContent(pBt);
56105 }
56106
56107 btreeEndTransaction(p);
@@ -56461,11 +56550,11 @@
56461 }
56462 for(i=0; i<=pCur->iPage; i++){
56463 releasePage(pCur->apPage[i]);
56464 }
56465 unlockBtreeIfUnused(pBt);
56466 sqlite3DbFree(pBtree->db, pCur->aOverflow);
56467 /* sqlite3_free(pCur); */
56468 sqlite3BtreeLeave(pBtree);
56469 }
56470 return SQLITE_OK;
56471 }
@@ -56755,10 +56844,11 @@
56755 pBuf += a;
56756 amt -= a;
56757 }else{
56758 offset -= pCur->info.nLocal;
56759 }
 
56760
56761 if( rc==SQLITE_OK && amt>0 ){
56762 const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
56763 Pgno nextPage;
56764
@@ -56773,12 +56863,12 @@
56773 ** means "not yet known" (the cache is lazily populated).
56774 */
56775 if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
56776 int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
56777 if( nOvfl>pCur->nOvflAlloc ){
56778 Pgno *aNew = (Pgno*)sqlite3DbRealloc(
56779 pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
56780 );
56781 if( aNew==0 ){
56782 rc = SQLITE_NOMEM;
56783 }else{
56784 pCur->nOvflAlloc = nOvfl*2;
@@ -56821,10 +56911,11 @@
56821 ** Note that the aOverflow[] array must be allocated because eOp!=2
56822 ** here. If eOp==2, then offset==0 and this branch is never taken.
56823 */
56824 assert( eOp!=2 );
56825 assert( pCur->curFlags & BTCF_ValidOvfl );
 
56826 if( pCur->aOverflow[iIdx+1] ){
56827 nextPage = pCur->aOverflow[iIdx+1];
56828 }else{
56829 rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
56830 }
@@ -59410,12 +59501,12 @@
59410 assert( leafCorrection==4 );
59411 if( szCell[nCell]<4 ){
59412 /* Do not allow any cells smaller than 4 bytes. If a smaller cell
59413 ** does exist, pad it with 0x00 bytes. */
59414 assert( szCell[nCell]==3 );
59415 assert( apCell[nCell]==&pTemp[iSpace1-3] );
59416 pTemp[iSpace1++] = 0x00;
59417 szCell[nCell] = 4;
59418 }
59419 }
59420 nCell++;
59421 }
@@ -60723,10 +60814,17 @@
60723 ** is read-only, the others are read/write.
60724 **
60725 ** The schema layer numbers meta values differently. At the schema
60726 ** layer (and the SetCookie and ReadCookie opcodes) the number of
60727 ** free pages is not visible. So Cookie[0] is the same as Meta[1].
 
 
 
 
 
 
 
60728 */
60729 SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
60730 BtShared *pBt = p->pBt;
60731
60732 sqlite3BtreeEnter(p);
@@ -60733,11 +60831,15 @@
60733 assert( p->inTrans>TRANS_NONE );
60734 assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
60735 assert( pBt->pPage1 );
60736 assert( idx>=0 && idx<=15 );
60737
60738 *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
 
 
 
 
60739
60740 /* If auto-vacuum is disabled in this build and this is an auto-vacuum
60741 ** database, mark the database as read-only. */
60742 #ifdef SQLITE_OMIT_AUTOVACUUM
60743 if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){
@@ -60824,11 +60926,11 @@
60824 if( pPage->leaf ){
60825 do {
60826 if( pCur->iPage==0 ){
60827 /* All pages of the b-tree have been visited. Return successfully. */
60828 *pnEntry = nEntry;
60829 return SQLITE_OK;
60830 }
60831 moveToParent(pCur);
60832 }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
60833
60834 pCur->aiIdx[pCur->iPage]++;
@@ -61680,11 +61782,11 @@
61680 }
61681
61682 /*
61683 ** Return the size of the header added to each page by this module.
61684 */
61685 SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return sizeof(MemPage); }
61686
61687 /************** End of btree.c ***********************************************/
61688 /************** Begin file backup.c ******************************************/
61689 /*
61690 ** 2009 January 28
@@ -64444,36 +64546,39 @@
64444 **
64445 ** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) );
64446 */
64447 SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
64448 int hasAbort = 0;
 
64449 Op *pOp;
64450 VdbeOpIter sIter;
64451 memset(&sIter, 0, sizeof(sIter));
64452 sIter.v = v;
64453
64454 while( (pOp = opIterNext(&sIter))!=0 ){
64455 int opcode = pOp->opcode;
64456 if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
64457 #ifndef SQLITE_OMIT_FOREIGN_KEY
64458 || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
64459 #endif
64460 || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
64461 && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
64462 ){
64463 hasAbort = 1;
64464 break;
64465 }
 
 
 
 
 
64466 }
64467 sqlite3DbFree(v->db, sIter.apSub);
64468
64469 /* Return true if hasAbort==mayAbort. Or if a malloc failure occurred.
64470 ** If malloc failed, then the while() loop above may not have iterated
64471 ** through all opcodes and hasAbort may be set incorrectly. Return
64472 ** true for this case to prevent the assert() in the callers frame
64473 ** from failing. */
64474 return ( v->db->mallocFailed || hasAbort==mayAbort );
64475 }
64476 #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
64477
64478 /*
64479 ** Loop through the program looking for P2 values that are negative
@@ -67394,10 +67499,45 @@
67394 if( pKeyInfo->db->mallocFailed ) return 1;
67395 return 0;
67396 }
67397 #endif
67398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67399 /*
67400 ** Both *pMem1 and *pMem2 contain string values. Compare the two values
67401 ** using the collation sequence pColl. As usual, return a negative , zero
67402 ** or positive value if *pMem1 is less than, equal to or greater than
67403 ** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
@@ -67805,10 +67945,11 @@
67805 u32 y;
67806 u64 x;
67807 i64 v = pPKey2->aMem[0].u.i;
67808 i64 lhs;
67809
 
67810 assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
67811 switch( serial_type ){
67812 case 1: { /* 1-byte signed integer */
67813 lhs = ONE_BYTE_INT(aKey);
67814 testcase( lhs<0 );
@@ -67892,10 +68033,11 @@
67892 ){
67893 const u8 *aKey1 = (const u8*)pKey1;
67894 int serial_type;
67895 int res;
67896
 
67897 getVarint32(&aKey1[1], serial_type);
67898 if( serial_type<12 ){
67899 res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
67900 }else if( !(serial_type & 0x01) ){
67901 res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
@@ -68593,11 +68735,14 @@
68593 #ifndef SQLITE_OMIT_WAL
68594 int i;
68595 for(i=0; i<db->nDb; i++){
68596 Btree *pBt = db->aDb[i].pBt;
68597 if( pBt ){
68598 int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
 
 
 
68599 if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
68600 rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
68601 }
68602 }
68603 }
@@ -68773,11 +68918,10 @@
68773 ** program counter to 0 to ensure that when the statement is
68774 ** finalized or reset the parser error message is available via
68775 ** sqlite3_errmsg() and sqlite3_errcode().
68776 */
68777 const char *zErr = (const char *)sqlite3_value_text(db->pErr);
68778 assert( zErr!=0 || db->mallocFailed );
68779 sqlite3DbFree(db, v->zErrMsg);
68780 if( !db->mallocFailed ){
68781 v->zErrMsg = sqlite3DbStrDup(db, zErr);
68782 v->rc = rc2;
68783 } else {
@@ -73838,12 +73982,12 @@
73838 pIdxKey->default_rc = 0;
73839 if( pOp->opcode==OP_NoConflict ){
73840 /* For the OP_NoConflict opcode, take the jump if any of the
73841 ** input fields are NULL, since any key with a NULL will not
73842 ** conflict */
73843 for(ii=0; ii<r.nField; ii++){
73844 if( r.aMem[ii].flags & MEM_Null ){
73845 pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
73846 break;
73847 }
73848 }
73849 }
@@ -77135,11 +77279,11 @@
77135 /*
77136 ** Hard-coded maximum amount of data to accumulate in memory before flushing
77137 ** to a level 0 PMA. The purpose of this limit is to prevent various integer
77138 ** overflows. 512MiB.
77139 */
77140 #define SQLITE_MAX_MXPMASIZE (1<<29)
77141
77142 /*
77143 ** Private objects used by the sorter
77144 */
77145 typedef struct MergeEngine MergeEngine; /* Merge PMAs together */
@@ -77431,15 +77575,10 @@
77431 **
77432 ** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; }
77433 */
77434 #define SRVAL(p) ((void*)((SorterRecord*)(p) + 1))
77435
77436 /* The minimum PMA size is set to this value multiplied by the database
77437 ** page size in bytes. */
77438 #ifndef SQLITE_SORTER_PMASZ
77439 # define SQLITE_SORTER_PMASZ 10
77440 #endif
77441
77442 /* Maximum number of PMAs that a single MergeEngine can merge */
77443 #define SORTER_MAX_MERGE_COUNT 16
77444
77445 static int vdbeIncrSwap(IncrMerger*);
@@ -77834,14 +77973,15 @@
77834 SortSubtask *pTask = &pSorter->aTask[i];
77835 pTask->pSorter = pSorter;
77836 }
77837
77838 if( !sqlite3TempInMemory(db) ){
77839 pSorter->mnPmaSize = SQLITE_SORTER_PMASZ * pgsz;
 
77840 mxCache = db->aDb[0].pSchema->cache_size;
77841 if( mxCache<SQLITE_SORTER_PMASZ ) mxCache = SQLITE_SORTER_PMASZ;
77842 pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_MXPMASIZE);
77843
77844 /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
77845 ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
77846 ** large heap allocations.
77847 */
@@ -78115,16 +78255,16 @@
78115 ** Whether or not the file does end up memory mapped of course depends on
78116 ** the specific VFS implementation.
78117 */
78118 static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
78119 if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
78120 int rc = sqlite3OsTruncate(pFd, nByte);
78121 if( rc==SQLITE_OK ){
78122 void *p = 0;
78123 sqlite3OsFetch(pFd, 0, (int)nByte, &p);
78124 sqlite3OsUnfetch(pFd, 0, p);
78125 }
78126 }
78127 }
78128 #else
78129 # define vdbeSorterExtendFile(x,y,z)
78130 #endif
@@ -79401,10 +79541,11 @@
79401 rc = vdbePmaReaderNext(pSorter->pReader);
79402 *pbEof = (pSorter->pReader->pFd==0);
79403 }else
79404 #endif
79405 /*if( !pSorter->bUseThreads )*/ {
 
79406 assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
79407 rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
79408 }
79409 }else{
79410 SorterRecord *pFree = pSorter->list.pList;
@@ -82167,11 +82308,11 @@
82167 Expr *pLeft, /* Left operand */
82168 Expr *pRight, /* Right operand */
82169 const Token *pToken /* Argument token */
82170 ){
82171 Expr *p;
82172 if( op==TK_AND && pLeft && pRight ){
82173 /* Take advantage of short-circuit false optimization for AND */
82174 p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
82175 }else{
82176 p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
82177 sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
@@ -85721,14 +85862,15 @@
85721 ** NEVER() will need to be removed. */
85722 if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){
85723 int i;
85724 struct SrcCount *p = pWalker->u.pSrcCount;
85725 SrcList *pSrc = p->pSrc;
85726 for(i=0; i<pSrc->nSrc; i++){
 
85727 if( pExpr->iTable==pSrc->a[i].iCursor ) break;
85728 }
85729 if( i<pSrc->nSrc ){
85730 p->nThis++;
85731 }else{
85732 p->nOther++;
85733 }
85734 }
@@ -87302,11 +87444,11 @@
87302
87303 p->iGet = -1;
87304 p->mxSample = mxSample;
87305 p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
87306 p->current.anLt = &p->current.anEq[nColUp];
87307 p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565;
87308
87309 /* Set up the Stat4Accum.a[] and aBest[] arrays */
87310 p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
87311 p->aBest = &p->a[mxSample];
87312 pSpace = (u8*)(&p->a[mxSample+nCol]);
@@ -88895,17 +89037,19 @@
88895 }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
88896 zErrDyn = sqlite3MPrintf(db,
88897 "attached databases must use the same text encoding as main database");
88898 rc = SQLITE_ERROR;
88899 }
 
88900 pPager = sqlite3BtreePager(aNew->pBt);
88901 sqlite3PagerLockingMode(pPager, db->dfltLockMode);
88902 sqlite3BtreeSecureDelete(aNew->pBt,
88903 sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
88904 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
88905 sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
88906 #endif
 
88907 }
88908 aNew->safety_level = 3;
88909 aNew->zName = sqlite3DbStrDup(db, zName);
88910 if( rc==SQLITE_OK && aNew->zName==0 ){
88911 rc = SQLITE_NOMEM;
@@ -90027,11 +90171,10 @@
90027 */
90028 static void freeIndex(sqlite3 *db, Index *p){
90029 #ifndef SQLITE_OMIT_ANALYZE
90030 sqlite3DeleteIndexSamples(db, p);
90031 #endif
90032 if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
90033 sqlite3ExprDelete(db, p->pPartIdxWhere);
90034 sqlite3DbFree(db, p->zColAff);
90035 if( p->isResized ) sqlite3DbFree(db, p->azColl);
90036 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
90037 sqlite3_free(p->aiRowEst);
@@ -91306,10 +91449,23 @@
91306 if( pPk==0 ) return;
91307 pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
91308 pTab->iPKey = -1;
91309 }else{
91310 pPk = sqlite3PrimaryKeyIndex(pTab);
 
 
 
 
 
 
 
 
 
 
 
 
 
91311 }
91312 pPk->isCovering = 1;
91313 assert( pPk!=0 );
91314 nPk = pPk->nKeyCol;
91315
@@ -93782,44 +93938,35 @@
93782 **
93783 ** The caller should invoke sqlite3KeyInfoUnref() on the returned object
93784 ** when it has finished using it.
93785 */
93786 SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
 
 
 
 
93787 if( pParse->nErr ) return 0;
93788 #ifndef SQLITE_OMIT_SHARED_CACHE
93789 if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){
93790 sqlite3KeyInfoUnref(pIdx->pKeyInfo);
93791 pIdx->pKeyInfo = 0;
93792 }
93793 #endif
93794 if( pIdx->pKeyInfo==0 ){
93795 int i;
93796 int nCol = pIdx->nColumn;
93797 int nKey = pIdx->nKeyCol;
93798 KeyInfo *pKey;
93799 if( pIdx->uniqNotNull ){
93800 pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
93801 }else{
93802 pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
93803 }
93804 if( pKey ){
93805 assert( sqlite3KeyInfoIsWriteable(pKey) );
93806 for(i=0; i<nCol; i++){
93807 char *zColl = pIdx->azColl[i];
93808 assert( zColl!=0 );
93809 pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
93810 sqlite3LocateCollSeq(pParse, zColl);
93811 pKey->aSortOrder[i] = pIdx->aSortOrder[i];
93812 }
93813 if( pParse->nErr ){
93814 sqlite3KeyInfoUnref(pKey);
93815 }else{
93816 pIdx->pKeyInfo = pKey;
93817 }
93818 }
93819 }
93820 return sqlite3KeyInfoRef(pIdx->pKeyInfo);
93821 }
93822
93823 #ifndef SQLITE_OMIT_CTE
93824 /*
93825 ** This routine is invoked once per CTE by the parser while parsing a
@@ -94596,12 +94743,12 @@
94596 const char *zDb; /* Name of database holding pTab */
94597 int i; /* Loop counter */
94598 WhereInfo *pWInfo; /* Information about the WHERE clause */
94599 Index *pIdx; /* For looping over indices of the table */
94600 int iTabCur; /* Cursor number for the table */
94601 int iDataCur; /* VDBE cursor for the canonical data source */
94602 int iIdxCur; /* Cursor number of the first index */
94603 int nIdx; /* Number of indices */
94604 sqlite3 *db; /* Main database structure */
94605 AuthContext sContext; /* Authorization context */
94606 NameContext sNC; /* Name context to resolve expressions in */
94607 int iDb; /* Database number */
@@ -97436,11 +97583,11 @@
97436 assert( nIncr==1 );
97437 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
97438 OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
97439 }else{
97440 if( nIncr>0 && pFKey->isDeferred==0 ){
97441 sqlite3ParseToplevel(pParse)->mayAbort = 1;
97442 }
97443 sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
97444 }
97445
97446 sqlite3VdbeResolveLabel(v, iOk);
@@ -97507,10 +97654,14 @@
97507 ** This function is called to generate code executed when a row is deleted
97508 ** from the parent table of foreign key constraint pFKey and, if pFKey is
97509 ** deferred, when a row is inserted into the same table. When generating
97510 ** code for an SQL UPDATE operation, this function may be called twice -
97511 ** once to "delete" the old row and once to "insert" the new row.
 
 
 
 
97512 **
97513 ** The code generated by this function scans through the rows in the child
97514 ** table that correspond to the parent table row being deleted or inserted.
97515 ** For each child row found, one of the following actions is taken:
97516 **
@@ -97624,17 +97775,13 @@
97624 sNameContext.pSrcList = pSrc;
97625 sNameContext.pParse = pParse;
97626 sqlite3ResolveExprNames(&sNameContext, pWhere);
97627
97628 /* Create VDBE to loop through the entries in pSrc that match the WHERE
97629 ** clause. If the constraint is not deferred, throw an exception for
97630 ** each row found. Otherwise, for deferred constraints, increment the
97631 ** deferred constraint counter by nIncr for each row selected. */
97632 pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
97633 if( nIncr>0 && pFKey->isDeferred==0 ){
97634 sqlite3ParseToplevel(pParse)->mayAbort = 1;
97635 }
97636 sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
97637 if( pWInfo ){
97638 sqlite3WhereEnd(pWInfo);
97639 }
97640
@@ -97808,10 +97955,28 @@
97808 }
97809 }
97810 }
97811 return 0;
97812 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97813
97814 /*
97815 ** This function is called when inserting, deleting or updating a row of
97816 ** table pTab to generate VDBE code to perform foreign key constraint
97817 ** processing for the operation.
@@ -97861,11 +98026,11 @@
97861 Index *pIdx = 0; /* Index on key columns in pTo */
97862 int *aiFree = 0;
97863 int *aiCol;
97864 int iCol;
97865 int i;
97866 int isIgnore = 0;
97867
97868 if( aChange
97869 && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
97870 && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
97871 ){
@@ -97920,11 +98085,11 @@
97920 ** values read from the parent table are NULL. */
97921 if( db->xAuth ){
97922 int rcauth;
97923 char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
97924 rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
97925 isIgnore = (rcauth==SQLITE_IGNORE);
97926 }
97927 #endif
97928 }
97929
97930 /* Take a shared-cache advisory read-lock on the parent table. Allocate
@@ -97935,16 +98100,22 @@
97935
97936 if( regOld!=0 ){
97937 /* A row is being removed from the child table. Search for the parent.
97938 ** If the parent does not exist, removing the child row resolves an
97939 ** outstanding foreign key constraint violation. */
97940 fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore);
97941 }
97942 if( regNew!=0 ){
97943 /* A row is being added to the child table. If a parent row cannot
97944 ** be found, adding the child row has violated the FK constraint. */
97945 fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore);
 
 
 
 
 
 
97946 }
97947
97948 sqlite3DbFree(db, aiFree);
97949 }
97950
@@ -97961,12 +98132,12 @@
97961
97962 if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
97963 && !pParse->pToplevel && !pParse->isMultiWrite
97964 ){
97965 assert( regOld==0 && regNew!=0 );
97966 /* Inserting a single row into a parent table cannot cause an immediate
97967 ** foreign key violation. So do nothing in this case. */
97968 continue;
97969 }
97970
97971 if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
97972 if( !isIgnoreErrors || db->mallocFailed ) return;
@@ -97986,17 +98157,32 @@
97986
97987 if( regNew!=0 ){
97988 fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
97989 }
97990 if( regOld!=0 ){
97991 /* If there is a RESTRICT action configured for the current operation
97992 ** on the parent table of this FK, then throw an exception
97993 ** immediately if the FK constraint is violated, even if this is a
97994 ** deferred trigger. That's what RESTRICT means. To defer checking
97995 ** the constraint, the FK should specify NO ACTION (represented
97996 ** using OE_None). NO ACTION is the default. */
97997 fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97998 }
97999 pItem->zName = 0;
98000 sqlite3SrcListDelete(db, pSrc);
98001 }
98002 sqlite3DbFree(db, aiCol);
@@ -101895,10 +102081,11 @@
101895 #define PragTyp_KEY 38
101896 #define PragTyp_REKEY 39
101897 #define PragTyp_LOCK_STATUS 40
101898 #define PragTyp_PARSER_TRACE 41
101899 #define PragFlag_NeedSchema 0x01
 
101900 static const struct sPragmaNames {
101901 const char *const zName; /* Name of pragma */
101902 u8 ePragTyp; /* PragTyp_XXX value */
101903 u8 mPragFlag; /* Zero or more PragFlag_XXX values */
101904 u32 iArg; /* Extra argument */
@@ -101911,11 +102098,11 @@
101911 #endif
101912 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
101913 { /* zName: */ "application_id",
101914 /* ePragTyp: */ PragTyp_HEADER_VALUE,
101915 /* ePragFlag: */ 0,
101916 /* iArg: */ 0 },
101917 #endif
101918 #if !defined(SQLITE_OMIT_AUTOVACUUM)
101919 { /* zName: */ "auto_vacuum",
101920 /* ePragTyp: */ PragTyp_AUTO_VACUUM,
101921 /* ePragFlag: */ PragFlag_NeedSchema,
@@ -101977,10 +102164,16 @@
101977 { /* zName: */ "data_store_directory",
101978 /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
101979 /* ePragFlag: */ 0,
101980 /* iArg: */ 0 },
101981 #endif
 
 
 
 
 
 
101982 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
101983 { /* zName: */ "database_list",
101984 /* ePragTyp: */ PragTyp_DATABASE_LIST,
101985 /* ePragFlag: */ PragFlag_NeedSchema,
101986 /* iArg: */ 0 },
@@ -102032,12 +102225,12 @@
102032 #endif
102033 #endif
102034 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102035 { /* zName: */ "freelist_count",
102036 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102037 /* ePragFlag: */ 0,
102038 /* iArg: */ 0 },
102039 #endif
102040 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
102041 { /* zName: */ "full_column_names",
102042 /* ePragTyp: */ PragTyp_FLAG,
102043 /* ePragFlag: */ 0,
@@ -102185,11 +102378,11 @@
102185 #endif
102186 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102187 { /* zName: */ "schema_version",
102188 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102189 /* ePragFlag: */ 0,
102190 /* iArg: */ 0 },
102191 #endif
102192 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
102193 { /* zName: */ "secure_delete",
102194 /* ePragTyp: */ PragTyp_SECURE_DELETE,
102195 /* ePragFlag: */ 0,
@@ -102251,11 +102444,11 @@
102251 /* iArg: */ 0 },
102252 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102253 { /* zName: */ "user_version",
102254 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102255 /* ePragFlag: */ 0,
102256 /* iArg: */ 0 },
102257 #endif
102258 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
102259 #if defined(SQLITE_DEBUG)
102260 { /* zName: */ "vdbe_addoptrace",
102261 /* ePragTyp: */ PragTyp_FLAG,
@@ -102294,11 +102487,11 @@
102294 /* ePragTyp: */ PragTyp_FLAG,
102295 /* ePragFlag: */ 0,
102296 /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
102297 #endif
102298 };
102299 /* Number of pragmas: 57 on by default, 70 total. */
102300 /* End of the automatically generated pragma table.
102301 ***************************************************************************/
102302
102303 /*
102304 ** Interpret the given string as a safety level. Return 0 for OFF,
@@ -102544,11 +102737,11 @@
102544 char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
102545 const char *zDb = 0; /* The database name */
102546 Token *pId; /* Pointer to <id> token */
102547 char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
102548 int iDb; /* Database index for <database> */
102549 int lwr, upr, mid; /* Binary search bounds */
102550 int rc; /* return value form SQLITE_FCNTL_PRAGMA */
102551 sqlite3 *db = pParse->db; /* The database connection */
102552 Db *pDb; /* The specific database being pragmaed */
102553 Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
102554
@@ -103904,11 +104097,12 @@
103904 !(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
103905 DbHasProperty(db, 0, DB_Empty)
103906 ){
103907 for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
103908 if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
103909 ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
 
103910 break;
103911 }
103912 }
103913 if( !pEnc->zName ){
103914 sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
@@ -103949,28 +104143,13 @@
103949 **
103950 ** The user-version is not used internally by SQLite. It may be used by
103951 ** applications for any purpose.
103952 */
103953 case PragTyp_HEADER_VALUE: {
103954 int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
103955 sqlite3VdbeUsesBtree(v, iDb);
103956 switch( zLeft[0] ){
103957 case 'a': case 'A':
103958 iCookie = BTREE_APPLICATION_ID;
103959 break;
103960 case 'f': case 'F':
103961 iCookie = BTREE_FREE_PAGE_COUNT;
103962 break;
103963 case 's': case 'S':
103964 iCookie = BTREE_SCHEMA_VERSION;
103965 break;
103966 default:
103967 iCookie = BTREE_USER_VERSION;
103968 break;
103969 }
103970
103971 if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){
103972 /* Write the specified cookie value */
103973 static const VdbeOpList setCookie[] = {
103974 { OP_Transaction, 0, 1, 0}, /* 0 */
103975 { OP_Integer, 0, 1, 0}, /* 1 */
103976 { OP_SetCookie, 0, 0, 1}, /* 2 */
@@ -104612,13 +104791,15 @@
104612 SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
104613 int i, rc;
104614 int commit_internal = !(db->flags&SQLITE_InternChanges);
104615
104616 assert( sqlite3_mutex_held(db->mutex) );
 
104617 assert( db->init.busy==0 );
104618 rc = SQLITE_OK;
104619 db->init.busy = 1;
 
104620 for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
104621 if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
104622 rc = sqlite3InitOne(db, i, pzErrMsg);
104623 if( rc ){
104624 sqlite3ResetOneSchema(db, i);
@@ -105169,24 +105350,29 @@
105169 u8 sortFlags; /* Zero or more SORTFLAG_* bits */
105170 };
105171 #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
105172
105173 /*
105174 ** Delete all the content of a Select structure but do not deallocate
105175 ** the select structure itself.
105176 */
105177 static void clearSelect(sqlite3 *db, Select *p){
105178 sqlite3ExprListDelete(db, p->pEList);
105179 sqlite3SrcListDelete(db, p->pSrc);
105180 sqlite3ExprDelete(db, p->pWhere);
105181 sqlite3ExprListDelete(db, p->pGroupBy);
105182 sqlite3ExprDelete(db, p->pHaving);
105183 sqlite3ExprListDelete(db, p->pOrderBy);
105184 sqlite3SelectDelete(db, p->pPrior);
105185 sqlite3ExprDelete(db, p->pLimit);
105186 sqlite3ExprDelete(db, p->pOffset);
105187 sqlite3WithDelete(db, p->pWith);
 
 
 
 
 
105188 }
105189
105190 /*
105191 ** Initialize a SelectDest structure.
105192 */
@@ -105241,12 +105427,11 @@
105241 pNew->pOffset = pOffset;
105242 assert( pOffset==0 || pLimit!=0 );
105243 pNew->addrOpenEphm[0] = -1;
105244 pNew->addrOpenEphm[1] = -1;
105245 if( db->mallocFailed ) {
105246 clearSelect(db, pNew);
105247 if( pNew!=&standin ) sqlite3DbFree(db, pNew);
105248 pNew = 0;
105249 }else{
105250 assert( pNew->pSrc!=0 || pParse->nErr>0 );
105251 }
105252 assert( pNew!=&standin );
@@ -105267,14 +105452,11 @@
105267
105268 /*
105269 ** Delete the given Select structure and all of its substructures.
105270 */
105271 SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
105272 if( p ){
105273 clearSelect(db, p);
105274 sqlite3DbFree(db, p);
105275 }
105276 }
105277
105278 /*
105279 ** Return a pointer to the right-most SELECT statement in a compound.
105280 */
@@ -105653,11 +105835,13 @@
105653 if( pParse->db->mallocFailed ) return;
105654 pOp->p2 = nKey + nData;
105655 pKI = pOp->p4.pKeyInfo;
105656 memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
105657 sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
105658 pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
 
 
105659 addrJmp = sqlite3VdbeCurrentAddr(v);
105660 sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
105661 pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
105662 pSort->regReturn = ++pParse->nMem;
105663 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
@@ -106164,11 +106348,11 @@
106164 struct ExprList_item *pItem;
106165 sqlite3 *db = pParse->db;
106166 int i;
106167
106168 nExpr = pList->nExpr;
106169 pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
106170 if( pInfo ){
106171 assert( sqlite3KeyInfoIsWriteable(pInfo) );
106172 for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
106173 CollSeq *pColl;
106174 pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
@@ -107186,10 +107370,70 @@
107186 Parse *pParse, /* Parsing context */
107187 Select *p, /* The right-most of SELECTs to be coded */
107188 SelectDest *pDest /* What to do with query results */
107189 );
107190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107191
107192 /*
107193 ** This routine is called to process a compound query form from
107194 ** two or more separate queries using UNION, UNION ALL, EXCEPT, or
107195 ** INTERSECT
@@ -107266,22 +107510,24 @@
107266 assert( p->pEList );
107267 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
107268 sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
107269 dest.eDest = SRT_Table;
107270 }
 
 
 
 
 
 
 
107271
107272 /* Make sure all SELECTs in the statement have the same number of elements
107273 ** in their result sets.
107274 */
107275 assert( p->pEList && pPrior->pEList );
107276 if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
107277 if( p->selFlags & SF_Values ){
107278 sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
107279 }else{
107280 sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
107281 " do not have the same number of result columns", selectOpName(p->op));
107282 }
107283 rc = 1;
107284 goto multi_select_end;
107285 }
107286
107287 #ifndef SQLITE_OMIT_CTE
@@ -109163,11 +109409,13 @@
109163 if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
109164 return WRC_Prune;
109165 }
109166 pTabList = p->pSrc;
109167 pEList = p->pEList;
109168 sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
 
 
109169
109170 /* Make sure cursor numbers have been assigned to all entries in
109171 ** the FROM clause of the SELECT statement.
109172 */
109173 sqlite3SrcListAssignCursors(pParse, pTabList);
@@ -109454,11 +109702,13 @@
109454 if( pParse->hasCompound ){
109455 w.xSelectCallback = convertCompoundSelectToSubquery;
109456 sqlite3WalkSelect(&w, pSelect);
109457 }
109458 w.xSelectCallback = selectExpander;
109459 w.xSelectCallback2 = selectPopWith;
 
 
109460 sqlite3WalkSelect(&w, pSelect);
109461 }
109462
109463
109464 #ifndef SQLITE_OMIT_SUBQUERY
@@ -109968,11 +110218,11 @@
109968 ** we figure out that the sorting index is not needed. The addrSortIndex
109969 ** variable is used to facilitate that change.
109970 */
109971 if( sSort.pOrderBy ){
109972 KeyInfo *pKeyInfo;
109973 pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
109974 sSort.iECursor = pParse->nTab++;
109975 sSort.addrSortIndex =
109976 sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
109977 sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
109978 (char*)pKeyInfo, P4_KEYINFO
@@ -110142,11 +110392,11 @@
110142 ** implement it. Allocate that sorting index now. If it turns out
110143 ** that we do not need it after all, the OP_SorterOpen instruction
110144 ** will be converted into a Noop.
110145 */
110146 sAggInfo.sortingIdx = pParse->nTab++;
110147 pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
110148 addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
110149 sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
110150 0, (char*)pKeyInfo, P4_KEYINFO);
110151
110152 /* Initialize memory locations used by GROUP BY aggregate processing
@@ -110756,11 +111006,11 @@
110756 ){
110757 int rc;
110758 TabResult res;
110759
110760 #ifdef SQLITE_ENABLE_API_ARMOR
110761 if( pazResult==0 ) return SQLITE_MISUSE_BKPT;
110762 #endif
110763 *pazResult = 0;
110764 if( pnColumn ) *pnColumn = 0;
110765 if( pnRow ) *pnRow = 0;
110766 if( pzErrMsg ) *pzErrMsg = 0;
@@ -118626,11 +118876,10 @@
118626 sqlite3_free(p->u.vtab.idxStr);
118627 p->u.vtab.needFree = 0;
118628 p->u.vtab.idxStr = 0;
118629 }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
118630 sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
118631 sqlite3KeyInfoUnref(p->u.btree.pIndex->pKeyInfo);
118632 sqlite3DbFree(db, p->u.btree.pIndex);
118633 p->u.btree.pIndex = 0;
118634 }
118635 }
118636 }
@@ -123783,17 +124032,23 @@
123783 Select *p = yymsp[0].minor.yy3, *pNext, *pLoop;
123784 if( p ){
123785 int cnt = 0, mxSelect;
123786 p->pWith = yymsp[-1].minor.yy59;
123787 if( p->pPrior ){
 
123788 pNext = 0;
123789 for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
123790 pLoop->pNext = pNext;
123791 pLoop->selFlags |= SF_Compound;
 
123792 }
123793 mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
123794 if( mxSelect && cnt>mxSelect ){
 
 
 
 
123795 sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
123796 }
123797 }
123798 }else{
123799 sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
@@ -125633,10 +125888,13 @@
125633 u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
125634 sqlite3 *db = pParse->db; /* The database connection */
125635 int mxSqlLen; /* Max length of an SQL string */
125636
125637
 
 
 
125638 mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
125639 if( db->nVdbeActive==0 ){
125640 db->u1.isInterrupted = 0;
125641 }
125642 pParse->rc = SQLITE_OK;
@@ -125871,17 +126129,10 @@
125871 */
125872 SQLITE_API int sqlite3_complete(const char *zSql){
125873 u8 state = 0; /* Current state, using numbers defined in header comment */
125874 u8 token; /* Value of the next token */
125875
125876 #ifdef SQLITE_ENABLE_API_ARMOR
125877 if( zSql==0 ){
125878 (void)SQLITE_MISUSE_BKPT;
125879 return 0;
125880 }
125881 #endif
125882
125883 #ifndef SQLITE_OMIT_TRIGGER
125884 /* A complex statement machine used to detect the end of a CREATE TRIGGER
125885 ** statement. This is the normal case.
125886 */
125887 static const u8 trans[8][8] = {
@@ -125906,10 +126157,17 @@
125906 /* 0 INVALID: */ { 1, 0, 2, },
125907 /* 1 START: */ { 1, 1, 2, },
125908 /* 2 NORMAL: */ { 1, 2, 2, },
125909 };
125910 #endif /* SQLITE_OMIT_TRIGGER */
 
 
 
 
 
 
 
125911
125912 while( *zSql ){
125913 switch( *zSql ){
125914 case ';': { /* A semicolon */
125915 token = tkSEMI;
@@ -126208,11 +126466,11 @@
126208 ** If the following function pointer is not NULL and if
126209 ** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
126210 ** I/O active are written using this function. These messages
126211 ** are intended for debugging activity only.
126212 */
126213 SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*, ...) = 0;
126214 #endif
126215
126216 /*
126217 ** If the following global variable points to a string which is the
126218 ** name of a directory, then that directory will be used to store
@@ -126417,10 +126675,17 @@
126417 ** routine is not threadsafe. But it is safe to invoke this routine
126418 ** on when SQLite is already shut down. If SQLite is already shut down
126419 ** when this routine is invoked, then this routine is a harmless no-op.
126420 */
126421 SQLITE_API int sqlite3_shutdown(void){
 
 
 
 
 
 
 
126422 if( sqlite3GlobalConfig.isInit ){
126423 #ifdef SQLITE_EXTRA_SHUTDOWN
126424 void SQLITE_EXTRA_SHUTDOWN(void);
126425 SQLITE_EXTRA_SHUTDOWN();
126426 #endif
@@ -126732,10 +126997,15 @@
126732 ** heap. */
126733 sqlite3GlobalConfig.nHeap = va_arg(ap, int);
126734 break;
126735 }
126736 #endif
 
 
 
 
 
126737
126738 default: {
126739 rc = SQLITE_ERROR;
126740 break;
126741 }
@@ -127178,20 +127448,10 @@
127178
127179 /* Close all database connections */
127180 for(j=0; j<db->nDb; j++){
127181 struct Db *pDb = &db->aDb[j];
127182 if( pDb->pBt ){
127183 if( pDb->pSchema ){
127184 /* Must clear the KeyInfo cache. See ticket [e4a18565a36884b00edf] */
127185 sqlite3BtreeEnter(pDb->pBt);
127186 for(i=sqliteHashFirst(&pDb->pSchema->idxHash); i; i=sqliteHashNext(i)){
127187 Index *pIdx = sqliteHashData(i);
127188 sqlite3KeyInfoUnref(pIdx->pKeyInfo);
127189 pIdx->pKeyInfo = 0;
127190 }
127191 sqlite3BtreeLeave(pDb->pBt);
127192 }
127193 sqlite3BtreeClose(pDb->pBt);
127194 pDb->pBt = 0;
127195 if( j!=1 ){
127196 pDb->pSchema = 0;
127197 }
@@ -127494,11 +127754,11 @@
127494 */
127495 static int sqliteDefaultBusyCallback(
127496 void *ptr, /* Database connection */
127497 int count /* Number of times table has been busy */
127498 ){
127499 #if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
127500 static const u8 delays[] =
127501 { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
127502 static const u8 totals[] =
127503 { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
127504 # define NDELAY ArraySize(delays)
@@ -128110,10 +128370,11 @@
128110 }
128111 if( iDb<0 ){
128112 rc = SQLITE_ERROR;
128113 sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
128114 }else{
 
128115 rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
128116 sqlite3Error(db, rc);
128117 }
128118 rc = sqlite3ApiExit(db, rc);
128119 sqlite3_mutex_leave(db->mutex);
@@ -128315,36 +128576,10 @@
128315 */
128316 SQLITE_API const char *sqlite3_errstr(int rc){
128317 return sqlite3ErrStr(rc);
128318 }
128319
128320 /*
128321 ** Invalidate all cached KeyInfo objects for database connection "db"
128322 */
128323 static void invalidateCachedKeyInfo(sqlite3 *db){
128324 Db *pDb; /* A single database */
128325 int iDb; /* The database index number */
128326 HashElem *k; /* For looping over tables in pDb */
128327 Table *pTab; /* A table in the database */
128328 Index *pIdx; /* Each index */
128329
128330 for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
128331 if( pDb->pBt==0 ) continue;
128332 sqlite3BtreeEnter(pDb->pBt);
128333 for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
128334 pTab = (Table*)sqliteHashData(k);
128335 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
128336 if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){
128337 sqlite3KeyInfoUnref(pIdx->pKeyInfo);
128338 pIdx->pKeyInfo = 0;
128339 }
128340 }
128341 }
128342 sqlite3BtreeLeave(pDb->pBt);
128343 }
128344 }
128345
128346 /*
128347 ** Create a new collating function for database "db". The name is zName
128348 ** and the encoding is enc.
128349 */
128350 static int createCollation(
@@ -128384,11 +128619,10 @@
128384 sqlite3ErrorWithMsg(db, SQLITE_BUSY,
128385 "unable to delete/modify collation sequence due to active statements");
128386 return SQLITE_BUSY;
128387 }
128388 sqlite3ExpirePreparedStatements(db);
128389 invalidateCachedKeyInfo(db);
128390
128391 /* If collation sequence pColl was created directly by a call to
128392 ** sqlite3_create_collation, and not generated by synthCollSeq(),
128393 ** then any copies made by synthCollSeq() need to be invalidated.
128394 ** Also, collation destructor - CollSeq.xDel() - function may need
@@ -128941,10 +129175,11 @@
128941 sqlite3Error(db, rc);
128942 goto opendb_out;
128943 }
128944 sqlite3BtreeEnter(db->aDb[0].pBt);
128945 db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
 
128946 sqlite3BtreeLeave(db->aDb[0].pBt);
128947 db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
128948
128949 /* The default safety_level for the main database is 'full'; for the temp
128950 ** database it is 'NONE'. This matches the pager layer defaults.
@@ -129099,11 +129334,11 @@
129099 if( zFilename8 ){
129100 rc = openDatabase(zFilename8, ppDb,
129101 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
129102 assert( *ppDb || rc==SQLITE_NOMEM );
129103 if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
129104 ENC(*ppDb) = SQLITE_UTF16NATIVE;
129105 }
129106 }else{
129107 rc = SQLITE_NOMEM;
129108 }
129109 sqlite3ValueFree(pVal);
@@ -129310,11 +129545,11 @@
129310 ){
129311 int rc;
129312 char *zErrMsg = 0;
129313 Table *pTab = 0;
129314 Column *pCol = 0;
129315 int iCol;
129316
129317 char const *zDataType = 0;
129318 char const *zCollSeq = 0;
129319 int notnull = 0;
129320 int primarykey = 0;
@@ -129841,32 +130076,34 @@
129841 /*
129842 ** Return the filename of the database associated with a database
129843 ** connection.
129844 */
129845 SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
 
129846 #ifdef SQLITE_ENABLE_API_ARMOR
129847 if( !sqlite3SafetyCheckOk(db) ){
129848 (void)SQLITE_MISUSE_BKPT;
129849 return 0;
129850 }
129851 #endif
129852 Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
129853 return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
129854 }
129855
129856 /*
129857 ** Return 1 if database is read-only or 0 if read/write. Return -1 if
129858 ** no such database exists.
129859 */
129860 SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
 
129861 #ifdef SQLITE_ENABLE_API_ARMOR
129862 if( !sqlite3SafetyCheckOk(db) ){
129863 (void)SQLITE_MISUSE_BKPT;
129864 return -1;
129865 }
129866 #endif
129867 Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
129868 return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
129869 }
129870
129871 /************** End of main.c ************************************************/
129872 /************** Begin file notify.c ******************************************/
@@ -132931,11 +133168,11 @@
132931 const char *zNode, /* Buffer containing segment interior node */
132932 int nNode, /* Size of buffer at zNode */
132933 sqlite3_int64 *piLeaf, /* Selected leaf node */
132934 sqlite3_int64 *piLeaf2 /* Selected leaf node */
132935 ){
132936 int rc; /* Return code */
132937 int iHeight; /* Height of this node in tree */
132938
132939 assert( piLeaf || piLeaf2 );
132940
132941 fts3GetVarint32(zNode, &iHeight);
@@ -132942,11 +133179,11 @@
132942 rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
132943 assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
132944
132945 if( rc==SQLITE_OK && iHeight>1 ){
132946 char *zBlob = 0; /* Blob read from %_segments table */
132947 int nBlob; /* Size of zBlob in bytes */
132948
132949 if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
132950 rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
132951 if( rc==SQLITE_OK ){
132952 rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0);
@@ -134164,11 +134401,11 @@
134164 int idxNum, /* Strategy index */
134165 const char *idxStr, /* Unused */
134166 int nVal, /* Number of elements in apVal */
134167 sqlite3_value **apVal /* Arguments for the indexing scheme */
134168 ){
134169 int rc;
134170 char *zSql; /* SQL statement used to access %_content */
134171 int eSearch;
134172 Fts3Table *p = (Fts3Table *)pCursor->pVtab;
134173 Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
134174
@@ -140652,11 +140889,11 @@
140652 int argc, /* Number of elements in argv array */
140653 const char * const *argv, /* xCreate/xConnect argument array */
140654 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
140655 char **pzErr /* OUT: sqlite3_malloc'd error message */
140656 ){
140657 Fts3tokTable *pTab;
140658 const sqlite3_tokenizer_module *pMod = 0;
140659 sqlite3_tokenizer *pTok = 0;
140660 int rc;
140661 char **azDequote = 0;
140662 int nDequote;
@@ -144027,12 +144264,12 @@
144027 }
144028 rc = sqlite3_reset(pRange);
144029
144030 if( bOk ){
144031 int iIdx = 0;
144032 sqlite3_stmt *pUpdate1;
144033 sqlite3_stmt *pUpdate2;
144034
144035 if( rc==SQLITE_OK ){
144036 rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0);
144037 }
144038 if( rc==SQLITE_OK ){
@@ -149260,17 +149497,16 @@
149260 */
149261 static int readInt16(u8 *p){
149262 return (p[0]<<8) + p[1];
149263 }
149264 static void readCoord(u8 *p, RtreeCoord *pCoord){
149265 u32 i = (
149266 (((u32)p[0]) << 24) +
149267 (((u32)p[1]) << 16) +
149268 (((u32)p[2]) << 8) +
149269 (((u32)p[3]) << 0)
149270 );
149271 *(u32 *)pCoord = i;
149272 }
149273 static i64 readInt64(u8 *p){
149274 return (
149275 (((i64)p[0]) << 56) +
149276 (((i64)p[1]) << 48) +
@@ -149295,11 +149531,11 @@
149295 }
149296 static int writeCoord(u8 *p, RtreeCoord *pCoord){
149297 u32 i;
149298 assert( sizeof(RtreeCoord)==4 );
149299 assert( sizeof(u32)==4 );
149300 i = *(u32 *)pCoord;
149301 p[0] = (i>>24)&0xFF;
149302 p[1] = (i>>16)&0xFF;
149303 p[2] = (i>> 8)&0xFF;
149304 p[3] = (i>> 0)&0xFF;
149305 return 4;
@@ -149626,18 +149862,17 @@
149626 RtreeNode *pNode, /* The node containing the cell to be read */
149627 int iCell, /* Index of the cell within the node */
149628 RtreeCell *pCell /* OUT: Write the cell contents here */
149629 ){
149630 u8 *pData;
149631 u8 *pEnd;
149632 RtreeCoord *pCoord;
 
149633 pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
149634 pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
149635 pEnd = pData + pRtree->nDim*8;
149636 pCoord = pCell->aCoord;
149637 for(; pData<pEnd; pData+=4, pCoord++){
149638 readCoord(pData, pCoord);
149639 }
149640 }
149641
149642
149643 /* Forward declaration for the function that does the work of
@@ -150073,11 +150308,11 @@
150073 }
150074 i = pCur->nPoint++;
150075 pNew = pCur->aPoint + i;
150076 pNew->rScore = rScore;
150077 pNew->iLevel = iLevel;
150078 assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH );
150079 while( i>0 ){
150080 RtreeSearchPoint *pParent;
150081 j = (i-1)/2;
150082 pParent = pCur->aPoint + j;
150083 if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break;
@@ -151696,10 +151931,12 @@
151696 RtreeCell cell; /* New cell to insert if nData>1 */
151697 int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
151698
151699 rtreeReference(pRtree);
151700 assert(nData>=1);
 
 
151701
151702 /* Constraint handling. A write operation on an r-tree table may return
151703 ** SQLITE_CONSTRAINT for two reasons:
151704 **
151705 ** 1. A duplicate rowid value, or
151706
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.8.8.2. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -41,10 +41,57 @@
41 **
42 */
43 #ifndef _SQLITEINT_H_
44 #define _SQLITEINT_H_
45
46 /*
47 ** Include the header file used to customize the compiler options for MSVC.
48 ** This should be done first so that it can successfully prevent spurious
49 ** compiler warnings due to subsequent content in this file and other files
50 ** that are included by this file.
51 */
52 /************** Include msvc.h in the middle of sqliteInt.h ******************/
53 /************** Begin file msvc.h ********************************************/
54 /*
55 ** 2015 January 12
56 **
57 ** The author disclaims copyright to this source code. In place of
58 ** a legal notice, here is a blessing:
59 **
60 ** May you do good and not evil.
61 ** May you find forgiveness for yourself and forgive others.
62 ** May you share freely, never taking more than you give.
63 **
64 ******************************************************************************
65 **
66 ** This file contains code that is specific to MSVC.
67 */
68 #ifndef _MSVC_H_
69 #define _MSVC_H_
70
71 #if defined(_MSC_VER)
72 #pragma warning(disable : 4054)
73 #pragma warning(disable : 4055)
74 #pragma warning(disable : 4100)
75 #pragma warning(disable : 4127)
76 #pragma warning(disable : 4152)
77 #pragma warning(disable : 4189)
78 #pragma warning(disable : 4206)
79 #pragma warning(disable : 4210)
80 #pragma warning(disable : 4232)
81 #pragma warning(disable : 4244)
82 #pragma warning(disable : 4305)
83 #pragma warning(disable : 4306)
84 #pragma warning(disable : 4702)
85 #pragma warning(disable : 4706)
86 #endif /* defined(_MSC_VER) */
87
88 #endif /* _MSVC_H_ */
89
90 /************** End of msvc.h ************************************************/
91 /************** Continuing where we left off in sqliteInt.h ******************/
92
93 /*
94 ** These #defines should enable >2GB file support on POSIX if the
95 ** underlying operating system supports it. If the OS lacks
96 ** large file support, or if the OS is windows, these should be no-ops.
97 **
@@ -229,13 +276,13 @@
276 **
277 ** See also: [sqlite3_libversion()],
278 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
279 ** [sqlite_version()] and [sqlite_source_id()].
280 */
281 #define SQLITE_VERSION "3.8.8.2"
282 #define SQLITE_VERSION_NUMBER 3008008
283 #define SQLITE_SOURCE_ID "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
284
285 /*
286 ** CAPI3REF: Run-Time Library Version Numbers
287 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
288 **
@@ -323,11 +370,11 @@
370 ** This interface only reports on the compile-time mutex setting
371 ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
372 ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
373 ** can be fully or partially disabled using a call to [sqlite3_config()]
374 ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
375 ** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
376 ** sqlite3_threadsafe() function shows only the compile-time setting of
377 ** thread safety, not any run-time changes to that setting made by
378 ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
379 ** is unchanged by calls to sqlite3_config().)^
380 **
@@ -1692,11 +1739,11 @@
1739 ** configuration option.
1740 ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
1741 ** 8-byte aligned
1742 ** memory, the size of each page buffer (sz), and the number of pages (N).
1743 ** The sz argument should be the size of the largest database page
1744 ** (a power of two between 512 and 65536) plus some extra bytes for each
1745 ** page header. ^The number of extra bytes needed by the page header
1746 ** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
1747 ** to [sqlite3_config()].
1748 ** ^It is harmless, apart from the wasted memory,
1749 ** for the sz parameter to be larger than necessary. The first
@@ -1872,10 +1919,21 @@
1919 ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
1920 ** is a pointer to an integer and writes into that integer the number of extra
1921 ** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
1922 ** The amount of extra space required can change depending on the compiler,
1923 ** target platform, and SQLite version.
1924 **
1925 ** [[SQLITE_CONFIG_PMASZ]]
1926 ** <dt>SQLITE_CONFIG_PMASZ
1927 ** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
1928 ** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
1929 ** sorter to that integer. The default minimum PMA Size is set by the
1930 ** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
1931 ** to help with sort operations when multithreaded sorting
1932 ** is enabled (using the [PRAGMA threads] command) and the amount of content
1933 ** to be sorted exceeds the page size times the minimum of the
1934 ** [PRAGMA cache_size] setting and this value.
1935 ** </dl>
1936 */
1937 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
1938 #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
1939 #define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1898,10 +1956,11 @@
1956 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
1957 #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
1958 #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
1959 #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
1960 #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
1961 #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
1962
1963 /*
1964 ** CAPI3REF: Database Connection Configuration Options
1965 **
1966 ** These constants are the available integer configuration options that
@@ -7307,16 +7366,14 @@
7366
7367 /*
7368 ** CAPI3REF: Write-Ahead Log Commit Hook
7369 **
7370 ** ^The [sqlite3_wal_hook()] function is used to register a callback that
7371 ** is invoked each time data is committed to a database in wal mode.
 
 
7372 **
7373 ** ^(The callback is invoked by SQLite after the commit has taken place and
7374 ** the associated write-lock on the database released)^, so the implementation
7375 ** may read, write or [checkpoint] the database as required.
7376 **
7377 ** ^The first parameter passed to the callback function when it is invoked
7378 ** is a copy of the third parameter passed to sqlite3_wal_hook() when
7379 ** registering the callback. ^The second is a copy of the database handle.
@@ -7603,10 +7660,14 @@
7660 **
7661 ** The following constants can be used for the T parameter to the
7662 ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
7663 ** different metric for sqlite3_stmt_scanstatus() to return.
7664 **
7665 ** When the value returned to V is a string, space to hold that string is
7666 ** managed by the prepared statement S and will be automatically freed when
7667 ** S is finalized.
7668 **
7669 ** <dl>
7670 ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
7671 ** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
7672 ** set to the total number of times that the X-th loop has run.</dd>
7673 **
@@ -7648,11 +7709,18 @@
7709 #define SQLITE_SCANSTAT_SELECTID 5
7710
7711 /*
7712 ** CAPI3REF: Prepared Statement Scan Status
7713 **
7714 ** This interface returns information about the predicted and measured
7715 ** performance for pStmt. Advanced applications can use this
7716 ** interface to compare the predicted and the measured performance and
7717 ** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
7718 **
7719 ** Since this interface is expected to be rarely used, it is only
7720 ** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
7721 ** compile-time option.
7722 **
7723 ** The "iScanStatusOp" parameter determines which status information to return.
7724 ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
7725 ** of this interface is undefined.
7726 ** ^The requested measurement is written into a variable pointed to by
@@ -7666,13 +7734,10 @@
7734 ** ^Statistics might not be available for all loops in all statements. ^In cases
7735 ** where there exist loops with no available statistics, this function behaves
7736 ** as if the loop did not exist - it returns non-zero and leave the variable
7737 ** that pOut points to unchanged.
7738 **
 
 
 
7739 ** See also: [sqlite3_stmt_scanstatus_reset()]
7740 */
7741 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
7742 sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
7743 int idx, /* Index of loop to report on */
@@ -9100,11 +9165,11 @@
9165 #define _BTREE_H_
9166
9167 /* TODO: This definition is just included so other modules compile. It
9168 ** needs to be revisited.
9169 */
9170 #define SQLITE_N_BTREE_META 16
9171
9172 /*
9173 ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
9174 ** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
9175 */
@@ -9215,10 +9280,15 @@
9280 ** offset = 36 + (idx * 4)
9281 **
9282 ** For example, the free-page-count field is located at byte offset 36 of
9283 ** the database file header. The incr-vacuum-flag field is located at
9284 ** byte offset 64 (== 36+4*7).
9285 **
9286 ** The BTREE_DATA_VERSION value is not really a value stored in the header.
9287 ** It is a read-only number computed by the pager. But we merge it with
9288 ** the header value access routines since its access pattern is the same.
9289 ** Call it a "virtual meta value".
9290 */
9291 #define BTREE_FREE_PAGE_COUNT 0
9292 #define BTREE_SCHEMA_VERSION 1
9293 #define BTREE_FILE_FORMAT 2
9294 #define BTREE_DEFAULT_CACHE_SIZE 3
@@ -9225,10 +9295,11 @@
9295 #define BTREE_LARGEST_ROOT_PAGE 4
9296 #define BTREE_TEXT_ENCODING 5
9297 #define BTREE_USER_VERSION 6
9298 #define BTREE_INCR_VACUUM 7
9299 #define BTREE_APPLICATION_ID 8
9300 #define BTREE_DATA_VERSION 15 /* A virtual meta-value */
9301
9302 /*
9303 ** Values that may be OR'd together to form the second argument of an
9304 ** sqlite3BtreeCursorHints() call.
9305 */
@@ -10006,10 +10077,11 @@
10077 SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
10078 #endif
10079
10080 /* Functions used to query pager state and configuration. */
10081 SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
10082 SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
10083 SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
10084 SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
10085 SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
10086 SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
10087 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
@@ -10747,10 +10819,11 @@
10819 i64 szMmap; /* Default mmap_size setting */
10820 unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
10821 int errCode; /* Most recent error code (SQLITE_*) */
10822 int errMask; /* & result codes with this before returning */
10823 u16 dbOptFlags; /* Flags to enable/disable optimizations */
10824 u8 enc; /* Text encoding */
10825 u8 autoCommit; /* The auto-commit flag. */
10826 u8 temp_store; /* 1: file 2: memory 0: default */
10827 u8 mallocFailed; /* True if we have seen a malloc failure */
10828 u8 dfltLockMode; /* Default locking-mode for attached dbs */
10829 signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
@@ -10848,11 +10921,12 @@
10921 };
10922
10923 /*
10924 ** A macro to discover the encoding of a database.
10925 */
10926 #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
10927 #define ENC(db) ((db)->enc)
10928
10929 /*
10930 ** Possible values for the sqlite3.flags.
10931 */
10932 #define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
@@ -11472,11 +11546,10 @@
11546 Index *pNext; /* The next index associated with the same table */
11547 Schema *pSchema; /* Schema containing this index */
11548 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
11549 char **azColl; /* Array of collation sequence names for index */
11550 Expr *pPartIdxWhere; /* WHERE clause for partial indices */
 
11551 int tnum; /* DB Page containing root of this index */
11552 LogEst szIdxRow; /* Estimated average row size in bytes */
11553 u16 nKeyCol; /* Number of columns forming the key */
11554 u16 nColumn; /* Number of columns stored in the index */
11555 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
@@ -12036,11 +12109,11 @@
12109 #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
12110 #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
12111 #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
12112 #define SF_Compound 0x0040 /* Part of a compound query */
12113 #define SF_Values 0x0080 /* Synthesized from VALUES clause */
12114 #define SF_AllValues 0x0100 /* All terms of compound are VALUES */
12115 #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
12116 #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
12117 #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
12118 #define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
12119
@@ -12526,10 +12599,11 @@
12599 void *pPage; /* Page cache memory */
12600 int szPage; /* Size of each page in pPage[] */
12601 int nPage; /* Number of pages in pPage[] */
12602 int mxParserStack; /* maximum depth of the parser stack */
12603 int sharedCacheEnabled; /* true if shared-cache mode enabled */
12604 u32 szPma; /* Maximum Sorter PMA size */
12605 /* The above might be initialized to non-zero. The following need to always
12606 ** initially be zero, however. */
12607 int isInit; /* True after initialization has finished */
12608 int inProgress; /* True while initialization in progress */
12609 int isMutexInit; /* True after mutexes are initialized */
@@ -12663,11 +12737,11 @@
12737 ** FTS4 is really an extension for FTS3. It is enabled using the
12738 ** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call
12739 ** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
12740 */
12741 #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
12742 # define SQLITE_ENABLE_FTS3 1
12743 #endif
12744
12745 /*
12746 ** The ctype.h header is needed for non-ASCII systems. It is also
12747 ** needed by FTS3 when FTS3 is included in the amalgamation.
@@ -13448,11 +13522,11 @@
13522 ** print I/O tracing messages.
13523 */
13524 #ifdef SQLITE_ENABLE_IOTRACE
13525 # define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
13526 SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*);
13527 void (*sqlite3IoTrace)(const char*,...);
13528 #else
13529 # define IOTRACE(A)
13530 # define sqlite3VdbeIOTraceSql(X)
13531 #endif
13532
@@ -13661,10 +13735,17 @@
13735 */
13736 #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
13737 # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
13738 #endif
13739
13740 /* The minimum PMA size is set to this value multiplied by the database
13741 ** page size in bytes.
13742 */
13743 #ifndef SQLITE_SORTER_PMASZ
13744 # define SQLITE_SORTER_PMASZ 250
13745 #endif
13746
13747 /*
13748 ** The following singleton contains the global configuration for
13749 ** the SQLite library.
13750 */
13751 SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
@@ -13691,10 +13772,11 @@
13772 (void*)0, /* pPage */
13773 0, /* szPage */
13774 0, /* nPage */
13775 0, /* mxParserStack */
13776 0, /* sharedCacheEnabled */
13777 SQLITE_SORTER_PMASZ, /* szPma */
13778 /* All the rest should always be initialized to zero */
13779 0, /* isInit */
13780 0, /* inProgress */
13781 0, /* isMutexInit */
13782 0, /* isMallocInit */
@@ -13797,355 +13879,355 @@
13879 /* These macros are provided to "stringify" the value of the define
13880 ** for those options in which the value is meaningful. */
13881 #define CTIMEOPT_VAL_(opt) #opt
13882 #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
13883
13884 #if SQLITE_32BIT_ROWID
13885 "32BIT_ROWID",
13886 #endif
13887 #if SQLITE_4_BYTE_ALIGNED_MALLOC
13888 "4_BYTE_ALIGNED_MALLOC",
13889 #endif
13890 #if SQLITE_CASE_SENSITIVE_LIKE
13891 "CASE_SENSITIVE_LIKE",
13892 #endif
13893 #if SQLITE_CHECK_PAGES
13894 "CHECK_PAGES",
13895 #endif
13896 #if SQLITE_COVERAGE_TEST
13897 "COVERAGE_TEST",
13898 #endif
13899 #if SQLITE_DEBUG
13900 "DEBUG",
13901 #endif
13902 #if SQLITE_DEFAULT_LOCKING_MODE
13903 "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
13904 #endif
13905 #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
13906 "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
13907 #endif
13908 #if SQLITE_DISABLE_DIRSYNC
13909 "DISABLE_DIRSYNC",
13910 #endif
13911 #if SQLITE_DISABLE_LFS
13912 "DISABLE_LFS",
13913 #endif
13914 #if SQLITE_ENABLE_API_ARMOR
13915 "ENABLE_API_ARMOR",
13916 #endif
13917 #if SQLITE_ENABLE_ATOMIC_WRITE
13918 "ENABLE_ATOMIC_WRITE",
13919 #endif
13920 #if SQLITE_ENABLE_CEROD
13921 "ENABLE_CEROD",
13922 #endif
13923 #if SQLITE_ENABLE_COLUMN_METADATA
13924 "ENABLE_COLUMN_METADATA",
13925 #endif
13926 #if SQLITE_ENABLE_EXPENSIVE_ASSERT
13927 "ENABLE_EXPENSIVE_ASSERT",
13928 #endif
13929 #if SQLITE_ENABLE_FTS1
13930 "ENABLE_FTS1",
13931 #endif
13932 #if SQLITE_ENABLE_FTS2
13933 "ENABLE_FTS2",
13934 #endif
13935 #if SQLITE_ENABLE_FTS3
13936 "ENABLE_FTS3",
13937 #endif
13938 #if SQLITE_ENABLE_FTS3_PARENTHESIS
13939 "ENABLE_FTS3_PARENTHESIS",
13940 #endif
13941 #if SQLITE_ENABLE_FTS4
13942 "ENABLE_FTS4",
13943 #endif
13944 #if SQLITE_ENABLE_ICU
13945 "ENABLE_ICU",
13946 #endif
13947 #if SQLITE_ENABLE_IOTRACE
13948 "ENABLE_IOTRACE",
13949 #endif
13950 #if SQLITE_ENABLE_LOAD_EXTENSION
13951 "ENABLE_LOAD_EXTENSION",
13952 #endif
13953 #if SQLITE_ENABLE_LOCKING_STYLE
13954 "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
13955 #endif
13956 #if SQLITE_ENABLE_MEMORY_MANAGEMENT
13957 "ENABLE_MEMORY_MANAGEMENT",
13958 #endif
13959 #if SQLITE_ENABLE_MEMSYS3
13960 "ENABLE_MEMSYS3",
13961 #endif
13962 #if SQLITE_ENABLE_MEMSYS5
13963 "ENABLE_MEMSYS5",
13964 #endif
13965 #if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
13966 "ENABLE_OVERSIZE_CELL_CHECK",
13967 #endif
13968 #if SQLITE_ENABLE_RTREE
13969 "ENABLE_RTREE",
13970 #endif
13971 #if defined(SQLITE_ENABLE_STAT4)
13972 "ENABLE_STAT4",
13973 #elif defined(SQLITE_ENABLE_STAT3)
13974 "ENABLE_STAT3",
13975 #endif
13976 #if SQLITE_ENABLE_UNLOCK_NOTIFY
13977 "ENABLE_UNLOCK_NOTIFY",
13978 #endif
13979 #if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
13980 "ENABLE_UPDATE_DELETE_LIMIT",
13981 #endif
13982 #if SQLITE_HAS_CODEC
13983 "HAS_CODEC",
13984 #endif
13985 #if HAVE_ISNAN || SQLITE_HAVE_ISNAN
13986 "HAVE_ISNAN",
13987 #endif
13988 #if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
13989 "HOMEGROWN_RECURSIVE_MUTEX",
13990 #endif
13991 #if SQLITE_IGNORE_AFP_LOCK_ERRORS
13992 "IGNORE_AFP_LOCK_ERRORS",
13993 #endif
13994 #if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
13995 "IGNORE_FLOCK_LOCK_ERRORS",
13996 #endif
13997 #ifdef SQLITE_INT64_TYPE
13998 "INT64_TYPE",
13999 #endif
14000 #if SQLITE_LOCK_TRACE
14001 "LOCK_TRACE",
14002 #endif
14003 #if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
14004 "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
14005 #endif
14006 #ifdef SQLITE_MAX_SCHEMA_RETRY
14007 "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
14008 #endif
14009 #if SQLITE_MEMDEBUG
14010 "MEMDEBUG",
14011 #endif
14012 #if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
14013 "MIXED_ENDIAN_64BIT_FLOAT",
14014 #endif
14015 #if SQLITE_NO_SYNC
14016 "NO_SYNC",
14017 #endif
14018 #if SQLITE_OMIT_ALTERTABLE
14019 "OMIT_ALTERTABLE",
14020 #endif
14021 #if SQLITE_OMIT_ANALYZE
14022 "OMIT_ANALYZE",
14023 #endif
14024 #if SQLITE_OMIT_ATTACH
14025 "OMIT_ATTACH",
14026 #endif
14027 #if SQLITE_OMIT_AUTHORIZATION
14028 "OMIT_AUTHORIZATION",
14029 #endif
14030 #if SQLITE_OMIT_AUTOINCREMENT
14031 "OMIT_AUTOINCREMENT",
14032 #endif
14033 #if SQLITE_OMIT_AUTOINIT
14034 "OMIT_AUTOINIT",
14035 #endif
14036 #if SQLITE_OMIT_AUTOMATIC_INDEX
14037 "OMIT_AUTOMATIC_INDEX",
14038 #endif
14039 #if SQLITE_OMIT_AUTORESET
14040 "OMIT_AUTORESET",
14041 #endif
14042 #if SQLITE_OMIT_AUTOVACUUM
14043 "OMIT_AUTOVACUUM",
14044 #endif
14045 #if SQLITE_OMIT_BETWEEN_OPTIMIZATION
14046 "OMIT_BETWEEN_OPTIMIZATION",
14047 #endif
14048 #if SQLITE_OMIT_BLOB_LITERAL
14049 "OMIT_BLOB_LITERAL",
14050 #endif
14051 #if SQLITE_OMIT_BTREECOUNT
14052 "OMIT_BTREECOUNT",
14053 #endif
14054 #if SQLITE_OMIT_BUILTIN_TEST
14055 "OMIT_BUILTIN_TEST",
14056 #endif
14057 #if SQLITE_OMIT_CAST
14058 "OMIT_CAST",
14059 #endif
14060 #if SQLITE_OMIT_CHECK
14061 "OMIT_CHECK",
14062 #endif
14063 #if SQLITE_OMIT_COMPLETE
14064 "OMIT_COMPLETE",
14065 #endif
14066 #if SQLITE_OMIT_COMPOUND_SELECT
14067 "OMIT_COMPOUND_SELECT",
14068 #endif
14069 #if SQLITE_OMIT_CTE
14070 "OMIT_CTE",
14071 #endif
14072 #if SQLITE_OMIT_DATETIME_FUNCS
14073 "OMIT_DATETIME_FUNCS",
14074 #endif
14075 #if SQLITE_OMIT_DECLTYPE
14076 "OMIT_DECLTYPE",
14077 #endif
14078 #if SQLITE_OMIT_DEPRECATED
14079 "OMIT_DEPRECATED",
14080 #endif
14081 #if SQLITE_OMIT_DISKIO
14082 "OMIT_DISKIO",
14083 #endif
14084 #if SQLITE_OMIT_EXPLAIN
14085 "OMIT_EXPLAIN",
14086 #endif
14087 #if SQLITE_OMIT_FLAG_PRAGMAS
14088 "OMIT_FLAG_PRAGMAS",
14089 #endif
14090 #if SQLITE_OMIT_FLOATING_POINT
14091 "OMIT_FLOATING_POINT",
14092 #endif
14093 #if SQLITE_OMIT_FOREIGN_KEY
14094 "OMIT_FOREIGN_KEY",
14095 #endif
14096 #if SQLITE_OMIT_GET_TABLE
14097 "OMIT_GET_TABLE",
14098 #endif
14099 #if SQLITE_OMIT_INCRBLOB
14100 "OMIT_INCRBLOB",
14101 #endif
14102 #if SQLITE_OMIT_INTEGRITY_CHECK
14103 "OMIT_INTEGRITY_CHECK",
14104 #endif
14105 #if SQLITE_OMIT_LIKE_OPTIMIZATION
14106 "OMIT_LIKE_OPTIMIZATION",
14107 #endif
14108 #if SQLITE_OMIT_LOAD_EXTENSION
14109 "OMIT_LOAD_EXTENSION",
14110 #endif
14111 #if SQLITE_OMIT_LOCALTIME
14112 "OMIT_LOCALTIME",
14113 #endif
14114 #if SQLITE_OMIT_LOOKASIDE
14115 "OMIT_LOOKASIDE",
14116 #endif
14117 #if SQLITE_OMIT_MEMORYDB
14118 "OMIT_MEMORYDB",
14119 #endif
14120 #if SQLITE_OMIT_OR_OPTIMIZATION
14121 "OMIT_OR_OPTIMIZATION",
14122 #endif
14123 #if SQLITE_OMIT_PAGER_PRAGMAS
14124 "OMIT_PAGER_PRAGMAS",
14125 #endif
14126 #if SQLITE_OMIT_PRAGMA
14127 "OMIT_PRAGMA",
14128 #endif
14129 #if SQLITE_OMIT_PROGRESS_CALLBACK
14130 "OMIT_PROGRESS_CALLBACK",
14131 #endif
14132 #if SQLITE_OMIT_QUICKBALANCE
14133 "OMIT_QUICKBALANCE",
14134 #endif
14135 #if SQLITE_OMIT_REINDEX
14136 "OMIT_REINDEX",
14137 #endif
14138 #if SQLITE_OMIT_SCHEMA_PRAGMAS
14139 "OMIT_SCHEMA_PRAGMAS",
14140 #endif
14141 #if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
14142 "OMIT_SCHEMA_VERSION_PRAGMAS",
14143 #endif
14144 #if SQLITE_OMIT_SHARED_CACHE
14145 "OMIT_SHARED_CACHE",
14146 #endif
14147 #if SQLITE_OMIT_SUBQUERY
14148 "OMIT_SUBQUERY",
14149 #endif
14150 #if SQLITE_OMIT_TCL_VARIABLE
14151 "OMIT_TCL_VARIABLE",
14152 #endif
14153 #if SQLITE_OMIT_TEMPDB
14154 "OMIT_TEMPDB",
14155 #endif
14156 #if SQLITE_OMIT_TRACE
14157 "OMIT_TRACE",
14158 #endif
14159 #if SQLITE_OMIT_TRIGGER
14160 "OMIT_TRIGGER",
14161 #endif
14162 #if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
14163 "OMIT_TRUNCATE_OPTIMIZATION",
14164 #endif
14165 #if SQLITE_OMIT_UTF16
14166 "OMIT_UTF16",
14167 #endif
14168 #if SQLITE_OMIT_VACUUM
14169 "OMIT_VACUUM",
14170 #endif
14171 #if SQLITE_OMIT_VIEW
14172 "OMIT_VIEW",
14173 #endif
14174 #if SQLITE_OMIT_VIRTUALTABLE
14175 "OMIT_VIRTUALTABLE",
14176 #endif
14177 #if SQLITE_OMIT_WAL
14178 "OMIT_WAL",
14179 #endif
14180 #if SQLITE_OMIT_WSD
14181 "OMIT_WSD",
14182 #endif
14183 #if SQLITE_OMIT_XFER_OPT
14184 "OMIT_XFER_OPT",
14185 #endif
14186 #if SQLITE_PERFORMANCE_TRACE
14187 "PERFORMANCE_TRACE",
14188 #endif
14189 #if SQLITE_PROXY_DEBUG
14190 "PROXY_DEBUG",
14191 #endif
14192 #if SQLITE_RTREE_INT_ONLY
14193 "RTREE_INT_ONLY",
14194 #endif
14195 #if SQLITE_SECURE_DELETE
14196 "SECURE_DELETE",
14197 #endif
14198 #if SQLITE_SMALL_STACK
14199 "SMALL_STACK",
14200 #endif
14201 #if SQLITE_SOUNDEX
14202 "SOUNDEX",
14203 #endif
14204 #if SQLITE_SYSTEM_MALLOC
14205 "SYSTEM_MALLOC",
14206 #endif
14207 #if SQLITE_TCL
14208 "TCL",
14209 #endif
14210 #if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
14211 "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
14212 #endif
14213 #if SQLITE_TEST
14214 "TEST",
14215 #endif
14216 #if defined(SQLITE_THREADSAFE)
14217 "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
14218 #endif
14219 #if SQLITE_USE_ALLOCA
14220 "USE_ALLOCA",
14221 #endif
14222 #if SQLITE_USER_AUTHENTICATION
14223 "USER_AUTHENTICATION",
14224 #endif
14225 #if SQLITE_WIN32_MALLOC
14226 "WIN32_MALLOC",
14227 #endif
14228 #if SQLITE_ZERO_MALLOC
14229 "ZERO_MALLOC"
14230 #endif
14231 };
14232
14233 /*
@@ -14156,11 +14238,11 @@
14238 ** is not required for a match.
14239 */
14240 SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
14241 int i, n;
14242
14243 #if SQLITE_ENABLE_API_ARMOR
14244 if( zOptName==0 ){
14245 (void)SQLITE_MISUSE_BKPT;
14246 return 0;
14247 }
14248 #endif
@@ -15384,12 +15466,13 @@
15466 **
15467 ** If the user has not indicated to use localtime_r() or localtime_s()
15468 ** already, check for an MSVC build environment that provides
15469 ** localtime_s().
15470 */
15471 #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
15472 && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
15473 #undef HAVE_LOCALTIME_S
15474 #define HAVE_LOCALTIME_S 1
15475 #endif
15476
15477 #ifndef SQLITE_OMIT_LOCALTIME
15478 /*
@@ -15405,12 +15488,11 @@
15488 ** library function localtime_r() is used to assist in the calculation of
15489 ** local time.
15490 */
15491 static int osLocaltime(time_t *t, struct tm *pTm){
15492 int rc;
15493 #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
 
15494 struct tm *pX;
15495 #if SQLITE_THREADSAFE>0
15496 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
15497 #endif
15498 sqlite3_mutex_enter(mutex);
@@ -15423,11 +15505,11 @@
15505 rc = pX==0;
15506 #else
15507 #ifndef SQLITE_OMIT_BUILTIN_TEST
15508 if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
15509 #endif
15510 #if HAVE_LOCALTIME_R
15511 rc = localtime_r(t, pTm)==0;
15512 #else
15513 rc = localtime_s(pTm, t);
15514 #endif /* HAVE_LOCALTIME_R */
15515 #endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
@@ -15867,12 +15949,14 @@
15949 DateTime x;
15950 u64 n;
15951 size_t i,j;
15952 char *z;
15953 sqlite3 *db;
15954 const char *zFmt;
15955 char zBuf[100];
15956 if( argc==0 ) return;
15957 zFmt = (const char*)sqlite3_value_text(argv[0]);
15958 if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
15959 db = sqlite3_context_db_handle(context);
15960 for(i=0, n=1; zFmt[i]; i++, n++){
15961 if( zFmt[i]=='%' ){
15962 switch( zFmt[i+1] ){
@@ -16062,11 +16146,11 @@
16146 UNUSED_PARAMETER(argv);
16147
16148 iT = sqlite3StmtCurrentTime(context);
16149 if( iT<=0 ) return;
16150 t = iT/1000 - 10000*(sqlite3_int64)21086676;
16151 #if HAVE_GMTIME_R
16152 pTm = gmtime_r(&t, &sNow);
16153 #else
16154 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
16155 pTm = gmtime(&t);
16156 if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
@@ -16736,13 +16820,13 @@
16820
16821 /*
16822 ** The malloc.h header file is needed for malloc_usable_size() function
16823 ** on some systems (e.g. Linux).
16824 */
16825 #if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE
16826 # define SQLITE_USE_MALLOC_H 1
16827 # define SQLITE_USE_MALLOC_USABLE_SIZE 1
16828 /*
16829 ** The MSVCRT has malloc_usable_size(), but it is called _msize(). The
16830 ** use of _msize() is automatic, but can be disabled by compiling with
16831 ** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires
16832 ** the malloc.h header file.
@@ -19976,10 +20060,16 @@
20060 #endif
20061 }
20062 break;
20063 }
20064 default: {
20065 #ifdef SQLITE_ENABLE_API_ARMOR
20066 if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){
20067 (void)SQLITE_MISUSE_BKPT;
20068 return 0;
20069 }
20070 #endif
20071 assert( iType-2 >= 0 );
20072 assert( iType-2 < ArraySize(winMutex_staticMutexes) );
20073 assert( winMutex_isInit==1 );
20074 p = &winMutex_staticMutexes[iType-2];
20075 #ifdef SQLITE_DEBUG
@@ -20971,21 +21061,10 @@
21061 ** This file contains code for a set of "printf"-like routines. These
21062 ** routines format strings much like the printf() from the standard C
21063 ** library, though the implementation here has enhancements to support
21064 ** SQLlite.
21065 */
 
 
 
 
 
 
 
 
 
 
 
21066
21067 /*
21068 ** Conversion types fall into various categories as defined by the
21069 ** following enumeration.
21070 */
@@ -22280,10 +22359,12 @@
22359 ** single threaded systems. Nothing in SQLite requires multiple threads.
22360 ** This interface exists so that applications that want to take advantage
22361 ** of multiple cores can do so, while also allowing applications to stay
22362 ** single-threaded if desired.
22363 */
22364 #if SQLITE_OS_WIN
22365 #endif
22366
22367 #if SQLITE_MAX_WORKER_THREADS>0
22368
22369 /********************************* Unix Pthreads ****************************/
22370 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
@@ -23066,11 +23147,11 @@
23147 ** This file contains functions for allocating memory, comparing
23148 ** strings, and stuff like that.
23149 **
23150 */
23151 /* #include <stdarg.h> */
23152 #if HAVE_ISNAN || SQLITE_HAVE_ISNAN
23153 # include <math.h>
23154 #endif
23155
23156 /*
23157 ** Routine needed to support the testcase() macro.
@@ -23107,11 +23188,11 @@
23188 ** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
23189 ** Otherwise, we have our own implementation that works on most systems.
23190 */
23191 SQLITE_PRIVATE int sqlite3IsNaN(double x){
23192 int rc; /* The value return */
23193 #if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
23194 /*
23195 ** Systems that support the isnan() library function should probably
23196 ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
23197 ** found that many systems do not have a working isnan() function so
23198 ** this implementation is provided as an alternative.
@@ -23137,13 +23218,13 @@
23218 # error SQLite will not work correctly with the -ffast-math option of GCC.
23219 #endif
23220 volatile double y = x;
23221 volatile double z = y;
23222 rc = (y!=z);
23223 #else /* if HAVE_ISNAN */
23224 rc = isnan(x);
23225 #endif /* HAVE_ISNAN */
23226 testcase( rc );
23227 return rc;
23228 }
23229 #endif /* SQLITE_OMIT_FLOATING_POINT */
23230
@@ -28460,13 +28541,13 @@
28541
28542 /*
28543 ** We do not trust systems to provide a working fdatasync(). Some do.
28544 ** Others do no. To be safe, we will stick with the (slightly slower)
28545 ** fsync(). If you know that your system does support fdatasync() correctly,
28546 ** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
28547 */
28548 #if !defined(fdatasync) && !HAVE_FDATASYNC
28549 # define fdatasync fsync
28550 #endif
28551
28552 /*
28553 ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
@@ -28783,28 +28864,32 @@
28864 do{
28865 err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
28866 }while( err==EINTR );
28867 if( err ) return SQLITE_IOERR_WRITE;
28868 #else
28869 /* If the OS does not have posix_fallocate(), fake it. Write a
28870 ** single byte to the last byte in each block that falls entirely
28871 ** within the extended region. Then, if required, a single byte
28872 ** at offset (nSize-1), to set the size of the file correctly.
28873 ** This is a similar technique to that used by glibc on systems
28874 ** that do not have a real fallocate() call.
28875 */
28876 int nBlk = buf.st_blksize; /* File-system block size */
28877 int nWrite = 0; /* Number of bytes written by seekAndWrite */
28878 i64 iWrite; /* Next offset to write to */
28879
 
 
 
 
28880 iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
28881 assert( iWrite>=buf.st_size );
28882 assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
28883 assert( ((iWrite+1)%nBlk)==0 );
28884 for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
28885 nWrite = seekAndWrite(pFile, iWrite, "", 1);
28886 if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
28887 }
28888 if( nWrite==0 || (nSize%nBlk) ){
28889 nWrite = seekAndWrite(pFile, nSize-1, "", 1);
28890 if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
28891 }
28892 #endif
28893 }
28894 }
28895
@@ -34018,12 +34103,12 @@
34103 */
34104 SQLITE_API int sqlite3_win32_reset_heap(){
34105 int rc;
34106 MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
34107 MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
34108 MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
34109 MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
34110 sqlite3_mutex_enter(pMaster);
34111 sqlite3_mutex_enter(pMem);
34112 winMemAssertMagic();
34113 if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
34114 /*
@@ -35294,11 +35379,11 @@
35379 sqlite3_file *id, /* File to read from */
35380 void *pBuf, /* Write content into this buffer */
35381 int amt, /* Number of bytes to read */
35382 sqlite3_int64 offset /* Begin reading at this offset */
35383 ){
35384 #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
35385 OVERLAPPED overlapped; /* The offset for ReadFile. */
35386 #endif
35387 winFile *pFile = (winFile*)id; /* file handle */
35388 DWORD nRead; /* Number of bytes actually read from file */
35389 int nRetry = 0; /* Number of retrys */
@@ -35326,11 +35411,11 @@
35411 offset += nCopy;
35412 }
35413 }
35414 #endif
35415
35416 #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
35417 if( winSeekFile(pFile, offset) ){
35418 OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
35419 return SQLITE_FULL;
35420 }
35421 while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -35398,32 +35483,32 @@
35483 offset += nCopy;
35484 }
35485 }
35486 #endif
35487
35488 #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
35489 rc = winSeekFile(pFile, offset);
35490 if( rc==0 ){
35491 #else
35492 {
35493 #endif
35494 #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
35495 OVERLAPPED overlapped; /* The offset for WriteFile. */
35496 #endif
35497 u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
35498 int nRem = amt; /* Number of bytes yet to be written */
35499 DWORD nWrite; /* Bytes written by each WriteFile() call */
35500 DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
35501
35502 #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
35503 memset(&overlapped, 0, sizeof(OVERLAPPED));
35504 overlapped.Offset = (LONG)(offset & 0xffffffff);
35505 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
35506 #endif
35507
35508 while( nRem>0 ){
35509 #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
35510 if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
35511 #else
35512 if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
35513 #endif
35514 if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
@@ -35432,11 +35517,11 @@
35517 assert( nWrite==0 || nWrite<=(DWORD)nRem );
35518 if( nWrite==0 || nWrite>(DWORD)nRem ){
35519 lastErrno = osGetLastError();
35520 break;
35521 }
35522 #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
35523 offset += nWrite;
35524 overlapped.Offset = (LONG)(offset & 0xffffffff);
35525 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
35526 #endif
35527 aRem += nWrite;
@@ -38813,22 +38898,10 @@
38898 void *pStress; /* Argument to xStress */
38899 sqlite3_pcache *pCache; /* Pluggable cache module */
38900 PgHdr *pPage1; /* Reference to page 1 */
38901 };
38902
 
 
 
 
 
 
 
 
 
 
 
 
38903 /********************************** Linked List Management ********************/
38904
38905 /* Allowed values for second argument to pcacheManageDirtyList() */
38906 #define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
38907 #define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
@@ -38978,11 +39051,12 @@
39051 SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
39052 assert( pCache->nRef==0 && pCache->pDirty==0 );
39053 if( pCache->szPage ){
39054 sqlite3_pcache *pNew;
39055 pNew = sqlite3GlobalConfig.pcache2.xCreate(
39056 szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
39057 pCache->bPurgeable
39058 );
39059 if( pNew==0 ) return SQLITE_NOMEM;
39060 sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
39061 if( pCache->pCache ){
39062 sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
@@ -39437,11 +39511,11 @@
39511
39512 /*
39513 ** Return the size of the header added by this middleware layer
39514 ** in the page-cache hierarchy.
39515 */
39516 SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
39517
39518
39519 #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
39520 /*
39521 ** For all dirty pages currently in the cache, invoke the specified
@@ -39753,11 +39827,11 @@
39827 pcache1Free(pPg);
39828 sqlite3_free(p);
39829 pPg = 0;
39830 }
39831 #else
39832 pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
39833 p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
39834 #endif
39835 pcache1EnterMutex(pCache->pGroup);
39836
39837 if( pPg ){
@@ -40441,11 +40515,11 @@
40515 }
40516
40517 /*
40518 ** Return the size of the header on each page of this PCACHE implementation.
40519 */
40520 SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
40521
40522 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
40523 /*
40524 ** This function is called to free superfluous dynamically allocated memory
40525 ** held by the pager system. Memory in use by any SQLite pager allocated
@@ -41799,10 +41873,12 @@
41873 u8 eLock; /* Current lock held on database file */
41874 u8 changeCountDone; /* Set after incrementing the change-counter */
41875 u8 setMaster; /* True if a m-j name has been written to jrnl */
41876 u8 doNotSpill; /* Do not spill the cache when non-zero */
41877 u8 subjInMemory; /* True to use in-memory sub-journals */
41878 u8 bUseFetch; /* True to use xFetch() */
41879 u8 hasBeenUsed; /* True if any content previously read from this pager*/
41880 Pgno dbSize; /* Number of pages in the database */
41881 Pgno dbOrigSize; /* dbSize before the current transaction */
41882 Pgno dbFileSize; /* Number of pages in the database file */
41883 Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */
41884 int errCode; /* One of several kinds of errors */
@@ -41816,13 +41892,13 @@
41892 i64 journalOff; /* Current write offset in the journal file */
41893 i64 journalHdr; /* Byte offset to previous journal header */
41894 sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
41895 PagerSavepoint *aSavepoint; /* Array of active savepoints */
41896 int nSavepoint; /* Number of elements in aSavepoint[] */
41897 u32 iDataVersion; /* Changes whenever database content changes */
41898 char dbFileVers[16]; /* Changes whenever database file changes */
41899
 
41900 int nMmapOut; /* Number of mmap pages currently outstanding */
41901 sqlite3_int64 szMmap; /* Desired maximum mmap size */
41902 PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
41903 /*
41904 ** End of the routinely-changing class members
@@ -42834,13 +42910,22 @@
42910
42911 /*
42912 ** Discard the entire contents of the in-memory page-cache.
42913 */
42914 static void pager_reset(Pager *pPager){
42915 pPager->iDataVersion++;
42916 sqlite3BackupRestart(pPager->pBackup);
42917 sqlite3PcacheClear(pPager->pPCache);
42918 }
42919
42920 /*
42921 ** Return the pPager->iDataVersion value
42922 */
42923 SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
42924 assert( pPager->eState>PAGER_OPEN );
42925 return pPager->iDataVersion;
42926 }
42927
42928 /*
42929 ** Free all structures in the Pager.aSavepoint[] array and set both
42930 ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
42931 ** if it is open and the pager is not in exclusive mode.
@@ -45040,11 +45125,11 @@
45125 Pgno pgno, /* Page number */
45126 void *pData, /* xFetch()'d data for this page */
45127 PgHdr **ppPage /* OUT: Acquired page object */
45128 ){
45129 PgHdr *p; /* Memory mapped page to return */
45130
45131 if( pPager->pMmapFreelist ){
45132 *ppPage = p = pPager->pMmapFreelist;
45133 pPager->pMmapFreelist = p->pDirty;
45134 p->pDirty = 0;
45135 memset(p->pExtra, 0, pPager->nExtra);
@@ -46271,20 +46356,16 @@
46356 assert( (pPager->eLock==SHARED_LOCK)
46357 || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
46358 );
46359 }
46360
46361 if( !pPager->tempFile && pPager->hasBeenUsed ){
46362 /* The shared-lock has just been acquired then check to
46363 ** see if the database has been modified. If the database has changed,
46364 ** flush the cache. The pPager->hasBeenUsed flag prevents this from
46365 ** occurring on the very first access to a file, in order to save a
46366 ** single unnecessary sqlite3OsRead() call at the start-up.
 
 
 
 
46367 **
46368 ** Database changes is detected by looking at 15 bytes beginning
46369 ** at offset 24 into the file. The first 4 of these 16 bytes are
46370 ** a 32-bit counter that is incremented with each change. The
46371 ** other bytes change randomly with each file change when
@@ -46445,10 +46526,11 @@
46526 assert( noContent==0 || bMmapOk==0 );
46527
46528 if( pgno==0 ){
46529 return SQLITE_CORRUPT_BKPT;
46530 }
46531 pPager->hasBeenUsed = 1;
46532
46533 /* If the pager is in the error state, return an error immediately.
46534 ** Otherwise, request the page from the PCache layer. */
46535 if( pPager->errCode!=SQLITE_OK ){
46536 rc = pPager->errCode;
@@ -46594,10 +46676,11 @@
46676 sqlite3_pcache_page *pPage;
46677 assert( pPager!=0 );
46678 assert( pgno!=0 );
46679 assert( pPager->pPCache!=0 );
46680 pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
46681 assert( pPage==0 || pPager->hasBeenUsed );
46682 return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
46683 }
46684
46685 /*
46686 ** Release a page reference.
@@ -47460,10 +47543,11 @@
47543 pPager->eState = PAGER_READER;
47544 return SQLITE_OK;
47545 }
47546
47547 PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
47548 pPager->iDataVersion++;
47549 rc = pager_end_transaction(pPager, pPager->setMaster, 1);
47550 return pager_error(pPager, rc);
47551 }
47552
47553 /*
@@ -50111,11 +50195,11 @@
50195 int (*xBusy)(void*), /* Function to call when busy */
50196 void *pBusyArg, /* Context argument for xBusyHandler */
50197 int sync_flags, /* Flags for OsSync() (or 0) */
50198 u8 *zBuf /* Temporary buffer to use */
50199 ){
50200 int rc = SQLITE_OK; /* Return code */
50201 int szPage; /* Database page-size */
50202 WalIterator *pIter = 0; /* Wal iterator context */
50203 u32 iDbpage = 0; /* Next database page to write */
50204 u32 iFrame = 0; /* Wal frame containing data for iDbpage */
50205 u32 mxSafeFrame; /* Max frame that can be backfilled */
@@ -50125,108 +50209,111 @@
50209
50210 szPage = walPagesize(pWal);
50211 testcase( szPage<=32768 );
50212 testcase( szPage>=65536 );
50213 pInfo = walCkptInfo(pWal);
50214 if( pInfo->nBackfill<pWal->hdr.mxFrame ){
50215
50216 /* Allocate the iterator */
50217 rc = walIteratorInit(pWal, &pIter);
50218 if( rc!=SQLITE_OK ){
50219 return rc;
50220 }
50221 assert( pIter );
50222
50223 /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
50224 ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
50225 assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
50226
50227 /* Compute in mxSafeFrame the index of the last frame of the WAL that is
50228 ** safe to write into the database. Frames beyond mxSafeFrame might
50229 ** overwrite database pages that are in use by active readers and thus
50230 ** cannot be backfilled from the WAL.
50231 */
50232 mxSafeFrame = pWal->hdr.mxFrame;
50233 mxPage = pWal->hdr.nPage;
50234 for(i=1; i<WAL_NREADER; i++){
50235 u32 y = pInfo->aReadMark[i];
50236 if( mxSafeFrame>y ){
50237 assert( y<=pWal->hdr.mxFrame );
50238 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
50239 if( rc==SQLITE_OK ){
50240 pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
50241 walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
50242 }else if( rc==SQLITE_BUSY ){
50243 mxSafeFrame = y;
50244 xBusy = 0;
50245 }else{
50246 goto walcheckpoint_out;
50247 }
50248 }
50249 }
50250
50251 if( pInfo->nBackfill<mxSafeFrame
50252 && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
50253 ){
50254 i64 nSize; /* Current size of database file */
50255 u32 nBackfill = pInfo->nBackfill;
50256
50257 /* Sync the WAL to disk */
50258 if( sync_flags ){
50259 rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
50260 }
50261
50262 /* If the database may grow as a result of this checkpoint, hint
50263 ** about the eventual size of the db file to the VFS layer.
50264 */
50265 if( rc==SQLITE_OK ){
50266 i64 nReq = ((i64)mxPage * szPage);
50267 rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
50268 if( rc==SQLITE_OK && nSize<nReq ){
50269 sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
50270 }
50271 }
50272
50273
50274 /* Iterate through the contents of the WAL, copying data to the db file */
50275 while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
50276 i64 iOffset;
50277 assert( walFramePgno(pWal, iFrame)==iDbpage );
50278 if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
50279 continue;
50280 }
50281 iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
50282 /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
50283 rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
50284 if( rc!=SQLITE_OK ) break;
50285 iOffset = (iDbpage-1)*(i64)szPage;
50286 testcase( IS_BIG_INT(iOffset) );
50287 rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
50288 if( rc!=SQLITE_OK ) break;
50289 }
50290
50291 /* If work was actually accomplished... */
50292 if( rc==SQLITE_OK ){
50293 if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
50294 i64 szDb = pWal->hdr.nPage*(i64)szPage;
50295 testcase( IS_BIG_INT(szDb) );
50296 rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
50297 if( rc==SQLITE_OK && sync_flags ){
50298 rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
50299 }
50300 }
50301 if( rc==SQLITE_OK ){
50302 pInfo->nBackfill = mxSafeFrame;
50303 }
50304 }
50305
50306 /* Release the reader lock held while backfilling */
50307 walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
50308 }
50309
50310 if( rc==SQLITE_BUSY ){
50311 /* Reset the return code so as not to report a checkpoint failure
50312 ** just because there are active readers. */
50313 rc = SQLITE_OK;
50314 }
50315 }
50316
50317 /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
50318 ** entire wal file has been copied into the database file, then block
50319 ** until all readers have finished using the wal file. This ensures that
@@ -50237,11 +50324,11 @@
50324 if( pInfo->nBackfill<pWal->hdr.mxFrame ){
50325 rc = SQLITE_BUSY;
50326 }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
50327 u32 salt1;
50328 sqlite3_randomness(4, &salt1);
50329 assert( pInfo->nBackfill==pWal->hdr.mxFrame );
50330 rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
50331 if( rc==SQLITE_OK ){
50332 if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
50333 /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
50334 ** SQLITE_CHECKPOINT_RESTART with the addition that it also
@@ -50829,11 +50916,11 @@
50916 }
50917 nCollide = HASHTABLE_NSLOT;
50918 for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
50919 u32 iFrame = aHash[iKey] + iZero;
50920 if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
50921 assert( iFrame>iRead || CORRUPT_DB );
50922 iRead = iFrame;
50923 }
50924 if( (nCollide--)==0 ){
50925 return SQLITE_CORRUPT_BKPT;
50926 }
@@ -51935,10 +52022,11 @@
52022 u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
52023 u8 sharable; /* True if we can share pBt with another db */
52024 u8 locked; /* True if db currently has pBt locked */
52025 int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
52026 int nBackup; /* Number of backup operations reading this btree */
52027 u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
52028 Btree *pNext; /* List of other sharable Btrees from the same db */
52029 Btree *pPrev; /* Back pointer of the same list */
52030 #ifndef SQLITE_OMIT_SHARED_CACHE
52031 BtLock lock; /* Object used to lock page 1 */
52032 #endif
@@ -56098,10 +56186,11 @@
56186 rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
56187 if( rc!=SQLITE_OK && bCleanup==0 ){
56188 sqlite3BtreeLeave(p);
56189 return rc;
56190 }
56191 p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
56192 pBt->inTransaction = TRANS_READ;
56193 btreeClearHasContent(pBt);
56194 }
56195
56196 btreeEndTransaction(p);
@@ -56461,11 +56550,11 @@
56550 }
56551 for(i=0; i<=pCur->iPage; i++){
56552 releasePage(pCur->apPage[i]);
56553 }
56554 unlockBtreeIfUnused(pBt);
56555 sqlite3_free(pCur->aOverflow);
56556 /* sqlite3_free(pCur); */
56557 sqlite3BtreeLeave(pBtree);
56558 }
56559 return SQLITE_OK;
56560 }
@@ -56755,10 +56844,11 @@
56844 pBuf += a;
56845 amt -= a;
56846 }else{
56847 offset -= pCur->info.nLocal;
56848 }
56849
56850
56851 if( rc==SQLITE_OK && amt>0 ){
56852 const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
56853 Pgno nextPage;
56854
@@ -56773,12 +56863,12 @@
56863 ** means "not yet known" (the cache is lazily populated).
56864 */
56865 if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
56866 int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
56867 if( nOvfl>pCur->nOvflAlloc ){
56868 Pgno *aNew = (Pgno*)sqlite3Realloc(
56869 pCur->aOverflow, nOvfl*2*sizeof(Pgno)
56870 );
56871 if( aNew==0 ){
56872 rc = SQLITE_NOMEM;
56873 }else{
56874 pCur->nOvflAlloc = nOvfl*2;
@@ -56821,10 +56911,11 @@
56911 ** Note that the aOverflow[] array must be allocated because eOp!=2
56912 ** here. If eOp==2, then offset==0 and this branch is never taken.
56913 */
56914 assert( eOp!=2 );
56915 assert( pCur->curFlags & BTCF_ValidOvfl );
56916 assert( pCur->pBtree->db==pBt->db );
56917 if( pCur->aOverflow[iIdx+1] ){
56918 nextPage = pCur->aOverflow[iIdx+1];
56919 }else{
56920 rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
56921 }
@@ -59410,12 +59501,12 @@
59501 assert( leafCorrection==4 );
59502 if( szCell[nCell]<4 ){
59503 /* Do not allow any cells smaller than 4 bytes. If a smaller cell
59504 ** does exist, pad it with 0x00 bytes. */
59505 assert( szCell[nCell]==3 );
59506 assert( apCell[nCell]==&aSpace1[iSpace1-3] );
59507 aSpace1[iSpace1++] = 0x00;
59508 szCell[nCell] = 4;
59509 }
59510 }
59511 nCell++;
59512 }
@@ -60723,10 +60814,17 @@
60814 ** is read-only, the others are read/write.
60815 **
60816 ** The schema layer numbers meta values differently. At the schema
60817 ** layer (and the SetCookie and ReadCookie opcodes) the number of
60818 ** free pages is not visible. So Cookie[0] is the same as Meta[1].
60819 **
60820 ** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead
60821 ** of reading the value out of the header, it instead loads the "DataVersion"
60822 ** from the pager. The BTREE_DATA_VERSION value is not actually stored in the
60823 ** database file. It is a number computed by the pager. But its access
60824 ** pattern is the same as header meta values, and so it is convenient to
60825 ** read it from this routine.
60826 */
60827 SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
60828 BtShared *pBt = p->pBt;
60829
60830 sqlite3BtreeEnter(p);
@@ -60733,11 +60831,15 @@
60831 assert( p->inTrans>TRANS_NONE );
60832 assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
60833 assert( pBt->pPage1 );
60834 assert( idx>=0 && idx<=15 );
60835
60836 if( idx==BTREE_DATA_VERSION ){
60837 *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
60838 }else{
60839 *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
60840 }
60841
60842 /* If auto-vacuum is disabled in this build and this is an auto-vacuum
60843 ** database, mark the database as read-only. */
60844 #ifdef SQLITE_OMIT_AUTOVACUUM
60845 if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){
@@ -60824,11 +60926,11 @@
60926 if( pPage->leaf ){
60927 do {
60928 if( pCur->iPage==0 ){
60929 /* All pages of the b-tree have been visited. Return successfully. */
60930 *pnEntry = nEntry;
60931 return moveToRoot(pCur);
60932 }
60933 moveToParent(pCur);
60934 }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
60935
60936 pCur->aiIdx[pCur->iPage]++;
@@ -61680,11 +61782,11 @@
61782 }
61783
61784 /*
61785 ** Return the size of the header added to each page by this module.
61786 */
61787 SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
61788
61789 /************** End of btree.c ***********************************************/
61790 /************** Begin file backup.c ******************************************/
61791 /*
61792 ** 2009 January 28
@@ -64444,36 +64546,39 @@
64546 **
64547 ** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) );
64548 */
64549 SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
64550 int hasAbort = 0;
64551 int hasFkCounter = 0;
64552 Op *pOp;
64553 VdbeOpIter sIter;
64554 memset(&sIter, 0, sizeof(sIter));
64555 sIter.v = v;
64556
64557 while( (pOp = opIterNext(&sIter))!=0 ){
64558 int opcode = pOp->opcode;
64559 if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
 
 
 
64560 || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
64561 && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
64562 ){
64563 hasAbort = 1;
64564 break;
64565 }
64566 #ifndef SQLITE_OMIT_FOREIGN_KEY
64567 if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
64568 hasFkCounter = 1;
64569 }
64570 #endif
64571 }
64572 sqlite3DbFree(v->db, sIter.apSub);
64573
64574 /* Return true if hasAbort==mayAbort. Or if a malloc failure occurred.
64575 ** If malloc failed, then the while() loop above may not have iterated
64576 ** through all opcodes and hasAbort may be set incorrectly. Return
64577 ** true for this case to prevent the assert() in the callers frame
64578 ** from failing. */
64579 return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
64580 }
64581 #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
64582
64583 /*
64584 ** Loop through the program looking for P2 values that are negative
@@ -67394,10 +67499,45 @@
67499 if( pKeyInfo->db->mallocFailed ) return 1;
67500 return 0;
67501 }
67502 #endif
67503
67504 #if SQLITE_DEBUG
67505 /*
67506 ** Count the number of fields (a.k.a. columns) in the record given by
67507 ** pKey,nKey. The verify that this count is less than or equal to the
67508 ** limit given by pKeyInfo->nField + pKeyInfo->nXField.
67509 **
67510 ** If this constraint is not satisfied, it means that the high-speed
67511 ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
67512 ** not work correctly. If this assert() ever fires, it probably means
67513 ** that the KeyInfo.nField or KeyInfo.nXField values were computed
67514 ** incorrectly.
67515 */
67516 static void vdbeAssertFieldCountWithinLimits(
67517 int nKey, const void *pKey, /* The record to verify */
67518 const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
67519 ){
67520 int nField = 0;
67521 u32 szHdr;
67522 u32 idx;
67523 u32 notUsed;
67524 const unsigned char *aKey = (const unsigned char*)pKey;
67525
67526 if( CORRUPT_DB ) return;
67527 idx = getVarint32(aKey, szHdr);
67528 assert( szHdr<=nKey );
67529 while( idx<szHdr ){
67530 idx += getVarint32(aKey+idx, notUsed);
67531 nField++;
67532 }
67533 assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
67534 }
67535 #else
67536 # define vdbeAssertFieldCountWithinLimits(A,B,C)
67537 #endif
67538
67539 /*
67540 ** Both *pMem1 and *pMem2 contain string values. Compare the two values
67541 ** using the collation sequence pColl. As usual, return a negative , zero
67542 ** or positive value if *pMem1 is less than, equal to or greater than
67543 ** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
@@ -67805,10 +67945,11 @@
67945 u32 y;
67946 u64 x;
67947 i64 v = pPKey2->aMem[0].u.i;
67948 i64 lhs;
67949
67950 vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
67951 assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
67952 switch( serial_type ){
67953 case 1: { /* 1-byte signed integer */
67954 lhs = ONE_BYTE_INT(aKey);
67955 testcase( lhs<0 );
@@ -67892,10 +68033,11 @@
68033 ){
68034 const u8 *aKey1 = (const u8*)pKey1;
68035 int serial_type;
68036 int res;
68037
68038 vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
68039 getVarint32(&aKey1[1], serial_type);
68040 if( serial_type<12 ){
68041 res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
68042 }else if( !(serial_type & 0x01) ){
68043 res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
@@ -68593,11 +68735,14 @@
68735 #ifndef SQLITE_OMIT_WAL
68736 int i;
68737 for(i=0; i<db->nDb; i++){
68738 Btree *pBt = db->aDb[i].pBt;
68739 if( pBt ){
68740 int nEntry;
68741 sqlite3BtreeEnter(pBt);
68742 nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
68743 sqlite3BtreeLeave(pBt);
68744 if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
68745 rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
68746 }
68747 }
68748 }
@@ -68773,11 +68918,10 @@
68918 ** program counter to 0 to ensure that when the statement is
68919 ** finalized or reset the parser error message is available via
68920 ** sqlite3_errmsg() and sqlite3_errcode().
68921 */
68922 const char *zErr = (const char *)sqlite3_value_text(db->pErr);
 
68923 sqlite3DbFree(db, v->zErrMsg);
68924 if( !db->mallocFailed ){
68925 v->zErrMsg = sqlite3DbStrDup(db, zErr);
68926 v->rc = rc2;
68927 } else {
@@ -73838,12 +73982,12 @@
73982 pIdxKey->default_rc = 0;
73983 if( pOp->opcode==OP_NoConflict ){
73984 /* For the OP_NoConflict opcode, take the jump if any of the
73985 ** input fields are NULL, since any key with a NULL will not
73986 ** conflict */
73987 for(ii=0; ii<pIdxKey->nField; ii++){
73988 if( pIdxKey->aMem[ii].flags & MEM_Null ){
73989 pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
73990 break;
73991 }
73992 }
73993 }
@@ -77135,11 +77279,11 @@
77279 /*
77280 ** Hard-coded maximum amount of data to accumulate in memory before flushing
77281 ** to a level 0 PMA. The purpose of this limit is to prevent various integer
77282 ** overflows. 512MiB.
77283 */
77284 #define SQLITE_MAX_PMASZ (1<<29)
77285
77286 /*
77287 ** Private objects used by the sorter
77288 */
77289 typedef struct MergeEngine MergeEngine; /* Merge PMAs together */
@@ -77431,15 +77575,10 @@
77575 **
77576 ** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; }
77577 */
77578 #define SRVAL(p) ((void*)((SorterRecord*)(p) + 1))
77579
 
 
 
 
 
77580
77581 /* Maximum number of PMAs that a single MergeEngine can merge */
77582 #define SORTER_MAX_MERGE_COUNT 16
77583
77584 static int vdbeIncrSwap(IncrMerger*);
@@ -77834,14 +77973,15 @@
77973 SortSubtask *pTask = &pSorter->aTask[i];
77974 pTask->pSorter = pSorter;
77975 }
77976
77977 if( !sqlite3TempInMemory(db) ){
77978 u32 szPma = sqlite3GlobalConfig.szPma;
77979 pSorter->mnPmaSize = szPma * pgsz;
77980 mxCache = db->aDb[0].pSchema->cache_size;
77981 if( mxCache<(int)szPma ) mxCache = (int)szPma;
77982 pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
77983
77984 /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
77985 ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
77986 ** large heap allocations.
77987 */
@@ -78115,16 +78255,16 @@
78255 ** Whether or not the file does end up memory mapped of course depends on
78256 ** the specific VFS implementation.
78257 */
78258 static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
78259 if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
78260 void *p = 0;
78261 int chunksize = 4*1024;
78262 sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
78263 sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
78264 sqlite3OsFetch(pFd, 0, (int)nByte, &p);
78265 sqlite3OsUnfetch(pFd, 0, p);
78266 }
78267 }
78268 #else
78269 # define vdbeSorterExtendFile(x,y,z)
78270 #endif
@@ -79401,10 +79541,11 @@
79541 rc = vdbePmaReaderNext(pSorter->pReader);
79542 *pbEof = (pSorter->pReader->pFd==0);
79543 }else
79544 #endif
79545 /*if( !pSorter->bUseThreads )*/ {
79546 assert( pSorter->pMerger!=0 );
79547 assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
79548 rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
79549 }
79550 }else{
79551 SorterRecord *pFree = pSorter->list.pList;
@@ -82167,11 +82308,11 @@
82308 Expr *pLeft, /* Left operand */
82309 Expr *pRight, /* Right operand */
82310 const Token *pToken /* Argument token */
82311 ){
82312 Expr *p;
82313 if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
82314 /* Take advantage of short-circuit false optimization for AND */
82315 p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
82316 }else{
82317 p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
82318 sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
@@ -85721,14 +85862,15 @@
85862 ** NEVER() will need to be removed. */
85863 if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){
85864 int i;
85865 struct SrcCount *p = pWalker->u.pSrcCount;
85866 SrcList *pSrc = p->pSrc;
85867 int nSrc = pSrc ? pSrc->nSrc : 0;
85868 for(i=0; i<nSrc; i++){
85869 if( pExpr->iTable==pSrc->a[i].iCursor ) break;
85870 }
85871 if( i<nSrc ){
85872 p->nThis++;
85873 }else{
85874 p->nOther++;
85875 }
85876 }
@@ -87302,11 +87444,11 @@
87444
87445 p->iGet = -1;
87446 p->mxSample = mxSample;
87447 p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
87448 p->current.anLt = &p->current.anEq[nColUp];
87449 p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
87450
87451 /* Set up the Stat4Accum.a[] and aBest[] arrays */
87452 p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
87453 p->aBest = &p->a[mxSample];
87454 pSpace = (u8*)(&p->a[mxSample+nCol]);
@@ -88895,17 +89037,19 @@
89037 }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
89038 zErrDyn = sqlite3MPrintf(db,
89039 "attached databases must use the same text encoding as main database");
89040 rc = SQLITE_ERROR;
89041 }
89042 sqlite3BtreeEnter(aNew->pBt);
89043 pPager = sqlite3BtreePager(aNew->pBt);
89044 sqlite3PagerLockingMode(pPager, db->dfltLockMode);
89045 sqlite3BtreeSecureDelete(aNew->pBt,
89046 sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
89047 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
89048 sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
89049 #endif
89050 sqlite3BtreeLeave(aNew->pBt);
89051 }
89052 aNew->safety_level = 3;
89053 aNew->zName = sqlite3DbStrDup(db, zName);
89054 if( rc==SQLITE_OK && aNew->zName==0 ){
89055 rc = SQLITE_NOMEM;
@@ -90027,11 +90171,10 @@
90171 */
90172 static void freeIndex(sqlite3 *db, Index *p){
90173 #ifndef SQLITE_OMIT_ANALYZE
90174 sqlite3DeleteIndexSamples(db, p);
90175 #endif
 
90176 sqlite3ExprDelete(db, p->pPartIdxWhere);
90177 sqlite3DbFree(db, p->zColAff);
90178 if( p->isResized ) sqlite3DbFree(db, p->azColl);
90179 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
90180 sqlite3_free(p->aiRowEst);
@@ -91306,10 +91449,23 @@
91449 if( pPk==0 ) return;
91450 pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
91451 pTab->iPKey = -1;
91452 }else{
91453 pPk = sqlite3PrimaryKeyIndex(pTab);
91454 /*
91455 ** Remove all redundant columns from the PRIMARY KEY. For example, change
91456 ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
91457 ** code assumes the PRIMARY KEY contains no repeated columns.
91458 */
91459 for(i=j=1; i<pPk->nKeyCol; i++){
91460 if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
91461 pPk->nColumn--;
91462 }else{
91463 pPk->aiColumn[j++] = pPk->aiColumn[i];
91464 }
91465 }
91466 pPk->nKeyCol = j;
91467 }
91468 pPk->isCovering = 1;
91469 assert( pPk!=0 );
91470 nPk = pPk->nKeyCol;
91471
@@ -93782,44 +93938,35 @@
93938 **
93939 ** The caller should invoke sqlite3KeyInfoUnref() on the returned object
93940 ** when it has finished using it.
93941 */
93942 SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
93943 int i;
93944 int nCol = pIdx->nColumn;
93945 int nKey = pIdx->nKeyCol;
93946 KeyInfo *pKey;
93947 if( pParse->nErr ) return 0;
93948 if( pIdx->uniqNotNull ){
93949 pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
93950 }else{
93951 pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
93952 }
93953 if( pKey ){
93954 assert( sqlite3KeyInfoIsWriteable(pKey) );
93955 for(i=0; i<nCol; i++){
93956 char *zColl = pIdx->azColl[i];
93957 assert( zColl!=0 );
93958 pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
93959 sqlite3LocateCollSeq(pParse, zColl);
93960 pKey->aSortOrder[i] = pIdx->aSortOrder[i];
93961 }
93962 if( pParse->nErr ){
93963 sqlite3KeyInfoUnref(pKey);
93964 pKey = 0;
93965 }
93966 }
93967 return pKey;
 
 
 
 
 
 
 
 
 
 
 
 
 
93968 }
93969
93970 #ifndef SQLITE_OMIT_CTE
93971 /*
93972 ** This routine is invoked once per CTE by the parser while parsing a
@@ -94596,12 +94743,12 @@
94743 const char *zDb; /* Name of database holding pTab */
94744 int i; /* Loop counter */
94745 WhereInfo *pWInfo; /* Information about the WHERE clause */
94746 Index *pIdx; /* For looping over indices of the table */
94747 int iTabCur; /* Cursor number for the table */
94748 int iDataCur = 0; /* VDBE cursor for the canonical data source */
94749 int iIdxCur = 0; /* Cursor number of the first index */
94750 int nIdx; /* Number of indices */
94751 sqlite3 *db; /* Main database structure */
94752 AuthContext sContext; /* Authorization context */
94753 NameContext sNC; /* Name context to resolve expressions in */
94754 int iDb; /* Database number */
@@ -97436,11 +97583,11 @@
97583 assert( nIncr==1 );
97584 sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
97585 OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
97586 }else{
97587 if( nIncr>0 && pFKey->isDeferred==0 ){
97588 sqlite3MayAbort(pParse);
97589 }
97590 sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
97591 }
97592
97593 sqlite3VdbeResolveLabel(v, iOk);
@@ -97507,10 +97654,14 @@
97654 ** This function is called to generate code executed when a row is deleted
97655 ** from the parent table of foreign key constraint pFKey and, if pFKey is
97656 ** deferred, when a row is inserted into the same table. When generating
97657 ** code for an SQL UPDATE operation, this function may be called twice -
97658 ** once to "delete" the old row and once to "insert" the new row.
97659 **
97660 ** Parameter nIncr is passed -1 when inserting a row (as this may decrease
97661 ** the number of FK violations in the db) or +1 when deleting one (as this
97662 ** may increase the number of FK constraint problems).
97663 **
97664 ** The code generated by this function scans through the rows in the child
97665 ** table that correspond to the parent table row being deleted or inserted.
97666 ** For each child row found, one of the following actions is taken:
97667 **
@@ -97624,17 +97775,13 @@
97775 sNameContext.pSrcList = pSrc;
97776 sNameContext.pParse = pParse;
97777 sqlite3ResolveExprNames(&sNameContext, pWhere);
97778
97779 /* Create VDBE to loop through the entries in pSrc that match the WHERE
97780 ** clause. For each row found, increment either the deferred or immediate
97781 ** foreign key constraint counter. */
 
97782 pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
 
 
 
97783 sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
97784 if( pWInfo ){
97785 sqlite3WhereEnd(pWInfo);
97786 }
97787
@@ -97808,10 +97955,28 @@
97955 }
97956 }
97957 }
97958 return 0;
97959 }
97960
97961 /*
97962 ** Return true if the parser passed as the first argument is being
97963 ** used to code a trigger that is really a "SET NULL" action belonging
97964 ** to trigger pFKey.
97965 */
97966 static int isSetNullAction(Parse *pParse, FKey *pFKey){
97967 Parse *pTop = sqlite3ParseToplevel(pParse);
97968 if( pTop->pTriggerPrg ){
97969 Trigger *p = pTop->pTriggerPrg->pTrigger;
97970 if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
97971 || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
97972 ){
97973 return 1;
97974 }
97975 }
97976 return 0;
97977 }
97978
97979 /*
97980 ** This function is called when inserting, deleting or updating a row of
97981 ** table pTab to generate VDBE code to perform foreign key constraint
97982 ** processing for the operation.
@@ -97861,11 +98026,11 @@
98026 Index *pIdx = 0; /* Index on key columns in pTo */
98027 int *aiFree = 0;
98028 int *aiCol;
98029 int iCol;
98030 int i;
98031 int bIgnore = 0;
98032
98033 if( aChange
98034 && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
98035 && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
98036 ){
@@ -97920,11 +98085,11 @@
98085 ** values read from the parent table are NULL. */
98086 if( db->xAuth ){
98087 int rcauth;
98088 char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
98089 rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
98090 bIgnore = (rcauth==SQLITE_IGNORE);
98091 }
98092 #endif
98093 }
98094
98095 /* Take a shared-cache advisory read-lock on the parent table. Allocate
@@ -97935,16 +98100,22 @@
98100
98101 if( regOld!=0 ){
98102 /* A row is being removed from the child table. Search for the parent.
98103 ** If the parent does not exist, removing the child row resolves an
98104 ** outstanding foreign key constraint violation. */
98105 fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
98106 }
98107 if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
98108 /* A row is being added to the child table. If a parent row cannot
98109 ** be found, adding the child row has violated the FK constraint.
98110 **
98111 ** If this operation is being performed as part of a trigger program
98112 ** that is actually a "SET NULL" action belonging to this very
98113 ** foreign key, then omit this scan altogether. As all child key
98114 ** values are guaranteed to be NULL, it is not possible for adding
98115 ** this row to cause an FK violation. */
98116 fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore);
98117 }
98118
98119 sqlite3DbFree(db, aiFree);
98120 }
98121
@@ -97961,12 +98132,12 @@
98132
98133 if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
98134 && !pParse->pToplevel && !pParse->isMultiWrite
98135 ){
98136 assert( regOld==0 && regNew!=0 );
98137 /* Inserting a single row into a parent table cannot cause (or fix)
98138 ** an immediate foreign key violation. So do nothing in this case. */
98139 continue;
98140 }
98141
98142 if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
98143 if( !isIgnoreErrors || db->mallocFailed ) return;
@@ -97986,17 +98157,32 @@
98157
98158 if( regNew!=0 ){
98159 fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
98160 }
98161 if( regOld!=0 ){
98162 int eAction = pFKey->aAction[aChange!=0];
 
 
 
 
 
98163 fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
98164 /* If this is a deferred FK constraint, or a CASCADE or SET NULL
98165 ** action applies, then any foreign key violations caused by
98166 ** removing the parent key will be rectified by the action trigger.
98167 ** So do not set the "may-abort" flag in this case.
98168 **
98169 ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the
98170 ** may-abort flag will eventually be set on this statement anyway
98171 ** (when this function is called as part of processing the UPDATE
98172 ** within the action trigger).
98173 **
98174 ** Note 2: At first glance it may seem like SQLite could simply omit
98175 ** all OP_FkCounter related scans when either CASCADE or SET NULL
98176 ** applies. The trouble starts if the CASCADE or SET NULL action
98177 ** trigger causes other triggers or action rules attached to the
98178 ** child table to fire. In these cases the fk constraint counters
98179 ** might be set incorrectly if any OP_FkCounter related scans are
98180 ** omitted. */
98181 if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
98182 sqlite3MayAbort(pParse);
98183 }
98184 }
98185 pItem->zName = 0;
98186 sqlite3SrcListDelete(db, pSrc);
98187 }
98188 sqlite3DbFree(db, aiCol);
@@ -101895,10 +102081,11 @@
102081 #define PragTyp_KEY 38
102082 #define PragTyp_REKEY 39
102083 #define PragTyp_LOCK_STATUS 40
102084 #define PragTyp_PARSER_TRACE 41
102085 #define PragFlag_NeedSchema 0x01
102086 #define PragFlag_ReadOnly 0x02
102087 static const struct sPragmaNames {
102088 const char *const zName; /* Name of pragma */
102089 u8 ePragTyp; /* PragTyp_XXX value */
102090 u8 mPragFlag; /* Zero or more PragFlag_XXX values */
102091 u32 iArg; /* Extra argument */
@@ -101911,11 +102098,11 @@
102098 #endif
102099 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102100 { /* zName: */ "application_id",
102101 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102102 /* ePragFlag: */ 0,
102103 /* iArg: */ BTREE_APPLICATION_ID },
102104 #endif
102105 #if !defined(SQLITE_OMIT_AUTOVACUUM)
102106 { /* zName: */ "auto_vacuum",
102107 /* ePragTyp: */ PragTyp_AUTO_VACUUM,
102108 /* ePragFlag: */ PragFlag_NeedSchema,
@@ -101977,10 +102164,16 @@
102164 { /* zName: */ "data_store_directory",
102165 /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
102166 /* ePragFlag: */ 0,
102167 /* iArg: */ 0 },
102168 #endif
102169 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102170 { /* zName: */ "data_version",
102171 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102172 /* ePragFlag: */ PragFlag_ReadOnly,
102173 /* iArg: */ BTREE_DATA_VERSION },
102174 #endif
102175 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
102176 { /* zName: */ "database_list",
102177 /* ePragTyp: */ PragTyp_DATABASE_LIST,
102178 /* ePragFlag: */ PragFlag_NeedSchema,
102179 /* iArg: */ 0 },
@@ -102032,12 +102225,12 @@
102225 #endif
102226 #endif
102227 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102228 { /* zName: */ "freelist_count",
102229 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102230 /* ePragFlag: */ PragFlag_ReadOnly,
102231 /* iArg: */ BTREE_FREE_PAGE_COUNT },
102232 #endif
102233 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
102234 { /* zName: */ "full_column_names",
102235 /* ePragTyp: */ PragTyp_FLAG,
102236 /* ePragFlag: */ 0,
@@ -102185,11 +102378,11 @@
102378 #endif
102379 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102380 { /* zName: */ "schema_version",
102381 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102382 /* ePragFlag: */ 0,
102383 /* iArg: */ BTREE_SCHEMA_VERSION },
102384 #endif
102385 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
102386 { /* zName: */ "secure_delete",
102387 /* ePragTyp: */ PragTyp_SECURE_DELETE,
102388 /* ePragFlag: */ 0,
@@ -102251,11 +102444,11 @@
102444 /* iArg: */ 0 },
102445 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
102446 { /* zName: */ "user_version",
102447 /* ePragTyp: */ PragTyp_HEADER_VALUE,
102448 /* ePragFlag: */ 0,
102449 /* iArg: */ BTREE_USER_VERSION },
102450 #endif
102451 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
102452 #if defined(SQLITE_DEBUG)
102453 { /* zName: */ "vdbe_addoptrace",
102454 /* ePragTyp: */ PragTyp_FLAG,
@@ -102294,11 +102487,11 @@
102487 /* ePragTyp: */ PragTyp_FLAG,
102488 /* ePragFlag: */ 0,
102489 /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
102490 #endif
102491 };
102492 /* Number of pragmas: 58 on by default, 71 total. */
102493 /* End of the automatically generated pragma table.
102494 ***************************************************************************/
102495
102496 /*
102497 ** Interpret the given string as a safety level. Return 0 for OFF,
@@ -102544,11 +102737,11 @@
102737 char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
102738 const char *zDb = 0; /* The database name */
102739 Token *pId; /* Pointer to <id> token */
102740 char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
102741 int iDb; /* Database index for <database> */
102742 int lwr, upr, mid = 0; /* Binary search bounds */
102743 int rc; /* return value form SQLITE_FCNTL_PRAGMA */
102744 sqlite3 *db = pParse->db; /* The database connection */
102745 Db *pDb; /* The specific database being pragmaed */
102746 Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
102747
@@ -103904,11 +104097,12 @@
104097 !(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
104098 DbHasProperty(db, 0, DB_Empty)
104099 ){
104100 for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
104101 if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
104102 SCHEMA_ENC(db) = ENC(db) =
104103 pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
104104 break;
104105 }
104106 }
104107 if( !pEnc->zName ){
104108 sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
@@ -103949,28 +104143,13 @@
104143 **
104144 ** The user-version is not used internally by SQLite. It may be used by
104145 ** applications for any purpose.
104146 */
104147 case PragTyp_HEADER_VALUE: {
104148 int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */
104149 sqlite3VdbeUsesBtree(v, iDb);
104150 if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104151 /* Write the specified cookie value */
104152 static const VdbeOpList setCookie[] = {
104153 { OP_Transaction, 0, 1, 0}, /* 0 */
104154 { OP_Integer, 0, 1, 0}, /* 1 */
104155 { OP_SetCookie, 0, 0, 1}, /* 2 */
@@ -104612,13 +104791,15 @@
104791 SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
104792 int i, rc;
104793 int commit_internal = !(db->flags&SQLITE_InternChanges);
104794
104795 assert( sqlite3_mutex_held(db->mutex) );
104796 assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
104797 assert( db->init.busy==0 );
104798 rc = SQLITE_OK;
104799 db->init.busy = 1;
104800 ENC(db) = SCHEMA_ENC(db);
104801 for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
104802 if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
104803 rc = sqlite3InitOne(db, i, pzErrMsg);
104804 if( rc ){
104805 sqlite3ResetOneSchema(db, i);
@@ -105169,24 +105350,29 @@
105350 u8 sortFlags; /* Zero or more SORTFLAG_* bits */
105351 };
105352 #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
105353
105354 /*
105355 ** Delete all the content of a Select structure. Deallocate the structure
105356 ** itself only if bFree is true.
105357 */
105358 static void clearSelect(sqlite3 *db, Select *p, int bFree){
105359 while( p ){
105360 Select *pPrior = p->pPrior;
105361 sqlite3ExprListDelete(db, p->pEList);
105362 sqlite3SrcListDelete(db, p->pSrc);
105363 sqlite3ExprDelete(db, p->pWhere);
105364 sqlite3ExprListDelete(db, p->pGroupBy);
105365 sqlite3ExprDelete(db, p->pHaving);
105366 sqlite3ExprListDelete(db, p->pOrderBy);
105367 sqlite3ExprDelete(db, p->pLimit);
105368 sqlite3ExprDelete(db, p->pOffset);
105369 sqlite3WithDelete(db, p->pWith);
105370 if( bFree ) sqlite3DbFree(db, p);
105371 p = pPrior;
105372 bFree = 1;
105373 }
105374 }
105375
105376 /*
105377 ** Initialize a SelectDest structure.
105378 */
@@ -105241,12 +105427,11 @@
105427 pNew->pOffset = pOffset;
105428 assert( pOffset==0 || pLimit!=0 );
105429 pNew->addrOpenEphm[0] = -1;
105430 pNew->addrOpenEphm[1] = -1;
105431 if( db->mallocFailed ) {
105432 clearSelect(db, pNew, pNew!=&standin);
 
105433 pNew = 0;
105434 }else{
105435 assert( pNew->pSrc!=0 || pParse->nErr>0 );
105436 }
105437 assert( pNew!=&standin );
@@ -105267,14 +105452,11 @@
105452
105453 /*
105454 ** Delete the given Select structure and all of its substructures.
105455 */
105456 SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
105457 clearSelect(db, p, 1);
 
 
 
105458 }
105459
105460 /*
105461 ** Return a pointer to the right-most SELECT statement in a compound.
105462 */
@@ -105653,11 +105835,13 @@
105835 if( pParse->db->mallocFailed ) return;
105836 pOp->p2 = nKey + nData;
105837 pKI = pOp->p4.pKeyInfo;
105838 memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
105839 sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
105840 testcase( pKI->nXField>2 );
105841 pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
105842 pKI->nXField-1);
105843 addrJmp = sqlite3VdbeCurrentAddr(v);
105844 sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
105845 pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
105846 pSort->regReturn = ++pParse->nMem;
105847 sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
@@ -106164,11 +106348,11 @@
106348 struct ExprList_item *pItem;
106349 sqlite3 *db = pParse->db;
106350 int i;
106351
106352 nExpr = pList->nExpr;
106353 pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1);
106354 if( pInfo ){
106355 assert( sqlite3KeyInfoIsWriteable(pInfo) );
106356 for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
106357 CollSeq *pColl;
106358 pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
@@ -107186,10 +107370,70 @@
107370 Parse *pParse, /* Parsing context */
107371 Select *p, /* The right-most of SELECTs to be coded */
107372 SelectDest *pDest /* What to do with query results */
107373 );
107374
107375 /*
107376 ** Error message for when two or more terms of a compound select have different
107377 ** size result sets.
107378 */
107379 static void selectWrongNumTermsError(Parse *pParse, Select *p){
107380 if( p->selFlags & SF_Values ){
107381 sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
107382 }else{
107383 sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
107384 " do not have the same number of result columns", selectOpName(p->op));
107385 }
107386 }
107387
107388 /*
107389 ** Handle the special case of a compound-select that originates from a
107390 ** VALUES clause. By handling this as a special case, we avoid deep
107391 ** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
107392 ** on a VALUES clause.
107393 **
107394 ** Because the Select object originates from a VALUES clause:
107395 ** (1) It has no LIMIT or OFFSET
107396 ** (2) All terms are UNION ALL
107397 ** (3) There is no ORDER BY clause
107398 */
107399 static int multiSelectValues(
107400 Parse *pParse, /* Parsing context */
107401 Select *p, /* The right-most of SELECTs to be coded */
107402 SelectDest *pDest /* What to do with query results */
107403 ){
107404 Select *pPrior;
107405 int nExpr = p->pEList->nExpr;
107406 int nRow = 1;
107407 int rc = 0;
107408 assert( p->pNext==0 );
107409 assert( p->selFlags & SF_AllValues );
107410 do{
107411 assert( p->selFlags & SF_Values );
107412 assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
107413 assert( p->pLimit==0 );
107414 assert( p->pOffset==0 );
107415 if( p->pEList->nExpr!=nExpr ){
107416 selectWrongNumTermsError(pParse, p);
107417 return 1;
107418 }
107419 if( p->pPrior==0 ) break;
107420 assert( p->pPrior->pNext==p );
107421 p = p->pPrior;
107422 nRow++;
107423 }while(1);
107424 while( p ){
107425 pPrior = p->pPrior;
107426 p->pPrior = 0;
107427 rc = sqlite3Select(pParse, p, pDest);
107428 p->pPrior = pPrior;
107429 if( rc ) break;
107430 p->nSelectRow = nRow;
107431 p = p->pNext;
107432 }
107433 return rc;
107434 }
107435
107436 /*
107437 ** This routine is called to process a compound query form from
107438 ** two or more separate queries using UNION, UNION ALL, EXCEPT, or
107439 ** INTERSECT
@@ -107266,22 +107510,24 @@
107510 assert( p->pEList );
107511 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
107512 sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
107513 dest.eDest = SRT_Table;
107514 }
107515
107516 /* Special handling for a compound-select that originates as a VALUES clause.
107517 */
107518 if( p->selFlags & SF_AllValues ){
107519 rc = multiSelectValues(pParse, p, &dest);
107520 goto multi_select_end;
107521 }
107522
107523 /* Make sure all SELECTs in the statement have the same number of elements
107524 ** in their result sets.
107525 */
107526 assert( p->pEList && pPrior->pEList );
107527 if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
107528 selectWrongNumTermsError(pParse, p);
 
 
 
 
 
107529 rc = 1;
107530 goto multi_select_end;
107531 }
107532
107533 #ifndef SQLITE_OMIT_CTE
@@ -109163,11 +109409,13 @@
109409 if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
109410 return WRC_Prune;
109411 }
109412 pTabList = p->pSrc;
109413 pEList = p->pEList;
109414 if( pWalker->xSelectCallback2==selectPopWith ){
109415 sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
109416 }
109417
109418 /* Make sure cursor numbers have been assigned to all entries in
109419 ** the FROM clause of the SELECT statement.
109420 */
109421 sqlite3SrcListAssignCursors(pParse, pTabList);
@@ -109454,11 +109702,13 @@
109702 if( pParse->hasCompound ){
109703 w.xSelectCallback = convertCompoundSelectToSubquery;
109704 sqlite3WalkSelect(&w, pSelect);
109705 }
109706 w.xSelectCallback = selectExpander;
109707 if( (pSelect->selFlags & SF_AllValues)==0 ){
109708 w.xSelectCallback2 = selectPopWith;
109709 }
109710 sqlite3WalkSelect(&w, pSelect);
109711 }
109712
109713
109714 #ifndef SQLITE_OMIT_SUBQUERY
@@ -109968,11 +110218,11 @@
110218 ** we figure out that the sorting index is not needed. The addrSortIndex
110219 ** variable is used to facilitate that change.
110220 */
110221 if( sSort.pOrderBy ){
110222 KeyInfo *pKeyInfo;
110223 pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
110224 sSort.iECursor = pParse->nTab++;
110225 sSort.addrSortIndex =
110226 sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
110227 sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
110228 (char*)pKeyInfo, P4_KEYINFO
@@ -110142,11 +110392,11 @@
110392 ** implement it. Allocate that sorting index now. If it turns out
110393 ** that we do not need it after all, the OP_SorterOpen instruction
110394 ** will be converted into a Noop.
110395 */
110396 sAggInfo.sortingIdx = pParse->nTab++;
110397 pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
110398 addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
110399 sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
110400 0, (char*)pKeyInfo, P4_KEYINFO);
110401
110402 /* Initialize memory locations used by GROUP BY aggregate processing
@@ -110756,11 +111006,11 @@
111006 ){
111007 int rc;
111008 TabResult res;
111009
111010 #ifdef SQLITE_ENABLE_API_ARMOR
111011 if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT;
111012 #endif
111013 *pazResult = 0;
111014 if( pnColumn ) *pnColumn = 0;
111015 if( pnRow ) *pnRow = 0;
111016 if( pzErrMsg ) *pzErrMsg = 0;
@@ -118626,11 +118876,10 @@
118876 sqlite3_free(p->u.vtab.idxStr);
118877 p->u.vtab.needFree = 0;
118878 p->u.vtab.idxStr = 0;
118879 }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
118880 sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
 
118881 sqlite3DbFree(db, p->u.btree.pIndex);
118882 p->u.btree.pIndex = 0;
118883 }
118884 }
118885 }
@@ -123783,17 +124032,23 @@
124032 Select *p = yymsp[0].minor.yy3, *pNext, *pLoop;
124033 if( p ){
124034 int cnt = 0, mxSelect;
124035 p->pWith = yymsp[-1].minor.yy59;
124036 if( p->pPrior ){
124037 u16 allValues = SF_Values;
124038 pNext = 0;
124039 for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
124040 pLoop->pNext = pNext;
124041 pLoop->selFlags |= SF_Compound;
124042 allValues &= pLoop->selFlags;
124043 }
124044 if( allValues ){
124045 p->selFlags |= SF_AllValues;
124046 }else if(
124047 (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
124048 && cnt>mxSelect
124049 ){
124050 sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
124051 }
124052 }
124053 }else{
124054 sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
@@ -125633,10 +125888,13 @@
125888 u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
125889 sqlite3 *db = pParse->db; /* The database connection */
125890 int mxSqlLen; /* Max length of an SQL string */
125891
125892
125893 #ifdef SQLITE_ENABLE_API_ARMOR
125894 if( zSql==0 || pzErrMsg==0 ) return SQLITE_MISUSE_BKPT;
125895 #endif
125896 mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
125897 if( db->nVdbeActive==0 ){
125898 db->u1.isInterrupted = 0;
125899 }
125900 pParse->rc = SQLITE_OK;
@@ -125871,17 +126129,10 @@
126129 */
126130 SQLITE_API int sqlite3_complete(const char *zSql){
126131 u8 state = 0; /* Current state, using numbers defined in header comment */
126132 u8 token; /* Value of the next token */
126133
 
 
 
 
 
 
 
126134 #ifndef SQLITE_OMIT_TRIGGER
126135 /* A complex statement machine used to detect the end of a CREATE TRIGGER
126136 ** statement. This is the normal case.
126137 */
126138 static const u8 trans[8][8] = {
@@ -125906,10 +126157,17 @@
126157 /* 0 INVALID: */ { 1, 0, 2, },
126158 /* 1 START: */ { 1, 1, 2, },
126159 /* 2 NORMAL: */ { 1, 2, 2, },
126160 };
126161 #endif /* SQLITE_OMIT_TRIGGER */
126162
126163 #ifdef SQLITE_ENABLE_API_ARMOR
126164 if( zSql==0 ){
126165 (void)SQLITE_MISUSE_BKPT;
126166 return 0;
126167 }
126168 #endif
126169
126170 while( *zSql ){
126171 switch( *zSql ){
126172 case ';': { /* A semicolon */
126173 token = tkSEMI;
@@ -126208,11 +126466,11 @@
126466 ** If the following function pointer is not NULL and if
126467 ** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
126468 ** I/O active are written using this function. These messages
126469 ** are intended for debugging activity only.
126470 */
126471 /* not-private */ void (*sqlite3IoTrace)(const char*, ...) = 0;
126472 #endif
126473
126474 /*
126475 ** If the following global variable points to a string which is the
126476 ** name of a directory, then that directory will be used to store
@@ -126417,10 +126675,17 @@
126675 ** routine is not threadsafe. But it is safe to invoke this routine
126676 ** on when SQLite is already shut down. If SQLite is already shut down
126677 ** when this routine is invoked, then this routine is a harmless no-op.
126678 */
126679 SQLITE_API int sqlite3_shutdown(void){
126680 #ifdef SQLITE_OMIT_WSD
126681 int rc = sqlite3_wsd_init(4096, 24);
126682 if( rc!=SQLITE_OK ){
126683 return rc;
126684 }
126685 #endif
126686
126687 if( sqlite3GlobalConfig.isInit ){
126688 #ifdef SQLITE_EXTRA_SHUTDOWN
126689 void SQLITE_EXTRA_SHUTDOWN(void);
126690 SQLITE_EXTRA_SHUTDOWN();
126691 #endif
@@ -126732,10 +126997,15 @@
126997 ** heap. */
126998 sqlite3GlobalConfig.nHeap = va_arg(ap, int);
126999 break;
127000 }
127001 #endif
127002
127003 case SQLITE_CONFIG_PMASZ: {
127004 sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int);
127005 break;
127006 }
127007
127008 default: {
127009 rc = SQLITE_ERROR;
127010 break;
127011 }
@@ -127178,20 +127448,10 @@
127448
127449 /* Close all database connections */
127450 for(j=0; j<db->nDb; j++){
127451 struct Db *pDb = &db->aDb[j];
127452 if( pDb->pBt ){
 
 
 
 
 
 
 
 
 
 
127453 sqlite3BtreeClose(pDb->pBt);
127454 pDb->pBt = 0;
127455 if( j!=1 ){
127456 pDb->pSchema = 0;
127457 }
@@ -127494,11 +127754,11 @@
127754 */
127755 static int sqliteDefaultBusyCallback(
127756 void *ptr, /* Database connection */
127757 int count /* Number of times table has been busy */
127758 ){
127759 #if SQLITE_OS_WIN || HAVE_USLEEP
127760 static const u8 delays[] =
127761 { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
127762 static const u8 totals[] =
127763 { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
127764 # define NDELAY ArraySize(delays)
@@ -128110,10 +128370,11 @@
128370 }
128371 if( iDb<0 ){
128372 rc = SQLITE_ERROR;
128373 sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
128374 }else{
128375 db->busyHandler.nBusy = 0;
128376 rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
128377 sqlite3Error(db, rc);
128378 }
128379 rc = sqlite3ApiExit(db, rc);
128380 sqlite3_mutex_leave(db->mutex);
@@ -128315,36 +128576,10 @@
128576 */
128577 SQLITE_API const char *sqlite3_errstr(int rc){
128578 return sqlite3ErrStr(rc);
128579 }
128580
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128581 /*
128582 ** Create a new collating function for database "db". The name is zName
128583 ** and the encoding is enc.
128584 */
128585 static int createCollation(
@@ -128384,11 +128619,10 @@
128619 sqlite3ErrorWithMsg(db, SQLITE_BUSY,
128620 "unable to delete/modify collation sequence due to active statements");
128621 return SQLITE_BUSY;
128622 }
128623 sqlite3ExpirePreparedStatements(db);
 
128624
128625 /* If collation sequence pColl was created directly by a call to
128626 ** sqlite3_create_collation, and not generated by synthCollSeq(),
128627 ** then any copies made by synthCollSeq() need to be invalidated.
128628 ** Also, collation destructor - CollSeq.xDel() - function may need
@@ -128941,10 +129175,11 @@
129175 sqlite3Error(db, rc);
129176 goto opendb_out;
129177 }
129178 sqlite3BtreeEnter(db->aDb[0].pBt);
129179 db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
129180 if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
129181 sqlite3BtreeLeave(db->aDb[0].pBt);
129182 db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
129183
129184 /* The default safety_level for the main database is 'full'; for the temp
129185 ** database it is 'NONE'. This matches the pager layer defaults.
@@ -129099,11 +129334,11 @@
129334 if( zFilename8 ){
129335 rc = openDatabase(zFilename8, ppDb,
129336 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
129337 assert( *ppDb || rc==SQLITE_NOMEM );
129338 if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
129339 SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
129340 }
129341 }else{
129342 rc = SQLITE_NOMEM;
129343 }
129344 sqlite3ValueFree(pVal);
@@ -129310,11 +129545,11 @@
129545 ){
129546 int rc;
129547 char *zErrMsg = 0;
129548 Table *pTab = 0;
129549 Column *pCol = 0;
129550 int iCol = 0;
129551
129552 char const *zDataType = 0;
129553 char const *zCollSeq = 0;
129554 int notnull = 0;
129555 int primarykey = 0;
@@ -129841,32 +130076,34 @@
130076 /*
130077 ** Return the filename of the database associated with a database
130078 ** connection.
130079 */
130080 SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
130081 Btree *pBt;
130082 #ifdef SQLITE_ENABLE_API_ARMOR
130083 if( !sqlite3SafetyCheckOk(db) ){
130084 (void)SQLITE_MISUSE_BKPT;
130085 return 0;
130086 }
130087 #endif
130088 pBt = sqlite3DbNameToBtree(db, zDbName);
130089 return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
130090 }
130091
130092 /*
130093 ** Return 1 if database is read-only or 0 if read/write. Return -1 if
130094 ** no such database exists.
130095 */
130096 SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
130097 Btree *pBt;
130098 #ifdef SQLITE_ENABLE_API_ARMOR
130099 if( !sqlite3SafetyCheckOk(db) ){
130100 (void)SQLITE_MISUSE_BKPT;
130101 return -1;
130102 }
130103 #endif
130104 pBt = sqlite3DbNameToBtree(db, zDbName);
130105 return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
130106 }
130107
130108 /************** End of main.c ************************************************/
130109 /************** Begin file notify.c ******************************************/
@@ -132931,11 +133168,11 @@
133168 const char *zNode, /* Buffer containing segment interior node */
133169 int nNode, /* Size of buffer at zNode */
133170 sqlite3_int64 *piLeaf, /* Selected leaf node */
133171 sqlite3_int64 *piLeaf2 /* Selected leaf node */
133172 ){
133173 int rc = SQLITE_OK; /* Return code */
133174 int iHeight; /* Height of this node in tree */
133175
133176 assert( piLeaf || piLeaf2 );
133177
133178 fts3GetVarint32(zNode, &iHeight);
@@ -132942,11 +133179,11 @@
133179 rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
133180 assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
133181
133182 if( rc==SQLITE_OK && iHeight>1 ){
133183 char *zBlob = 0; /* Blob read from %_segments table */
133184 int nBlob = 0; /* Size of zBlob in bytes */
133185
133186 if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
133187 rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
133188 if( rc==SQLITE_OK ){
133189 rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0);
@@ -134164,11 +134401,11 @@
134401 int idxNum, /* Strategy index */
134402 const char *idxStr, /* Unused */
134403 int nVal, /* Number of elements in apVal */
134404 sqlite3_value **apVal /* Arguments for the indexing scheme */
134405 ){
134406 int rc = SQLITE_OK;
134407 char *zSql; /* SQL statement used to access %_content */
134408 int eSearch;
134409 Fts3Table *p = (Fts3Table *)pCursor->pVtab;
134410 Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
134411
@@ -140652,11 +140889,11 @@
140889 int argc, /* Number of elements in argv array */
140890 const char * const *argv, /* xCreate/xConnect argument array */
140891 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
140892 char **pzErr /* OUT: sqlite3_malloc'd error message */
140893 ){
140894 Fts3tokTable *pTab = 0;
140895 const sqlite3_tokenizer_module *pMod = 0;
140896 sqlite3_tokenizer *pTok = 0;
140897 int rc;
140898 char **azDequote = 0;
140899 int nDequote;
@@ -144027,12 +144264,12 @@
144264 }
144265 rc = sqlite3_reset(pRange);
144266
144267 if( bOk ){
144268 int iIdx = 0;
144269 sqlite3_stmt *pUpdate1 = 0;
144270 sqlite3_stmt *pUpdate2 = 0;
144271
144272 if( rc==SQLITE_OK ){
144273 rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0);
144274 }
144275 if( rc==SQLITE_OK ){
@@ -149260,17 +149497,16 @@
149497 */
149498 static int readInt16(u8 *p){
149499 return (p[0]<<8) + p[1];
149500 }
149501 static void readCoord(u8 *p, RtreeCoord *pCoord){
149502 pCoord->u = (
149503 (((u32)p[0]) << 24) +
149504 (((u32)p[1]) << 16) +
149505 (((u32)p[2]) << 8) +
149506 (((u32)p[3]) << 0)
149507 );
 
149508 }
149509 static i64 readInt64(u8 *p){
149510 return (
149511 (((i64)p[0]) << 56) +
149512 (((i64)p[1]) << 48) +
@@ -149295,11 +149531,11 @@
149531 }
149532 static int writeCoord(u8 *p, RtreeCoord *pCoord){
149533 u32 i;
149534 assert( sizeof(RtreeCoord)==4 );
149535 assert( sizeof(u32)==4 );
149536 i = pCoord->u;
149537 p[0] = (i>>24)&0xFF;
149538 p[1] = (i>>16)&0xFF;
149539 p[2] = (i>> 8)&0xFF;
149540 p[3] = (i>> 0)&0xFF;
149541 return 4;
@@ -149626,18 +149862,17 @@
149862 RtreeNode *pNode, /* The node containing the cell to be read */
149863 int iCell, /* Index of the cell within the node */
149864 RtreeCell *pCell /* OUT: Write the cell contents here */
149865 ){
149866 u8 *pData;
 
149867 RtreeCoord *pCoord;
149868 int ii;
149869 pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
149870 pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
 
149871 pCoord = pCell->aCoord;
149872 for(ii=0; ii<pRtree->nDim*2; ii++){
149873 readCoord(&pData[ii*4], &pCoord[ii]);
149874 }
149875 }
149876
149877
149878 /* Forward declaration for the function that does the work of
@@ -150073,11 +150308,11 @@
150308 }
150309 i = pCur->nPoint++;
150310 pNew = pCur->aPoint + i;
150311 pNew->rScore = rScore;
150312 pNew->iLevel = iLevel;
150313 assert( iLevel<=RTREE_MAX_DEPTH );
150314 while( i>0 ){
150315 RtreeSearchPoint *pParent;
150316 j = (i-1)/2;
150317 pParent = pCur->aPoint + j;
150318 if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break;
@@ -151696,10 +151931,12 @@
151931 RtreeCell cell; /* New cell to insert if nData>1 */
151932 int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
151933
151934 rtreeReference(pRtree);
151935 assert(nData>=1);
151936
151937 cell.iRowid = 0; /* Used only to suppress a compiler warning */
151938
151939 /* Constraint handling. A write operation on an r-tree table may return
151940 ** SQLITE_CONSTRAINT for two reasons:
151941 **
151942 ** 1. A duplicate rowid value, or
151943
+31 -13
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -105,13 +105,13 @@
105105
**
106106
** See also: [sqlite3_libversion()],
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110
-#define SQLITE_VERSION "3.8.8"
110
+#define SQLITE_VERSION "3.8.8.2"
111111
#define SQLITE_VERSION_NUMBER 3008008
112
-#define SQLITE_SOURCE_ID "2014-12-10 04:58:43 3528f8dd39acace8eeb7337994c8617313f4b04b"
112
+#define SQLITE_SOURCE_ID "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -199,11 +199,11 @@
199199
** This interface only reports on the compile-time mutex setting
200200
** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
201201
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
202202
** can be fully or partially disabled using a call to [sqlite3_config()]
203203
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
204
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
204
+** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
205205
** sqlite3_threadsafe() function shows only the compile-time setting of
206206
** thread safety, not any run-time changes to that setting made by
207207
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
208208
** is unchanged by calls to sqlite3_config().)^
209209
**
@@ -1568,11 +1568,11 @@
15681568
** configuration option.
15691569
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
15701570
** 8-byte aligned
15711571
** memory, the size of each page buffer (sz), and the number of pages (N).
15721572
** The sz argument should be the size of the largest database page
1573
-** (a power of two between 512 and 32768) plus some extra bytes for each
1573
+** (a power of two between 512 and 65536) plus some extra bytes for each
15741574
** page header. ^The number of extra bytes needed by the page header
15751575
** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
15761576
** to [sqlite3_config()].
15771577
** ^It is harmless, apart from the wasted memory,
15781578
** for the sz parameter to be larger than necessary. The first
@@ -1748,10 +1748,21 @@
17481748
** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
17491749
** is a pointer to an integer and writes into that integer the number of extra
17501750
** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
17511751
** The amount of extra space required can change depending on the compiler,
17521752
** target platform, and SQLite version.
1753
+**
1754
+** [[SQLITE_CONFIG_PMASZ]]
1755
+** <dt>SQLITE_CONFIG_PMASZ
1756
+** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
1757
+** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
1758
+** sorter to that integer. The default minimum PMA Size is set by the
1759
+** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
1760
+** to help with sort operations when multithreaded sorting
1761
+** is enabled (using the [PRAGMA threads] command) and the amount of content
1762
+** to be sorted exceeds the page size times the minimum of the
1763
+** [PRAGMA cache_size] setting and this value.
17531764
** </dl>
17541765
*/
17551766
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
17561767
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
17571768
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1774,10 +1785,11 @@
17741785
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
17751786
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
17761787
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
17771788
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
17781789
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
1790
+#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
17791791
17801792
/*
17811793
** CAPI3REF: Database Connection Configuration Options
17821794
**
17831795
** These constants are the available integer configuration options that
@@ -7183,16 +7195,14 @@
71837195
71847196
/*
71857197
** CAPI3REF: Write-Ahead Log Commit Hook
71867198
**
71877199
** ^The [sqlite3_wal_hook()] function is used to register a callback that
7188
-** will be invoked each time a database connection commits data to a
7189
-** [write-ahead log] (i.e. whenever a transaction is committed in
7190
-** [journal_mode | journal_mode=WAL mode]).
7200
+** is invoked each time data is committed to a database in wal mode.
71917201
**
7192
-** ^The callback is invoked by SQLite after the commit has taken place and
7193
-** the associated write-lock on the database released, so the implementation
7202
+** ^(The callback is invoked by SQLite after the commit has taken place and
7203
+** the associated write-lock on the database released)^, so the implementation
71947204
** may read, write or [checkpoint] the database as required.
71957205
**
71967206
** ^The first parameter passed to the callback function when it is invoked
71977207
** is a copy of the third parameter passed to sqlite3_wal_hook() when
71987208
** registering the callback. ^The second is a copy of the database handle.
@@ -7479,10 +7489,14 @@
74797489
**
74807490
** The following constants can be used for the T parameter to the
74817491
** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
74827492
** different metric for sqlite3_stmt_scanstatus() to return.
74837493
**
7494
+** When the value returned to V is a string, space to hold that string is
7495
+** managed by the prepared statement S and will be automatically freed when
7496
+** S is finalized.
7497
+**
74847498
** <dl>
74857499
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
74867500
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
74877501
** set to the total number of times that the X-th loop has run.</dd>
74887502
**
@@ -7524,11 +7538,18 @@
75247538
#define SQLITE_SCANSTAT_SELECTID 5
75257539
75267540
/*
75277541
** CAPI3REF: Prepared Statement Scan Status
75287542
**
7529
-** Return status data for a single loop within query pStmt.
7543
+** This interface returns information about the predicted and measured
7544
+** performance for pStmt. Advanced applications can use this
7545
+** interface to compare the predicted and the measured performance and
7546
+** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
7547
+**
7548
+** Since this interface is expected to be rarely used, it is only
7549
+** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
7550
+** compile-time option.
75307551
**
75317552
** The "iScanStatusOp" parameter determines which status information to return.
75327553
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
75337554
** of this interface is undefined.
75347555
** ^The requested measurement is written into a variable pointed to by
@@ -7542,13 +7563,10 @@
75427563
** ^Statistics might not be available for all loops in all statements. ^In cases
75437564
** where there exist loops with no available statistics, this function behaves
75447565
** as if the loop did not exist - it returns non-zero and leave the variable
75457566
** that pOut points to unchanged.
75467567
**
7547
-** This API is only available if the library is built with pre-processor
7548
-** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
7549
-**
75507568
** See also: [sqlite3_stmt_scanstatus_reset()]
75517569
*/
75527570
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
75537571
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
75547572
int idx, /* Index of loop to report on */
75557573
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -105,13 +105,13 @@
105 **
106 ** See also: [sqlite3_libversion()],
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.8"
111 #define SQLITE_VERSION_NUMBER 3008008
112 #define SQLITE_SOURCE_ID "2014-12-10 04:58:43 3528f8dd39acace8eeb7337994c8617313f4b04b"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -199,11 +199,11 @@
199 ** This interface only reports on the compile-time mutex setting
200 ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
201 ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
202 ** can be fully or partially disabled using a call to [sqlite3_config()]
203 ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
204 ** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
205 ** sqlite3_threadsafe() function shows only the compile-time setting of
206 ** thread safety, not any run-time changes to that setting made by
207 ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
208 ** is unchanged by calls to sqlite3_config().)^
209 **
@@ -1568,11 +1568,11 @@
1568 ** configuration option.
1569 ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
1570 ** 8-byte aligned
1571 ** memory, the size of each page buffer (sz), and the number of pages (N).
1572 ** The sz argument should be the size of the largest database page
1573 ** (a power of two between 512 and 32768) plus some extra bytes for each
1574 ** page header. ^The number of extra bytes needed by the page header
1575 ** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
1576 ** to [sqlite3_config()].
1577 ** ^It is harmless, apart from the wasted memory,
1578 ** for the sz parameter to be larger than necessary. The first
@@ -1748,10 +1748,21 @@
1748 ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
1749 ** is a pointer to an integer and writes into that integer the number of extra
1750 ** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
1751 ** The amount of extra space required can change depending on the compiler,
1752 ** target platform, and SQLite version.
 
 
 
 
 
 
 
 
 
 
 
1753 ** </dl>
1754 */
1755 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
1756 #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
1757 #define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1774,10 +1785,11 @@
1774 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
1775 #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
1776 #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
1777 #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
1778 #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
 
1779
1780 /*
1781 ** CAPI3REF: Database Connection Configuration Options
1782 **
1783 ** These constants are the available integer configuration options that
@@ -7183,16 +7195,14 @@
7183
7184 /*
7185 ** CAPI3REF: Write-Ahead Log Commit Hook
7186 **
7187 ** ^The [sqlite3_wal_hook()] function is used to register a callback that
7188 ** will be invoked each time a database connection commits data to a
7189 ** [write-ahead log] (i.e. whenever a transaction is committed in
7190 ** [journal_mode | journal_mode=WAL mode]).
7191 **
7192 ** ^The callback is invoked by SQLite after the commit has taken place and
7193 ** the associated write-lock on the database released, so the implementation
7194 ** may read, write or [checkpoint] the database as required.
7195 **
7196 ** ^The first parameter passed to the callback function when it is invoked
7197 ** is a copy of the third parameter passed to sqlite3_wal_hook() when
7198 ** registering the callback. ^The second is a copy of the database handle.
@@ -7479,10 +7489,14 @@
7479 **
7480 ** The following constants can be used for the T parameter to the
7481 ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
7482 ** different metric for sqlite3_stmt_scanstatus() to return.
7483 **
 
 
 
 
7484 ** <dl>
7485 ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
7486 ** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
7487 ** set to the total number of times that the X-th loop has run.</dd>
7488 **
@@ -7524,11 +7538,18 @@
7524 #define SQLITE_SCANSTAT_SELECTID 5
7525
7526 /*
7527 ** CAPI3REF: Prepared Statement Scan Status
7528 **
7529 ** Return status data for a single loop within query pStmt.
 
 
 
 
 
 
 
7530 **
7531 ** The "iScanStatusOp" parameter determines which status information to return.
7532 ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
7533 ** of this interface is undefined.
7534 ** ^The requested measurement is written into a variable pointed to by
@@ -7542,13 +7563,10 @@
7542 ** ^Statistics might not be available for all loops in all statements. ^In cases
7543 ** where there exist loops with no available statistics, this function behaves
7544 ** as if the loop did not exist - it returns non-zero and leave the variable
7545 ** that pOut points to unchanged.
7546 **
7547 ** This API is only available if the library is built with pre-processor
7548 ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
7549 **
7550 ** See also: [sqlite3_stmt_scanstatus_reset()]
7551 */
7552 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
7553 sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
7554 int idx, /* Index of loop to report on */
7555
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -105,13 +105,13 @@
105 **
106 ** See also: [sqlite3_libversion()],
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.8.2"
111 #define SQLITE_VERSION_NUMBER 3008008
112 #define SQLITE_SOURCE_ID "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -199,11 +199,11 @@
199 ** This interface only reports on the compile-time mutex setting
200 ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
201 ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
202 ** can be fully or partially disabled using a call to [sqlite3_config()]
203 ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
204 ** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
205 ** sqlite3_threadsafe() function shows only the compile-time setting of
206 ** thread safety, not any run-time changes to that setting made by
207 ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
208 ** is unchanged by calls to sqlite3_config().)^
209 **
@@ -1568,11 +1568,11 @@
1568 ** configuration option.
1569 ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
1570 ** 8-byte aligned
1571 ** memory, the size of each page buffer (sz), and the number of pages (N).
1572 ** The sz argument should be the size of the largest database page
1573 ** (a power of two between 512 and 65536) plus some extra bytes for each
1574 ** page header. ^The number of extra bytes needed by the page header
1575 ** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
1576 ** to [sqlite3_config()].
1577 ** ^It is harmless, apart from the wasted memory,
1578 ** for the sz parameter to be larger than necessary. The first
@@ -1748,10 +1748,21 @@
1748 ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
1749 ** is a pointer to an integer and writes into that integer the number of extra
1750 ** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
1751 ** The amount of extra space required can change depending on the compiler,
1752 ** target platform, and SQLite version.
1753 **
1754 ** [[SQLITE_CONFIG_PMASZ]]
1755 ** <dt>SQLITE_CONFIG_PMASZ
1756 ** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
1757 ** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
1758 ** sorter to that integer. The default minimum PMA Size is set by the
1759 ** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
1760 ** to help with sort operations when multithreaded sorting
1761 ** is enabled (using the [PRAGMA threads] command) and the amount of content
1762 ** to be sorted exceeds the page size times the minimum of the
1763 ** [PRAGMA cache_size] setting and this value.
1764 ** </dl>
1765 */
1766 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
1767 #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
1768 #define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1774,10 +1785,11 @@
1785 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
1786 #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
1787 #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
1788 #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
1789 #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
1790 #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
1791
1792 /*
1793 ** CAPI3REF: Database Connection Configuration Options
1794 **
1795 ** These constants are the available integer configuration options that
@@ -7183,16 +7195,14 @@
7195
7196 /*
7197 ** CAPI3REF: Write-Ahead Log Commit Hook
7198 **
7199 ** ^The [sqlite3_wal_hook()] function is used to register a callback that
7200 ** is invoked each time data is committed to a database in wal mode.
 
 
7201 **
7202 ** ^(The callback is invoked by SQLite after the commit has taken place and
7203 ** the associated write-lock on the database released)^, so the implementation
7204 ** may read, write or [checkpoint] the database as required.
7205 **
7206 ** ^The first parameter passed to the callback function when it is invoked
7207 ** is a copy of the third parameter passed to sqlite3_wal_hook() when
7208 ** registering the callback. ^The second is a copy of the database handle.
@@ -7479,10 +7489,14 @@
7489 **
7490 ** The following constants can be used for the T parameter to the
7491 ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
7492 ** different metric for sqlite3_stmt_scanstatus() to return.
7493 **
7494 ** When the value returned to V is a string, space to hold that string is
7495 ** managed by the prepared statement S and will be automatically freed when
7496 ** S is finalized.
7497 **
7498 ** <dl>
7499 ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
7500 ** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
7501 ** set to the total number of times that the X-th loop has run.</dd>
7502 **
@@ -7524,11 +7538,18 @@
7538 #define SQLITE_SCANSTAT_SELECTID 5
7539
7540 /*
7541 ** CAPI3REF: Prepared Statement Scan Status
7542 **
7543 ** This interface returns information about the predicted and measured
7544 ** performance for pStmt. Advanced applications can use this
7545 ** interface to compare the predicted and the measured performance and
7546 ** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
7547 **
7548 ** Since this interface is expected to be rarely used, it is only
7549 ** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
7550 ** compile-time option.
7551 **
7552 ** The "iScanStatusOp" parameter determines which status information to return.
7553 ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
7554 ** of this interface is undefined.
7555 ** ^The requested measurement is written into a variable pointed to by
@@ -7542,13 +7563,10 @@
7563 ** ^Statistics might not be available for all loops in all statements. ^In cases
7564 ** where there exist loops with no available statistics, this function behaves
7565 ** as if the loop did not exist - it returns non-zero and leave the variable
7566 ** that pOut points to unchanged.
7567 **
 
 
 
7568 ** See also: [sqlite3_stmt_scanstatus_reset()]
7569 */
7570 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
7571 sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
7572 int idx, /* Index of loop to report on */
7573
+6
--- src/stat.c
+++ src/stat.c
@@ -55,15 +55,17 @@
5555
5656
login_check_credentials();
5757
if( !g.perm.Read ){ login_needed(); return; }
5858
brief = P("brief")!=0;
5959
style_header("Repository Statistics");
60
+ style_adunit_config(ADUNIT_RIGHT_OK);
6061
if( g.perm.Admin ){
6162
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
6263
style_submenu_element("Schema", "Repository Schema", "repo_schema");
6364
style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat");
6465
}
66
+ style_submenu_element("Activity", "Activity Reports", "reports");
6567
@ <table class="label-value">
6668
@ <tr><th>Repository&nbsp;Size:</th><td>
6769
fsize = file_size(g.zRepositoryName);
6870
bigSizeName(sizeof(zBuf), zBuf, fsize);
6971
@ %s(zBuf)
@@ -132,10 +134,11 @@
132134
@ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
133135
@ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
134136
@ </td></tr>
135137
@ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(sqlite3_sourceid())
136138
@ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))</td></tr>
139
+ @ <tr><th>Schema&nbsp;Version:</th><td>%h(g.zAuxSchema)</td></tr>
137140
@ <tr><th>Repository Rebuilt:</th><td>
138141
@ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never"))
139142
@ By Fossil %h(db_get("rebuilt","Unknown"))</td></tr>
140143
@ <tr><th>Database&nbsp;Stats:</th><td>
141144
zDb = db_name("repository");
@@ -253,10 +256,11 @@
253256
}
254257
#if 0
255258
/* Server-id is not useful information any more */
256259
fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0));
257260
#endif
261
+ fossil_print("%*s%s\n", colWidth, "schema-version:", g.zAuxSchema);
258262
if( !omitVers ){
259263
fossil_print("%*s%s %s [%s] (%s)\n",
260264
colWidth, "fossil-version:",
261265
MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
262266
COMPILER_NAME);
@@ -290,10 +294,11 @@
290294
int cnt;
291295
login_check_credentials();
292296
if( !g.perm.Admin ){ login_needed(); return; }
293297
294298
style_header("URLs and Checkouts");
299
+ style_adunit_config(ADUNIT_RIGHT_OK);
295300
style_submenu_element("Stat", "Repository Stats", "stat");
296301
style_submenu_element("Schema", "Repository Schema", "repo_schema");
297302
@ <div class="section">URLs</div>
298303
@ <table border="0" width='100%%'>
299304
db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')"
@@ -336,10 +341,11 @@
336341
Stmt q;
337342
login_check_credentials();
338343
if( !g.perm.Admin ){ login_needed(); return; }
339344
340345
style_header("Repository Schema");
346
+ style_adunit_config(ADUNIT_RIGHT_OK);
341347
style_submenu_element("Stat", "Repository Stats", "stat");
342348
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
343349
db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL",
344350
db_name("repository"));
345351
@ <pre>
346352
347353
ADDED src/statrep.c
--- src/stat.c
+++ src/stat.c
@@ -55,15 +55,17 @@
55
56 login_check_credentials();
57 if( !g.perm.Read ){ login_needed(); return; }
58 brief = P("brief")!=0;
59 style_header("Repository Statistics");
 
60 if( g.perm.Admin ){
61 style_submenu_element("URLs", "URLs and Checkouts", "urllist");
62 style_submenu_element("Schema", "Repository Schema", "repo_schema");
63 style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat");
64 }
 
65 @ <table class="label-value">
66 @ <tr><th>Repository&nbsp;Size:</th><td>
67 fsize = file_size(g.zRepositoryName);
68 bigSizeName(sizeof(zBuf), zBuf, fsize);
69 @ %s(zBuf)
@@ -132,10 +134,11 @@
132 @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
133 @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
134 @ </td></tr>
135 @ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(sqlite3_sourceid())
136 @ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))</td></tr>
 
137 @ <tr><th>Repository Rebuilt:</th><td>
138 @ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never"))
139 @ By Fossil %h(db_get("rebuilt","Unknown"))</td></tr>
140 @ <tr><th>Database&nbsp;Stats:</th><td>
141 zDb = db_name("repository");
@@ -253,10 +256,11 @@
253 }
254 #if 0
255 /* Server-id is not useful information any more */
256 fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0));
257 #endif
 
258 if( !omitVers ){
259 fossil_print("%*s%s %s [%s] (%s)\n",
260 colWidth, "fossil-version:",
261 MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
262 COMPILER_NAME);
@@ -290,10 +294,11 @@
290 int cnt;
291 login_check_credentials();
292 if( !g.perm.Admin ){ login_needed(); return; }
293
294 style_header("URLs and Checkouts");
 
295 style_submenu_element("Stat", "Repository Stats", "stat");
296 style_submenu_element("Schema", "Repository Schema", "repo_schema");
297 @ <div class="section">URLs</div>
298 @ <table border="0" width='100%%'>
299 db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')"
@@ -336,10 +341,11 @@
336 Stmt q;
337 login_check_credentials();
338 if( !g.perm.Admin ){ login_needed(); return; }
339
340 style_header("Repository Schema");
 
341 style_submenu_element("Stat", "Repository Stats", "stat");
342 style_submenu_element("URLs", "URLs and Checkouts", "urllist");
343 db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL",
344 db_name("repository"));
345 @ <pre>
346
347 DDED src/statrep.c
--- src/stat.c
+++ src/stat.c
@@ -55,15 +55,17 @@
55
56 login_check_credentials();
57 if( !g.perm.Read ){ login_needed(); return; }
58 brief = P("brief")!=0;
59 style_header("Repository Statistics");
60 style_adunit_config(ADUNIT_RIGHT_OK);
61 if( g.perm.Admin ){
62 style_submenu_element("URLs", "URLs and Checkouts", "urllist");
63 style_submenu_element("Schema", "Repository Schema", "repo_schema");
64 style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat");
65 }
66 style_submenu_element("Activity", "Activity Reports", "reports");
67 @ <table class="label-value">
68 @ <tr><th>Repository&nbsp;Size:</th><td>
69 fsize = file_size(g.zRepositoryName);
70 bigSizeName(sizeof(zBuf), zBuf, fsize);
71 @ %s(zBuf)
@@ -132,10 +134,11 @@
134 @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
135 @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
136 @ </td></tr>
137 @ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(sqlite3_sourceid())
138 @ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))</td></tr>
139 @ <tr><th>Schema&nbsp;Version:</th><td>%h(g.zAuxSchema)</td></tr>
140 @ <tr><th>Repository Rebuilt:</th><td>
141 @ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never"))
142 @ By Fossil %h(db_get("rebuilt","Unknown"))</td></tr>
143 @ <tr><th>Database&nbsp;Stats:</th><td>
144 zDb = db_name("repository");
@@ -253,10 +256,11 @@
256 }
257 #if 0
258 /* Server-id is not useful information any more */
259 fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code", 0));
260 #endif
261 fossil_print("%*s%s\n", colWidth, "schema-version:", g.zAuxSchema);
262 if( !omitVers ){
263 fossil_print("%*s%s %s [%s] (%s)\n",
264 colWidth, "fossil-version:",
265 MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
266 COMPILER_NAME);
@@ -290,10 +294,11 @@
294 int cnt;
295 login_check_credentials();
296 if( !g.perm.Admin ){ login_needed(); return; }
297
298 style_header("URLs and Checkouts");
299 style_adunit_config(ADUNIT_RIGHT_OK);
300 style_submenu_element("Stat", "Repository Stats", "stat");
301 style_submenu_element("Schema", "Repository Schema", "repo_schema");
302 @ <div class="section">URLs</div>
303 @ <table border="0" width='100%%'>
304 db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')"
@@ -336,10 +341,11 @@
341 Stmt q;
342 login_check_credentials();
343 if( !g.perm.Admin ){ login_needed(); return; }
344
345 style_header("Repository Schema");
346 style_adunit_config(ADUNIT_RIGHT_OK);
347 style_submenu_element("Stat", "Repository Stats", "stat");
348 style_submenu_element("URLs", "URLs and Checkouts", "urllist");
349 db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL",
350 db_name("repository"));
351 @ <pre>
352
353 DDED src/statrep.c
+535
--- a/src/statrep.c
+++ b/src/statrep.c
@@ -0,0 +1,535 @@
1
+eea"zT
2
+ ;
3
+ @ claT
4
+ ;
5
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
6
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
7
+ style_footer();
8
+}
9
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
10
+ ;
11
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
12
+ style_footer();
13
+}
14
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
15
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
16
+ "ELSE 'ERROR' END;"svg class="pie-chart"
17
+ @ svg class="pie-chart"
18
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
19
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
20
+ , "Sunday"
21
+ };
22
+
23
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
24
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
25
+ ;
26
+ @ claT
27
+ ;
28
+ @ ce><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
29
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
30
+ "ELSE 'ERROR' END;"svg class="pie-chart"
31
+ @ svg class="pie-chart"
32
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
33
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
34
+ , "Sunday"
35
+ };
36
+
37
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
38
+ ;
39
+ @ claT
40
+ e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
41
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
42
+ "ELSE 'ERROR' END;"svg class="pie-chart"
43
+ @ svg class="pie-chart"
44
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
45
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
46
+ , "Sunday"
47
+ };
48
+
49
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
50
+ ;
51
+ @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
52
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
53
+ "ELSE 'ERROR' END;"svg class="pie-chart"
54
+ @ svg class="pie-chart"
55
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
56
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
57
+ , "Sunday"
58
+ };
59
+
60
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
61
+ ;
62
+ element(zMenuName, zMenuName, "%s url_render(pUrl, zParBy File", ny TypeelpiechartTABLE peea"zT
63
+ ;
64
+ @ claT
65
+ ;
66
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
67
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
68
+ style_footer();
69
+}
70
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
71
+ ;
72
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
73
+ style_footer();
74
+}
75
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
76
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
77
+ "ELSE 'ERROR' END;"svg class="pie-chart"
78
+ @ svg class="pie-chart"
79
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
80
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
81
+ , "Sunday"
82
+ };
83
+
84
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
85
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
86
+ ;
87
+ @ claT
88
+ ;
89
+ @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
90
+ azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
91
+ azYear[n] = fossil_strdup(,0));
92
+ azYear[n+1] = azYear[n];
93
+ if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) zYear = azYear[0];zT
94
+ ;
95
+ @ claT
96
+ ;
97
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
98
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
99
+ style_footer();
100
+}
101
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
102
+ ;
103
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
104
+ style_footer();
105
+}
106
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
107
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
108
+ "ELSE 'ERROR' END;"svg class="pie-chart"
109
+ @ svg class="pie-chart"
110
+ @ HQuery url;/* RL for eventbranch linksurl_initialize(&url, "reports");
111
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
112
+ , "Sunday"
113
+ };
114
+
115
+ ;mtime %% 7mt/*
116
+** A helper for the /reports family of pages which prints out a menu
117
+** of links for the various type=XXX flags. zCurrentViewName must be
118
+** the name/value of the 'view' parameter which is in effect at the
119
+** time this is called. e.g. if called from the 'byuser' view then
120
+** zCurrentViewName must be "byuser". Any URL parameters which need to
121
+** be added to the generated URLs should be passed in zParam. The
122
+** caller is expected to have already encoded any zParam in event_types_menu(c><svg</centre>center><svg</centre> "Thursday",
123
+ , "Sunday"
124
+ };
125
+
126
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
127
+ ;
128
+ @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
129
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
130
+ "ELSE 'ERROR' END;"svg class="pie-chart"
131
+ @ svg class="pie-chart"uery url;/* URL for various branch linksurl_initialize(&url, "reports");
132
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>csnter><svg</centre> "Thursday",
133
+ , "Sunday"
134
+ };
135
+
136
+ ;mtime %% 7mtime %% 7Mg.zTop,MoTuesWednThur5Sunday eea"zT
137
+ ;
138
+ element(zMenuName, zMenuNameinsass="pie-chart"
139
+ @ HQuery url;/*ci'>checkin"2;"
140
+ "UPDATE piechareea"zT
141
+ ;
142
+ @ claT
143
+ ;
144
+ even class='lastchngTable'nameeea"zTuserlist","tT}
145
+ style_footer();e'>event; @ class='lastchngTeble'nameeea"zTuserlist","tT}
146
+ style_footer();
147
+}
148
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
149
+ ;
150
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
151
+ style_footer();
152
+}
153
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
154
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
155
+ "ELSE 'ERROR' END;"svg class="pie-chart"
156
+ @ svg class="pie-chart"
157
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
158
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
159
+ , "Sunday"
160
+ };
161
+
162
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
163
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
164
+ ;
165
+ @ claT
166
+ ;
167
+ @ ce><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
168
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
169
+ "ELSE 'ERROR' END;"svg class="pie-chart"
170
+ @ svg class="pie-chart"
171
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
172
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
173
+ , "Sunday"
174
+ };
175
+
176
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
177
+ ;
178
+ @ claT
179
+ e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
180
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
181
+ "ELSE 'ERROR' END;"svg class="pie-chart"
182
+ @ svg class="pie-chart"
183
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
184
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
185
+ , "Sunday"
186
+ };
187
+
188
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
189
+ ;
190
+ @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
191
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
192
+ "ELSE 'ERROR' END;"svg class="pie-chart"
193
+ @ svg class="pie-chart"
194
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
195
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
196
+ , "Sunday"
197
+ };
198
+
199
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
200
+ ;
201
+ element(zMenuName, zMenuName, "%s url_render(pUrl, zParBy File", ny TypeelpiechartTABLE peea"zT
202
+ ;
203
+ @ claT
204
+ ;
205
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
206
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
207
+ style_footer();
208
+}
209
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
210
+ ;
211
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
212
+ style_footer();
213
+}
214
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
215
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
216
+ "ELSE 'ERROR' END;"svg class="pie-chart"
217
+ @ svg class="pie-chart"
218
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
219
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
220
+ , "Sunday"
221
+ };
222
+
223
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
224
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
225
+ ;
226
+ @ claT
227
+ ;
228
+ @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
229
+ azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
230
+ azYear[n] = fossil_strdup(,0));
231
+ azYear[n+1] = azYear[n];
232
+ if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) zYear = azYear[0];zT
233
+ ;
234
+ @ claT
235
+ ;
236
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
237
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
238
+ style_footer();
239
+}
240
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
241
+ ;
242
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
243
+ style_footer();
244
+}
245
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
246
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
247
+ "ELSE 'ERRsR' END;"svg class="pie-chart"
248
+ @ svg class="pie-chart"
249
+ @ Hg.zTop,HQuery url;/* RL for various branch linksurl_initialize(&url, "reports");
250
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
251
+ , "Sunday"
252
+ };
253
+
254
+ ;mtime %% 7mt/*
255
+** A helper for the /reports family of pages which prints out a menu
256
+** of links for the various type=XXX flags. zCurrentViewName must be
257
+** the name/value of the 'view' parameter which is in effect at the
258
+** time this is called. e.g. if called from the 'byuser' view then
259
+** zCurrentViewName must be "byuser". Any URL parameters which need to
260
+** be added to the generated URLs should be passed in zParam. The
261
+** caller is expected to have already encoded any zParam in event_types_menu(c><svg</centre>center><svg</centre> "Thursday",
262
+ , "Sunday"
263
+ };
264
+
265
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
266
+ ;
267
+ @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
268
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
269
+ "ELSE 'ERROR' END;"svg class="pie-chart"
270
+ @ svg class="pie-chart"uery url;/* URL for various branch linksurl_initialize(&url, "reports");
271
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
272
+ , "Sunday"
273
+ };
274
+
275
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
276
+ ;
277
+ element(zMenuName, zMenuNameinsass="pie-chart"
278
+ @ HQuery url;/*ci'>checkin"2;"
279
+ "UPDATE piechareea"zT
280
+ ;
281
+ @ claT
282
+ ;
283
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
284
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
285
+ style_footer();
286
+}
287
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
288
+ ;
289
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
290
+ style_footer();
291
+}
292
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
293
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
294
+ "ELSE 'ERROR' END;"svg class="pie-chart"
295
+ @ svg class="pie-chart"
296
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
297
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
298
+ , "Sunday"
299
+ };
300
+
301
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
302
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
303
+ ;
304
+ @ claT
305
+ ;
306
+ @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
307
+ azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
308
+ azYear[n] = fossil_strdup(,0));
309
+ azYear[n+1] = azYear[n];
310
+ if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) ='lastchngTeble'nameeea"zTuserlist","tT}
311
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
312
+ style_footer();
313
+}
314
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
315
+ ;
316
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
317
+ style_footer();
318
+}
319
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
320
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
321
+ "ELSE 'ERROR' END;"svg class="pie-chart"
322
+ @ svg class="pie-chart"
323
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
324
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
325
+ , "Sunday"
326
+ };
327
+
328
+ ;mtime %% 7mtimand not empty
329
+** class="pie-chart"slist","tT}
330
+ style_feeaclass='lastchngTable'nameeea"zTuserlist","tT}
331
+ style_footer();
332
+}
333
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
334
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
335
+ "ELSE 'ERROR' END;"svg class="pie-chart"
336
+ @ svg class="pie-chart"
337
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");Blob sql-chart"
338
+ @ HQuery /* SQo_url(&url);url_rese_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
339
+ , "Sunday"
340
+ };
341
+
342
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
343
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
344
+ ;
345
+ @ claT
346
+ ;
347
+ @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
348
+ azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
349
+ azYear[n] = fossil_strdup(,0));
350
+ azYear[n+1] = azYear[n];
351
+ if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) ='lastchngTeble'nameeea"zTuserlist","tT}
352
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
353
+ style_footer();
354
+}
355
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
356
+ ;
357
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
358
+ unday"
359
+ } NULL );
360
+header, "s) by yearL for various branchmtime %% 7mtime %% 7MoTuesWedme=TABLE piechart(amt,labelpie);
361
+ blob_append_sql(&sqlr5Sunday eea"zT
362
+ ;
363
+ @e><htimeframe,a"/center><svg/centeea"zincludeMonth if( PB("pie") ){ cgi_query_paramete
364
+ " ySizeArraySizeArraySizeeea"zT
365
+ ;
366
+ @ claT
367
+ ;
368
+ @"zT
369
+ ;
370
+ @ claT
371
+ ;
372
+ @ 'lastchngTeble'name claT
373
+ ;
374
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
375
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
376
+ style_footer();Usereea"zT
377
+ ;
378
+ @ claT
379
+ ;
380
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
381
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
382
+ style_footer();
383
+}
384
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
385
+ ;
386
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
387
+ style_footer();
388
+}
389
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
390
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
391
+ "ELSE 'ERROR' END;"svg class="pie-chart"
392
+ @ svg class="pie-chart"
393
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
394
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
395
+ , "Sunday"
396
+ };
397
+
398
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
399
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
400
+ ;
401
+ @ claT
402
+ ;
403
+ @ ce><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
404
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
405
+ "ELSE 'ERROR' END;"svg class="pie-chart"
406
+ @ svg class="pie-chart"
407
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
408
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
409
+ , "Sunday"
410
+ };
411
+
412
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
413
+ ;
414
+ @ claT
415
+ e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
416
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
417
+ "ELSE 'ERROR' END;"svg class="pie-chart"
418
+ @ svg class="pie-chart"
419
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
420
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
421
+ , "Sunday"
422
+ };
423
+
424
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
425
+ ;
426
+ @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
427
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
428
+ "ELSE 'ERROR' END;"svg class="pie-chart"
429
+ @ svg class="pie-chart"
430
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
431
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
432
+ , "Sunday"
433
+ };
434
+
435
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
436
+ ;
437
+ element(zMenuName, zMenuName, "%s url_render(pUrl, zParBy File", ny TypeelpiechartTABLE peea"zT
438
+ ;
439
+ @ claT
440
+ ;
441
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
442
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
443
+ style_footer();
444
+}
445
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
446
+ ;
447
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
448
+ style_footer();
449
+}
450
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
451
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
452
+ "ELSE 'ERROR' END;"svg class="pie-chart"
453
+ @ svg class="pie-chart"
454
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
455
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
456
+ , "Sunday"
457
+ };
458
+
459
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
460
+ HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
461
+ ;
462
+ @ claT
463
+ ;
464
+ @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
465
+ azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
466
+ azYear[n] = fossil_strdup(,0));
467
+ azYear[n+1] = azYear[n];
468
+ if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) zYear = azYear[0];zT
469
+ ;
470
+ @ claT
471
+ ;
472
+ @ class='lastchngTeble'nameeea"zTuserlist","tT}
473
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
474
+ style_footer();
475
+}
476
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
477
+ ;
478
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
479
+ style_footer();
480
+}
481
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
482
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
483
+ "ELSE 'ERROR' END;"svg class="pie-chart"
484
+ @ svg class="pie-chart"
485
+ @ HQuery url;/* RL for various branch linksurl_initialize(&url, "reports");
486
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
487
+ , "Sunday"
488
+ };
489
+
490
+ ;mtime %% 7mt/*
491
+** A helper for the /reports family of pages which prints out a menu
492
+** of links for the various type=XXX flags. zCurrentViewName must be
493
+** the name/value of the 'view' parameter which is in effect at the
494
+** time this is called. e.g. if called from the 'byuser' view then
495
+** zCurrentViewName musa<br>?name=Teea"zT
496
+ ;g.zTop,;
497
+ @ claT
498
+ ;
499
+ @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
500
+ azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
501
+ azYear[n] = fossil_strdup(,0));
502
+ azYear[n+1] = azYear[n];
503
+ if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) ='lastchngTeble'nameeea"zTuserlist","tT}
504
+ style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
505
+ style_footer();
506
+}
507
+svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
508
+ ;
509
+ @ class='lastchngTable'nameeea"zTuserlist","tT}
510
+ style_footer();
511
+}
512
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
513
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
514
+ "ELSE 'ERROR' END;"svg class="pie-chart"
515
+ @ svg class="pie-chart"
516
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
517
+ cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
518
+ , "Sunday"
519
+ };
520
+
521
+ ;mtime %% 7mtimand not empty
522
+** class="pie-chart"slist","tT}
523
+ style_feeaclass='lastchngTable'nameeea"zTuserlist","tT}
524
+ style_footer();
525
+}
526
+center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
527
+ "UPDATE piechart SEWHEN 5 THEN 'Friday'"
528
+ "ELSE 'ERROR' END;"svg class="pie-chart"
529
+ @ svg class="pie-chart"
530
+ @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");Blob sql-chart"
531
+ @ HQuery /* SQo_url(&url);url_rese_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
532
+ , "Sunday"
533
+ };
534
+
535
+ ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Ge
--- a/src/statrep.c
+++ b/src/statrep.c
@@ -0,0 +1,535 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/statrep.c
+++ b/src/statrep.c
@@ -0,0 +1,535 @@
1 eea"zT
2 ;
3 @ claT
4 ;
5 @ class='lastchngTeble'nameeea"zTuserlist","tT}
6 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
7 style_footer();
8 }
9 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
10 ;
11 @ class='lastchngTable'nameeea"zTuserlist","tT}
12 style_footer();
13 }
14 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
15 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
16 "ELSE 'ERROR' END;"svg class="pie-chart"
17 @ svg class="pie-chart"
18 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
19 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
20 , "Sunday"
21 };
22
23 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
24 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
25 ;
26 @ claT
27 ;
28 @ ce><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
29 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
30 "ELSE 'ERROR' END;"svg class="pie-chart"
31 @ svg class="pie-chart"
32 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
33 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
34 , "Sunday"
35 };
36
37 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
38 ;
39 @ claT
40 e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
41 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
42 "ELSE 'ERROR' END;"svg class="pie-chart"
43 @ svg class="pie-chart"
44 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
45 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
46 , "Sunday"
47 };
48
49 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
50 ;
51 @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
52 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
53 "ELSE 'ERROR' END;"svg class="pie-chart"
54 @ svg class="pie-chart"
55 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
56 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
57 , "Sunday"
58 };
59
60 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
61 ;
62 element(zMenuName, zMenuName, "%s url_render(pUrl, zParBy File", ny TypeelpiechartTABLE peea"zT
63 ;
64 @ claT
65 ;
66 @ class='lastchngTeble'nameeea"zTuserlist","tT}
67 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
68 style_footer();
69 }
70 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
71 ;
72 @ class='lastchngTable'nameeea"zTuserlist","tT}
73 style_footer();
74 }
75 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
76 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
77 "ELSE 'ERROR' END;"svg class="pie-chart"
78 @ svg class="pie-chart"
79 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
80 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
81 , "Sunday"
82 };
83
84 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
85 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
86 ;
87 @ claT
88 ;
89 @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
90 azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
91 azYear[n] = fossil_strdup(,0));
92 azYear[n+1] = azYear[n];
93 if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) zYear = azYear[0];zT
94 ;
95 @ claT
96 ;
97 @ class='lastchngTeble'nameeea"zTuserlist","tT}
98 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
99 style_footer();
100 }
101 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
102 ;
103 @ class='lastchngTable'nameeea"zTuserlist","tT}
104 style_footer();
105 }
106 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
107 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
108 "ELSE 'ERROR' END;"svg class="pie-chart"
109 @ svg class="pie-chart"
110 @ HQuery url;/* RL for eventbranch linksurl_initialize(&url, "reports");
111 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
112 , "Sunday"
113 };
114
115 ;mtime %% 7mt/*
116 ** A helper for the /reports family of pages which prints out a menu
117 ** of links for the various type=XXX flags. zCurrentViewName must be
118 ** the name/value of the 'view' parameter which is in effect at the
119 ** time this is called. e.g. if called from the 'byuser' view then
120 ** zCurrentViewName must be "byuser". Any URL parameters which need to
121 ** be added to the generated URLs should be passed in zParam. The
122 ** caller is expected to have already encoded any zParam in event_types_menu(c><svg</centre>center><svg</centre> "Thursday",
123 , "Sunday"
124 };
125
126 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
127 ;
128 @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
129 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
130 "ELSE 'ERROR' END;"svg class="pie-chart"
131 @ svg class="pie-chart"uery url;/* URL for various branch linksurl_initialize(&url, "reports");
132 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>csnter><svg</centre> "Thursday",
133 , "Sunday"
134 };
135
136 ;mtime %% 7mtime %% 7Mg.zTop,MoTuesWednThur5Sunday eea"zT
137 ;
138 element(zMenuName, zMenuNameinsass="pie-chart"
139 @ HQuery url;/*ci'>checkin"2;"
140 "UPDATE piechareea"zT
141 ;
142 @ claT
143 ;
144 even class='lastchngTable'nameeea"zTuserlist","tT}
145 style_footer();e'>event; @ class='lastchngTeble'nameeea"zTuserlist","tT}
146 style_footer();
147 }
148 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
149 ;
150 @ class='lastchngTable'nameeea"zTuserlist","tT}
151 style_footer();
152 }
153 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
154 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
155 "ELSE 'ERROR' END;"svg class="pie-chart"
156 @ svg class="pie-chart"
157 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
158 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
159 , "Sunday"
160 };
161
162 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
163 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
164 ;
165 @ claT
166 ;
167 @ ce><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
168 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
169 "ELSE 'ERROR' END;"svg class="pie-chart"
170 @ svg class="pie-chart"
171 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
172 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
173 , "Sunday"
174 };
175
176 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
177 ;
178 @ claT
179 e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
180 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
181 "ELSE 'ERROR' END;"svg class="pie-chart"
182 @ svg class="pie-chart"
183 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
184 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
185 , "Sunday"
186 };
187
188 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
189 ;
190 @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
191 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
192 "ELSE 'ERROR' END;"svg class="pie-chart"
193 @ svg class="pie-chart"
194 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
195 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
196 , "Sunday"
197 };
198
199 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
200 ;
201 element(zMenuName, zMenuName, "%s url_render(pUrl, zParBy File", ny TypeelpiechartTABLE peea"zT
202 ;
203 @ claT
204 ;
205 @ class='lastchngTeble'nameeea"zTuserlist","tT}
206 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
207 style_footer();
208 }
209 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
210 ;
211 @ class='lastchngTable'nameeea"zTuserlist","tT}
212 style_footer();
213 }
214 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
215 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
216 "ELSE 'ERROR' END;"svg class="pie-chart"
217 @ svg class="pie-chart"
218 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
219 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
220 , "Sunday"
221 };
222
223 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
224 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
225 ;
226 @ claT
227 ;
228 @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
229 azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
230 azYear[n] = fossil_strdup(,0));
231 azYear[n+1] = azYear[n];
232 if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) zYear = azYear[0];zT
233 ;
234 @ claT
235 ;
236 @ class='lastchngTeble'nameeea"zTuserlist","tT}
237 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
238 style_footer();
239 }
240 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
241 ;
242 @ class='lastchngTable'nameeea"zTuserlist","tT}
243 style_footer();
244 }
245 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
246 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
247 "ELSE 'ERRsR' END;"svg class="pie-chart"
248 @ svg class="pie-chart"
249 @ Hg.zTop,HQuery url;/* RL for various branch linksurl_initialize(&url, "reports");
250 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
251 , "Sunday"
252 };
253
254 ;mtime %% 7mt/*
255 ** A helper for the /reports family of pages which prints out a menu
256 ** of links for the various type=XXX flags. zCurrentViewName must be
257 ** the name/value of the 'view' parameter which is in effect at the
258 ** time this is called. e.g. if called from the 'byuser' view then
259 ** zCurrentViewName must be "byuser". Any URL parameters which need to
260 ** be added to the generated URLs should be passed in zParam. The
261 ** caller is expected to have already encoded any zParam in event_types_menu(c><svg</centre>center><svg</centre> "Thursday",
262 , "Sunday"
263 };
264
265 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
266 ;
267 @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
268 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
269 "ELSE 'ERROR' END;"svg class="pie-chart"
270 @ svg class="pie-chart"uery url;/* URL for various branch linksurl_initialize(&url, "reports");
271 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
272 , "Sunday"
273 };
274
275 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
276 ;
277 element(zMenuName, zMenuNameinsass="pie-chart"
278 @ HQuery url;/*ci'>checkin"2;"
279 "UPDATE piechareea"zT
280 ;
281 @ claT
282 ;
283 @ class='lastchngTeble'nameeea"zTuserlist","tT}
284 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
285 style_footer();
286 }
287 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
288 ;
289 @ class='lastchngTable'nameeea"zTuserlist","tT}
290 style_footer();
291 }
292 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
293 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
294 "ELSE 'ERROR' END;"svg class="pie-chart"
295 @ svg class="pie-chart"
296 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
297 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
298 , "Sunday"
299 };
300
301 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
302 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
303 ;
304 @ claT
305 ;
306 @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
307 azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
308 azYear[n] = fossil_strdup(,0));
309 azYear[n+1] = azYear[n];
310 if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) ='lastchngTeble'nameeea"zTuserlist","tT}
311 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
312 style_footer();
313 }
314 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
315 ;
316 @ class='lastchngTable'nameeea"zTuserlist","tT}
317 style_footer();
318 }
319 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
320 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
321 "ELSE 'ERROR' END;"svg class="pie-chart"
322 @ svg class="pie-chart"
323 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
324 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
325 , "Sunday"
326 };
327
328 ;mtime %% 7mtimand not empty
329 ** class="pie-chart"slist","tT}
330 style_feeaclass='lastchngTable'nameeea"zTuserlist","tT}
331 style_footer();
332 }
333 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
334 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
335 "ELSE 'ERROR' END;"svg class="pie-chart"
336 @ svg class="pie-chart"
337 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");Blob sql-chart"
338 @ HQuery /* SQo_url(&url);url_rese_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
339 , "Sunday"
340 };
341
342 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
343 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
344 ;
345 @ claT
346 ;
347 @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
348 azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
349 azYear[n] = fossil_strdup(,0));
350 azYear[n+1] = azYear[n];
351 if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) ='lastchngTeble'nameeea"zTuserlist","tT}
352 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
353 style_footer();
354 }
355 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
356 ;
357 @ class='lastchngTable'nameeea"zTuserlist","tT}
358 unday"
359 } NULL );
360 header, "s) by yearL for various branchmtime %% 7mtime %% 7MoTuesWedme=TABLE piechart(amt,labelpie);
361 blob_append_sql(&sqlr5Sunday eea"zT
362 ;
363 @e><htimeframe,a"/center><svg/centeea"zincludeMonth if( PB("pie") ){ cgi_query_paramete
364 " ySizeArraySizeArraySizeeea"zT
365 ;
366 @ claT
367 ;
368 @"zT
369 ;
370 @ claT
371 ;
372 @ 'lastchngTeble'name claT
373 ;
374 @ class='lastchngTeble'nameeea"zTuserlist","tT}
375 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
376 style_footer();Usereea"zT
377 ;
378 @ claT
379 ;
380 @ class='lastchngTeble'nameeea"zTuserlist","tT}
381 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
382 style_footer();
383 }
384 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
385 ;
386 @ class='lastchngTable'nameeea"zTuserlist","tT}
387 style_footer();
388 }
389 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
390 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
391 "ELSE 'ERROR' END;"svg class="pie-chart"
392 @ svg class="pie-chart"
393 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
394 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
395 , "Sunday"
396 };
397
398 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
399 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
400 ;
401 @ claT
402 ;
403 @ ce><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
404 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
405 "ELSE 'ERROR' END;"svg class="pie-chart"
406 @ svg class="pie-chart"
407 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
408 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
409 , "Sunday"
410 };
411
412 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
413 ;
414 @ claT
415 e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
416 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
417 "ELSE 'ERROR' END;"svg class="pie-chart"
418 @ svg class="pie-chart"
419 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
420 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
421 , "Sunday"
422 };
423
424 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
425 ;
426 @e><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
427 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
428 "ELSE 'ERROR' END;"svg class="pie-chart"
429 @ svg class="pie-chart"
430 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
431 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
432 , "Sunday"
433 };
434
435 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday eea"zT
436 ;
437 element(zMenuName, zMenuName, "%s url_render(pUrl, zParBy File", ny TypeelpiechartTABLE peea"zT
438 ;
439 @ claT
440 ;
441 @ class='lastchngTeble'nameeea"zTuserlist","tT}
442 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
443 style_footer();
444 }
445 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
446 ;
447 @ class='lastchngTable'nameeea"zTuserlist","tT}
448 style_footer();
449 }
450 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
451 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
452 "ELSE 'ERROR' END;"svg class="pie-chart"
453 @ svg class="pie-chart"
454 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
455 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
456 , "Sunday"
457 };
458
459 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Generate a submenu element witrep_submenu(
460 HQuery *pUrl,/* Base URLe><hreea<br>?name=Teea"zT
461 ;
462 @ claT
463 ;
464 @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
465 azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
466 azYear[n] = fossil_strdup(,0));
467 azYear[n+1] = azYear[n];
468 if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) zYear = azYear[0];zT
469 ;
470 @ claT
471 ;
472 @ class='lastchngTeble'nameeea"zTuserlist","tT}
473 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
474 style_footer();
475 }
476 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
477 ;
478 @ class='lastchngTable'nameeea"zTuserlist","tT}
479 style_footer();
480 }
481 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
482 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
483 "ELSE 'ERROR' END;"svg class="pie-chart"
484 @ svg class="pie-chart"
485 @ HQuery url;/* RL for various branch linksurl_initialize(&url, "reports");
486 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
487 , "Sunday"
488 };
489
490 ;mtime %% 7mt/*
491 ** A helper for the /reports family of pages which prints out a menu
492 ** of links for the various type=XXX flags. zCurrentViewName must be
493 ** the name/value of the 'view' parameter which is in effect at the
494 ** time this is called. e.g. if called from the 'byuser' view then
495 ** zCurrentViewName musa<br>?name=Teea"zT
496 ;g.zTop,;
497 @ claT
498 ;
499 @ ce>4) AS yy ORDER BY y DESC", zUserName) ){
500 azYear = fossil_realloc(azYear, sizeof(char*)*(n+2));
501 azYear[n] = fossil_strdup(,0));
502 azYear[n+1] = azYear[n];
503 if( !isValidYear && fossil_strcmp(zYear,azYear[n])==0 ) ='lastchngTeble'nameeea"zTuserlist","tT}
504 style_footer(); @ class='lastchngTeble'nameeea"zTuserlist","tT}
505 style_footer();
506 }
507 svg class="pie-chart"svg class="pie-chart"ArraySizeArraySizeArraySizeeea"zT
508 ;
509 @ class='lastchngTable'nameeea"zTuserlist","tT}
510 style_footer();
511 }
512 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
513 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
514 "ELSE 'ERROR' END;"svg class="pie-chart"
515 @ svg class="pie-chart"
516 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");
517 cgi_query_parameters_to_url(&url);url_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
518 , "Sunday"
519 };
520
521 ;mtime %% 7mtimand not empty
522 ** class="pie-chart"slist","tT}
523 style_feeaclass='lastchngTable'nameeea"zTuserlist","tT}
524 style_footer();
525 }
526 center><svg/centre><hreea"/center><svg/centre><hreea<br>?name=TABLE piechart(amt,labelpiechartTABLE piechart(amt,labelpiechart)"2;"
527 "UPDATE piechart SEWHEN 5 THEN 'Friday'"
528 "ELSE 'ERROR' END;"svg class="pie-chart"
529 @ svg class="pie-chart"
530 @ HQuery url;/* URL for various branch linksurl_initialize(&url, "reports");Blob sql-chart"
531 @ HQuery /* SQo_url(&url);url_rese_reset(&urlcenter><svg</centre>center><svg</centre> "Thursday",
532 , "Sunday"
533 };
534
535 ;mtime %% 7mtime %% 7MoTuesWednThur5Sunday Ge
+92 -240
--- src/style.c
+++ src/style.c
@@ -46,10 +46,15 @@
4646
/*
4747
** remember, if a sidebox was used
4848
*/
4949
static int sideboxUsed = 0;
5050
51
+/*
52
+** Ad-unit styles.
53
+*/
54
+static unsigned adUnitFlags = 0;
55
+
5156
5257
/*
5358
** List of hyperlinks and forms that need to be resolved by javascript in
5459
** the footer.
5560
*/
@@ -284,11 +289,12 @@
284289
** Draw the header.
285290
*/
286291
void style_header(const char *zTitleFormat, ...){
287292
va_list ap;
288293
char *zTitle;
289
- const char *zHeader = db_get("header", (char*)zDefaultHeader);
294
+ const char *zHeader = db_get("header", 0);
295
+ if( zHeader==0 ) zHeader = builtin_text("skins/default/header.txt");
290296
login_check_credentials();
291297
292298
va_start(ap, zTitleFormat);
293299
zTitle = vmprintf(zTitleFormat, ap);
294300
va_end(ap);
@@ -343,34 +349,64 @@
343349
@ var e = document.getElementById(x);
344350
@ if(!e) throw new Error("Expecting element with ID "+x);
345351
@ else return e;}
346352
@ </script>
347353
}
354
+
355
+#if INTERFACE
356
+/* Allowed parameters for style_adunit() */
357
+#define ADUNIT_OFF 0x0001 /* Do not allow ads on this page */
358
+#define ADUNIT_RIGHT_OK 0x0002 /* Right-side vertical ads ok here */
359
+#endif
360
+
361
+/*
362
+** Various page implementations can invoke this interface to let the
363
+** style manager know what kinds of ads are appropriate for this page.
364
+*/
365
+void style_adunit_config(unsigned int mFlags){
366
+ adUnitFlags = mFlags;
367
+}
348368
349369
/*
350
-** Append ad unit text if appropriate.
370
+** Return the text of an ad-unit, if one should be rendered. Return
371
+** NULL if no ad-unit is desired.
372
+**
373
+** The *pAdFlag value might be set to ADUNIT_RIGHT_OK if this is
374
+** a right-hand vertical ad.
351375
*/
352
-static void style_ad_unit(void){
353
- const char *zAd;
376
+static const char *style_adunit_text(unsigned int *pAdFlag){
377
+ const char *zAd = 0;
378
+ *pAdFlag = 0;
379
+ if( adUnitFlags & ADUNIT_OFF ) return 0; /* Disallow ads on this page */
354380
if( g.perm.Admin && db_get_boolean("adunit-omit-if-admin",0) ){
355
- return;
381
+ return 0;
356382
}
357383
if( !login_is_nobody()
358384
&& fossil_strcmp(g.zLogin,"anonymous")!=0
359385
&& db_get_boolean("adunit-omit-if-user",0)
360386
){
361
- return;
387
+ return 0;
388
+ }
389
+ if( (adUnitFlags & ADUNIT_RIGHT_OK)!=0
390
+ && !fossil_all_whitespace(zAd = db_get("adunit-right", 0))
391
+ && !cgi_body_contains("<table")
392
+ ){
393
+ *pAdFlag = ADUNIT_RIGHT_OK;
394
+ return zAd;
395
+ }else if( !fossil_all_whitespace(zAd = db_get("adunit",0)) ){
396
+ return zAd;
362397
}
363
- zAd = db_get("adunit", 0);
364
- if( zAd ) cgi_append_content(zAd, -1);
398
+ return 0;
365399
}
366400
367401
/*
368402
** Draw the footer at the bottom of the page.
369403
*/
370404
void style_footer(void){
371405
const char *zFooter;
406
+ const char *zAd = 0;
407
+ unsigned int mAdFlags = 0;
372408
373409
if( !headerHasBeenGenerated ) return;
374410
375411
/* Go back and put the submenu at the top of the page. We delay the
376412
** creation of the submenu until the end so that we can add elements
@@ -389,12 +425,25 @@
389425
@ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a>
390426
}
391427
}
392428
@ </div>
393429
}
394
- style_ad_unit();
395
- @ <div class="content">
430
+
431
+ zAd = style_adunit_text(&mAdFlags);
432
+ if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
433
+ @ <div class="content adunit_right_container">
434
+ @ <div class="adunit_right">
435
+ cgi_append_content(zAd, -1);
436
+ @ </div>
437
+ }else{
438
+ if( zAd ){
439
+ @ <div class="adunit_banner">
440
+ cgi_append_content(zAd, -1);
441
+ @ </div>
442
+ }
443
+ @ <div class="content">
444
+ }
396445
cgi_destination(CGI_BODY);
397446
398447
if( sideboxUsed ){
399448
/* Put the footer at the bottom of the page.
400449
** the additional clear/both is needed to extend the content
@@ -406,11 +455,12 @@
406455
407456
/* Set the href= field on hyperlinks. Do this before the footer since
408457
** the footer will be generating </html> */
409458
style_resolve_href();
410459
411
- zFooter = db_get("footer", (char*)zDefaultFooter);
460
+ zFooter = db_get("footer", 0);
461
+ if( zFooter==0 ) zFooter = builtin_text("skins/default/footer.txt");
412462
if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
413463
Th_Render(zFooter);
414464
if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
415465
416466
/* Render trace log if TH1 tracing is enabled. */
@@ -436,230 +486,10 @@
436486
*/
437487
void style_sidebox_end(void){
438488
@ </div>
439489
}
440490
441
-/* @-comment: // */
442
-/*
443
-** The default page header.
444
-*/
445
-const char zDefaultHeader[] =
446
-@ <html>
447
-@ <head>
448
-@ <base href="$baseurl/$current_page" />
449
-@ <title>$<project_name>: $<title></title>
450
-@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
451
-@ href="$home/timeline.rss" />
452
-@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
453
-@ media="screen" />
454
-@ </head>
455
-@ <body>
456
-@ <div class="header">
457
-@ <div class="logo">
458
-@ <img src="$logo_image_url" alt="logo" />
459
-@ </div>
460
-@ <div class="title"><small>$<project_name></small><br />$<title></div>
461
-@ <div class="status"><th1>
462
-@ if {[info exists login]} {
463
-@ puts "Logged in as $login"
464
-@ } else {
465
-@ puts "Not logged in"
466
-@ }
467
-@ </th1></div>
468
-@ </div>
469
-@ <div class="mainmenu">
470
-@ <th1>
471
-@ html "<a href='$home$index_page'>Home</a>\n"
472
-@ if {[anycap jor]} {
473
-@ html "<a href='$home/timeline'>Timeline</a>\n"
474
-@ }
475
-@ if {[hascap oh]} {
476
-@ html "<a href='$home/tree?ci=tip'>Files</a>\n"
477
-@ }
478
-@ if {[hascap o]} {
479
-@ html "<a href='$home/brlist'>Branches</a>\n"
480
-@ html "<a href='$home/taglist'>Tags</a>\n"
481
-@ }
482
-@ if {[hascap r]} {
483
-@ html "<a href='$home/reportlist'>Tickets</a>\n"
484
-@ }
485
-@ if {[hascap j]} {
486
-@ html "<a href='$home/wiki'>Wiki</a>\n"
487
-@ }
488
-@ if {[hascap s]} {
489
-@ html "<a href='$home/setup'>Admin</a>\n"
490
-@ } elseif {[hascap a]} {
491
-@ html "<a href='$home/setup_ulist'>Users</a>\n"
492
-@ }
493
-@ if {[info exists login]} {
494
-@ html "<a href='$home/login'>Logout</a>\n"
495
-@ } else {
496
-@ html "<a href='$home/login'>Login</a>\n"
497
-@ }
498
-@ </th1></div>
499
-;
500
-
501
-/*
502
-** The default page footer
503
-*/
504
-const char zDefaultFooter[] =
505
-@ <div class="footer">
506
-@ This page was generated in about
507
-@ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
508
-@ Fossil version $manifest_version $manifest_date
509
-@ </div>
510
-@ </body></html>
511
-;
512
-
513
-/*
514
-** The default Cascading Style Sheet.
515
-** It's assembled by different strings for each class.
516
-** The default css contains all definitions.
517
-** The style sheet, send to the client only contains the ones,
518
-** not defined in the user defined css.
519
-*/
520
-const char zDefaultCSS[] =
521
-@ /* General settings for the entire page */
522
-@ body {
523
-@ margin: 0ex 1ex;
524
-@ padding: 0px;
525
-@ background-color: white;
526
-@ font-family: sans-serif;
527
-@ }
528
-@
529
-@ /* The project logo in the upper left-hand corner of each page */
530
-@ div.logo {
531
-@ display: table-cell;
532
-@ text-align: center;
533
-@ vertical-align: bottom;
534
-@ font-weight: bold;
535
-@ color: #558195;
536
-@ min-width: 200px;
537
-@ white-space: nowrap;
538
-@ }
539
-@
540
-@ /* The page title centered at the top of each page */
541
-@ div.title {
542
-@ display: table-cell;
543
-@ font-size: 2em;
544
-@ font-weight: bold;
545
-@ text-align: center;
546
-@ padding: 0 0 0 1em;
547
-@ color: #558195;
548
-@ vertical-align: bottom;
549
-@ width: 100%;
550
-@ }
551
-@
552
-@ /* The login status message in the top right-hand corner */
553
-@ div.status {
554
-@ display: table-cell;
555
-@ text-align: right;
556
-@ vertical-align: bottom;
557
-@ color: #558195;
558
-@ font-size: 0.8em;
559
-@ font-weight: bold;
560
-@ min-width: 200px;
561
-@ white-space: nowrap;
562
-@ }
563
-@
564
-@ /* The header across the top of the page */
565
-@ div.header {
566
-@ display: table;
567
-@ width: 100%;
568
-@ }
569
-@
570
-@ /* The main menu bar that appears at the top of the page beneath
571
-@ ** the header */
572
-@ div.mainmenu {
573
-@ padding: 5px 10px 5px 10px;
574
-@ font-size: 0.9em;
575
-@ font-weight: bold;
576
-@ text-align: center;
577
-@ letter-spacing: 1px;
578
-@ background-color: #558195;
579
-@ border-top-left-radius: 8px;
580
-@ border-top-right-radius: 8px;
581
-@ color: white;
582
-@ }
583
-@
584
-@ /* The submenu bar that *sometimes* appears below the main menu */
585
-@ div.submenu, div.sectionmenu {
586
-@ padding: 3px 10px 3px 0px;
587
-@ font-size: 0.9em;
588
-@ text-align: center;
589
-@ background-color: #456878;
590
-@ color: white;
591
-@ }
592
-@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
593
-@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
594
-@ padding: 3px 10px 3px 10px;
595
-@ color: white;
596
-@ text-decoration: none;
597
-@ }
598
-@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
599
-@ color: #558195;
600
-@ background-color: white;
601
-@ }
602
-@
603
-@ /* All page content from the bottom of the menu or submenu down to
604
-@ ** the footer */
605
-@ div.content {
606
-@ padding: 0ex 1ex 1ex 1ex;
607
-@ border: solid #aaa;
608
-@ border-width: 1px;
609
-@ }
610
-@
611
-@ /* Some pages have section dividers */
612
-@ div.section {
613
-@ margin-bottom: 0px;
614
-@ margin-top: 1em;
615
-@ padding: 1px 1px 1px 1px;
616
-@ font-size: 1.2em;
617
-@ font-weight: bold;
618
-@ background-color: #558195;
619
-@ color: white;
620
-@ white-space: nowrap;
621
-@ }
622
-@
623
-@ /* The "Date" that occurs on the left hand side of timelines */
624
-@ div.divider {
625
-@ background: #a1c4d4;
626
-@ border: 2px #558195 solid;
627
-@ font-size: 1em; font-weight: normal;
628
-@ padding: .25em;
629
-@ margin: .2em 0 .2em 0;
630
-@ float: left;
631
-@ clear: left;
632
-@ white-space: nowrap;
633
-@ }
634
-@
635
-@ /* The footer at the very bottom of the page */
636
-@ div.footer {
637
-@ clear: both;
638
-@ font-size: 0.8em;
639
-@ padding: 5px 10px 5px 10px;
640
-@ text-align: right;
641
-@ background-color: #558195;
642
-@ border-bottom-left-radius: 8px;
643
-@ border-bottom-right-radius: 8px;
644
-@ color: white;
645
-@ }
646
-@
647
-@ /* Hyperlink colors in the footer */
648
-@ div.footer a { color: white; }
649
-@ div.footer a:link { color: white; }
650
-@ div.footer a:visited { color: white; }
651
-@ div.footer a:hover { background-color: white; color: #558195; }
652
-@
653
-@ /* verbatim blocks */
654
-@ pre.verbatim {
655
-@ background-color: #f5f5f5;
656
-@ padding: 0.5em;
657
-@ white-space: pre-wrap;
658
-@}
659
-;
660
-
661491
662492
/* The following table contains bits of default CSS that must
663493
** be included if they are not found in the application-defined
664494
** CSS.
665495
*/
@@ -666,14 +496,10 @@
666496
const struct strctCssDefaults {
667497
const char *elementClass; /* Name of element needed */
668498
const char *comment; /* Comment text */
669499
const char *value; /* CSS text */
670500
} cssDefaultList[] = {
671
- { "",
672
- "",
673
- zDefaultCSS
674
- },
675501
{ "div.sidebox",
676502
"The nomenclature sidebox for branches,..",
677503
@ float: right;
678504
@ background-color: white;
679505
@ border-width: medium;
@@ -1270,10 +1096,39 @@
12701096
"fileage third column (the check-in comment)",
12711097
@ word-break: break-all;
12721098
@ word-wrap: break-word;
12731099
@ max-width: 50%;
12741100
},
1101
+ { ".brlist table", "The list of branches",
1102
+ @ border-spacing: 0;
1103
+ },
1104
+ { ".brlist table th", "Branch list table headers",
1105
+ @ text-align: left;
1106
+ @ padding: 0px 1em 0.5ex 0px;
1107
+ },
1108
+ { ".brlist table td", "Branch list table headers",
1109
+ @ padding: 0px 2em 0px 0px;
1110
+ @ white-space: nowrap;
1111
+ },
1112
+ { "th.sort:after",
1113
+ "General styles for sortable column marker",
1114
+ @ margin-left: .4em;
1115
+ @ cursor: pointer;
1116
+ @ text-shadow: 0 0 0 #000; /* Makes arrow darker */
1117
+ },
1118
+ { "th.sort.none:after",
1119
+ "None sort column marker",
1120
+ @ content: '\2666';
1121
+ },
1122
+ { "th.sort.asc:after",
1123
+ "Ascending sort column marker",
1124
+ @ content: '\2193';
1125
+ },
1126
+ { "th.sort.desc:after",
1127
+ "Descending sort column marker",
1128
+ @ content: '\2191';
1129
+ },
12751130
{ 0,
12761131
0,
12771132
0
12781133
}
12791134
};
@@ -1282,19 +1137,16 @@
12821137
** Append all of the default CSS to the CGI output.
12831138
*/
12841139
void cgi_append_default_css(void) {
12851140
int i;
12861141
1142
+ cgi_printf("%s", builtin_text("skins/default/css.txt"));
12871143
for( i=0; cssDefaultList[i].elementClass; i++ ){
12881144
if( cssDefaultList[i].elementClass[0] ){
12891145
cgi_printf("/* %s */\n%s {\n%s\n}\n\n",
12901146
cssDefaultList[i].comment,
12911147
cssDefaultList[i].elementClass,
1292
- cssDefaultList[i].value
1293
- );
1294
- }else{
1295
- cgi_printf("%s",
12961148
cssDefaultList[i].value
12971149
);
12981150
}
12991151
}
13001152
}
@@ -1305,11 +1157,11 @@
13051157
void page_style_css(void){
13061158
Blob css;
13071159
int i;
13081160
13091161
cgi_set_content_type("text/css");
1310
- blob_init(&css, db_get("css",(char*)zDefaultCSS), -1);
1162
+ blob_init(&css, db_get("css",(char*)builtin_text("skins/default/css.txt")), -1);
13111163
13121164
/* add special missing definitions */
13131165
for(i=1; cssDefaultList[i].elementClass; i++){
13141166
if( strstr(blob_str(&css), cssDefaultList[i].elementClass)==0 ){
13151167
blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
13161168
--- src/style.c
+++ src/style.c
@@ -46,10 +46,15 @@
46 /*
47 ** remember, if a sidebox was used
48 */
49 static int sideboxUsed = 0;
50
 
 
 
 
 
51
52 /*
53 ** List of hyperlinks and forms that need to be resolved by javascript in
54 ** the footer.
55 */
@@ -284,11 +289,12 @@
284 ** Draw the header.
285 */
286 void style_header(const char *zTitleFormat, ...){
287 va_list ap;
288 char *zTitle;
289 const char *zHeader = db_get("header", (char*)zDefaultHeader);
 
290 login_check_credentials();
291
292 va_start(ap, zTitleFormat);
293 zTitle = vmprintf(zTitleFormat, ap);
294 va_end(ap);
@@ -343,34 +349,64 @@
343 @ var e = document.getElementById(x);
344 @ if(!e) throw new Error("Expecting element with ID "+x);
345 @ else return e;}
346 @ </script>
347 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
349 /*
350 ** Append ad unit text if appropriate.
 
 
 
 
351 */
352 static void style_ad_unit(void){
353 const char *zAd;
 
 
354 if( g.perm.Admin && db_get_boolean("adunit-omit-if-admin",0) ){
355 return;
356 }
357 if( !login_is_nobody()
358 && fossil_strcmp(g.zLogin,"anonymous")!=0
359 && db_get_boolean("adunit-omit-if-user",0)
360 ){
361 return;
 
 
 
 
 
 
 
 
 
362 }
363 zAd = db_get("adunit", 0);
364 if( zAd ) cgi_append_content(zAd, -1);
365 }
366
367 /*
368 ** Draw the footer at the bottom of the page.
369 */
370 void style_footer(void){
371 const char *zFooter;
 
 
372
373 if( !headerHasBeenGenerated ) return;
374
375 /* Go back and put the submenu at the top of the page. We delay the
376 ** creation of the submenu until the end so that we can add elements
@@ -389,12 +425,25 @@
389 @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a>
390 }
391 }
392 @ </div>
393 }
394 style_ad_unit();
395 @ <div class="content">
 
 
 
 
 
 
 
 
 
 
 
 
 
396 cgi_destination(CGI_BODY);
397
398 if( sideboxUsed ){
399 /* Put the footer at the bottom of the page.
400 ** the additional clear/both is needed to extend the content
@@ -406,11 +455,12 @@
406
407 /* Set the href= field on hyperlinks. Do this before the footer since
408 ** the footer will be generating </html> */
409 style_resolve_href();
410
411 zFooter = db_get("footer", (char*)zDefaultFooter);
 
412 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
413 Th_Render(zFooter);
414 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
415
416 /* Render trace log if TH1 tracing is enabled. */
@@ -436,230 +486,10 @@
436 */
437 void style_sidebox_end(void){
438 @ </div>
439 }
440
441 /* @-comment: // */
442 /*
443 ** The default page header.
444 */
445 const char zDefaultHeader[] =
446 @ <html>
447 @ <head>
448 @ <base href="$baseurl/$current_page" />
449 @ <title>$<project_name>: $<title></title>
450 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
451 @ href="$home/timeline.rss" />
452 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
453 @ media="screen" />
454 @ </head>
455 @ <body>
456 @ <div class="header">
457 @ <div class="logo">
458 @ <img src="$logo_image_url" alt="logo" />
459 @ </div>
460 @ <div class="title"><small>$<project_name></small><br />$<title></div>
461 @ <div class="status"><th1>
462 @ if {[info exists login]} {
463 @ puts "Logged in as $login"
464 @ } else {
465 @ puts "Not logged in"
466 @ }
467 @ </th1></div>
468 @ </div>
469 @ <div class="mainmenu">
470 @ <th1>
471 @ html "<a href='$home$index_page'>Home</a>\n"
472 @ if {[anycap jor]} {
473 @ html "<a href='$home/timeline'>Timeline</a>\n"
474 @ }
475 @ if {[hascap oh]} {
476 @ html "<a href='$home/tree?ci=tip'>Files</a>\n"
477 @ }
478 @ if {[hascap o]} {
479 @ html "<a href='$home/brlist'>Branches</a>\n"
480 @ html "<a href='$home/taglist'>Tags</a>\n"
481 @ }
482 @ if {[hascap r]} {
483 @ html "<a href='$home/reportlist'>Tickets</a>\n"
484 @ }
485 @ if {[hascap j]} {
486 @ html "<a href='$home/wiki'>Wiki</a>\n"
487 @ }
488 @ if {[hascap s]} {
489 @ html "<a href='$home/setup'>Admin</a>\n"
490 @ } elseif {[hascap a]} {
491 @ html "<a href='$home/setup_ulist'>Users</a>\n"
492 @ }
493 @ if {[info exists login]} {
494 @ html "<a href='$home/login'>Logout</a>\n"
495 @ } else {
496 @ html "<a href='$home/login'>Login</a>\n"
497 @ }
498 @ </th1></div>
499 ;
500
501 /*
502 ** The default page footer
503 */
504 const char zDefaultFooter[] =
505 @ <div class="footer">
506 @ This page was generated in about
507 @ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
508 @ Fossil version $manifest_version $manifest_date
509 @ </div>
510 @ </body></html>
511 ;
512
513 /*
514 ** The default Cascading Style Sheet.
515 ** It's assembled by different strings for each class.
516 ** The default css contains all definitions.
517 ** The style sheet, send to the client only contains the ones,
518 ** not defined in the user defined css.
519 */
520 const char zDefaultCSS[] =
521 @ /* General settings for the entire page */
522 @ body {
523 @ margin: 0ex 1ex;
524 @ padding: 0px;
525 @ background-color: white;
526 @ font-family: sans-serif;
527 @ }
528 @
529 @ /* The project logo in the upper left-hand corner of each page */
530 @ div.logo {
531 @ display: table-cell;
532 @ text-align: center;
533 @ vertical-align: bottom;
534 @ font-weight: bold;
535 @ color: #558195;
536 @ min-width: 200px;
537 @ white-space: nowrap;
538 @ }
539 @
540 @ /* The page title centered at the top of each page */
541 @ div.title {
542 @ display: table-cell;
543 @ font-size: 2em;
544 @ font-weight: bold;
545 @ text-align: center;
546 @ padding: 0 0 0 1em;
547 @ color: #558195;
548 @ vertical-align: bottom;
549 @ width: 100%;
550 @ }
551 @
552 @ /* The login status message in the top right-hand corner */
553 @ div.status {
554 @ display: table-cell;
555 @ text-align: right;
556 @ vertical-align: bottom;
557 @ color: #558195;
558 @ font-size: 0.8em;
559 @ font-weight: bold;
560 @ min-width: 200px;
561 @ white-space: nowrap;
562 @ }
563 @
564 @ /* The header across the top of the page */
565 @ div.header {
566 @ display: table;
567 @ width: 100%;
568 @ }
569 @
570 @ /* The main menu bar that appears at the top of the page beneath
571 @ ** the header */
572 @ div.mainmenu {
573 @ padding: 5px 10px 5px 10px;
574 @ font-size: 0.9em;
575 @ font-weight: bold;
576 @ text-align: center;
577 @ letter-spacing: 1px;
578 @ background-color: #558195;
579 @ border-top-left-radius: 8px;
580 @ border-top-right-radius: 8px;
581 @ color: white;
582 @ }
583 @
584 @ /* The submenu bar that *sometimes* appears below the main menu */
585 @ div.submenu, div.sectionmenu {
586 @ padding: 3px 10px 3px 0px;
587 @ font-size: 0.9em;
588 @ text-align: center;
589 @ background-color: #456878;
590 @ color: white;
591 @ }
592 @ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
593 @ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
594 @ padding: 3px 10px 3px 10px;
595 @ color: white;
596 @ text-decoration: none;
597 @ }
598 @ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
599 @ color: #558195;
600 @ background-color: white;
601 @ }
602 @
603 @ /* All page content from the bottom of the menu or submenu down to
604 @ ** the footer */
605 @ div.content {
606 @ padding: 0ex 1ex 1ex 1ex;
607 @ border: solid #aaa;
608 @ border-width: 1px;
609 @ }
610 @
611 @ /* Some pages have section dividers */
612 @ div.section {
613 @ margin-bottom: 0px;
614 @ margin-top: 1em;
615 @ padding: 1px 1px 1px 1px;
616 @ font-size: 1.2em;
617 @ font-weight: bold;
618 @ background-color: #558195;
619 @ color: white;
620 @ white-space: nowrap;
621 @ }
622 @
623 @ /* The "Date" that occurs on the left hand side of timelines */
624 @ div.divider {
625 @ background: #a1c4d4;
626 @ border: 2px #558195 solid;
627 @ font-size: 1em; font-weight: normal;
628 @ padding: .25em;
629 @ margin: .2em 0 .2em 0;
630 @ float: left;
631 @ clear: left;
632 @ white-space: nowrap;
633 @ }
634 @
635 @ /* The footer at the very bottom of the page */
636 @ div.footer {
637 @ clear: both;
638 @ font-size: 0.8em;
639 @ padding: 5px 10px 5px 10px;
640 @ text-align: right;
641 @ background-color: #558195;
642 @ border-bottom-left-radius: 8px;
643 @ border-bottom-right-radius: 8px;
644 @ color: white;
645 @ }
646 @
647 @ /* Hyperlink colors in the footer */
648 @ div.footer a { color: white; }
649 @ div.footer a:link { color: white; }
650 @ div.footer a:visited { color: white; }
651 @ div.footer a:hover { background-color: white; color: #558195; }
652 @
653 @ /* verbatim blocks */
654 @ pre.verbatim {
655 @ background-color: #f5f5f5;
656 @ padding: 0.5em;
657 @ white-space: pre-wrap;
658 @}
659 ;
660
661
662 /* The following table contains bits of default CSS that must
663 ** be included if they are not found in the application-defined
664 ** CSS.
665 */
@@ -666,14 +496,10 @@
666 const struct strctCssDefaults {
667 const char *elementClass; /* Name of element needed */
668 const char *comment; /* Comment text */
669 const char *value; /* CSS text */
670 } cssDefaultList[] = {
671 { "",
672 "",
673 zDefaultCSS
674 },
675 { "div.sidebox",
676 "The nomenclature sidebox for branches,..",
677 @ float: right;
678 @ background-color: white;
679 @ border-width: medium;
@@ -1270,10 +1096,39 @@
1270 "fileage third column (the check-in comment)",
1271 @ word-break: break-all;
1272 @ word-wrap: break-word;
1273 @ max-width: 50%;
1274 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1275 { 0,
1276 0,
1277 0
1278 }
1279 };
@@ -1282,19 +1137,16 @@
1282 ** Append all of the default CSS to the CGI output.
1283 */
1284 void cgi_append_default_css(void) {
1285 int i;
1286
 
1287 for( i=0; cssDefaultList[i].elementClass; i++ ){
1288 if( cssDefaultList[i].elementClass[0] ){
1289 cgi_printf("/* %s */\n%s {\n%s\n}\n\n",
1290 cssDefaultList[i].comment,
1291 cssDefaultList[i].elementClass,
1292 cssDefaultList[i].value
1293 );
1294 }else{
1295 cgi_printf("%s",
1296 cssDefaultList[i].value
1297 );
1298 }
1299 }
1300 }
@@ -1305,11 +1157,11 @@
1305 void page_style_css(void){
1306 Blob css;
1307 int i;
1308
1309 cgi_set_content_type("text/css");
1310 blob_init(&css, db_get("css",(char*)zDefaultCSS), -1);
1311
1312 /* add special missing definitions */
1313 for(i=1; cssDefaultList[i].elementClass; i++){
1314 if( strstr(blob_str(&css), cssDefaultList[i].elementClass)==0 ){
1315 blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
1316
--- src/style.c
+++ src/style.c
@@ -46,10 +46,15 @@
46 /*
47 ** remember, if a sidebox was used
48 */
49 static int sideboxUsed = 0;
50
51 /*
52 ** Ad-unit styles.
53 */
54 static unsigned adUnitFlags = 0;
55
56
57 /*
58 ** List of hyperlinks and forms that need to be resolved by javascript in
59 ** the footer.
60 */
@@ -284,11 +289,12 @@
289 ** Draw the header.
290 */
291 void style_header(const char *zTitleFormat, ...){
292 va_list ap;
293 char *zTitle;
294 const char *zHeader = db_get("header", 0);
295 if( zHeader==0 ) zHeader = builtin_text("skins/default/header.txt");
296 login_check_credentials();
297
298 va_start(ap, zTitleFormat);
299 zTitle = vmprintf(zTitleFormat, ap);
300 va_end(ap);
@@ -343,34 +349,64 @@
349 @ var e = document.getElementById(x);
350 @ if(!e) throw new Error("Expecting element with ID "+x);
351 @ else return e;}
352 @ </script>
353 }
354
355 #if INTERFACE
356 /* Allowed parameters for style_adunit() */
357 #define ADUNIT_OFF 0x0001 /* Do not allow ads on this page */
358 #define ADUNIT_RIGHT_OK 0x0002 /* Right-side vertical ads ok here */
359 #endif
360
361 /*
362 ** Various page implementations can invoke this interface to let the
363 ** style manager know what kinds of ads are appropriate for this page.
364 */
365 void style_adunit_config(unsigned int mFlags){
366 adUnitFlags = mFlags;
367 }
368
369 /*
370 ** Return the text of an ad-unit, if one should be rendered. Return
371 ** NULL if no ad-unit is desired.
372 **
373 ** The *pAdFlag value might be set to ADUNIT_RIGHT_OK if this is
374 ** a right-hand vertical ad.
375 */
376 static const char *style_adunit_text(unsigned int *pAdFlag){
377 const char *zAd = 0;
378 *pAdFlag = 0;
379 if( adUnitFlags & ADUNIT_OFF ) return 0; /* Disallow ads on this page */
380 if( g.perm.Admin && db_get_boolean("adunit-omit-if-admin",0) ){
381 return 0;
382 }
383 if( !login_is_nobody()
384 && fossil_strcmp(g.zLogin,"anonymous")!=0
385 && db_get_boolean("adunit-omit-if-user",0)
386 ){
387 return 0;
388 }
389 if( (adUnitFlags & ADUNIT_RIGHT_OK)!=0
390 && !fossil_all_whitespace(zAd = db_get("adunit-right", 0))
391 && !cgi_body_contains("<table")
392 ){
393 *pAdFlag = ADUNIT_RIGHT_OK;
394 return zAd;
395 }else if( !fossil_all_whitespace(zAd = db_get("adunit",0)) ){
396 return zAd;
397 }
398 return 0;
 
399 }
400
401 /*
402 ** Draw the footer at the bottom of the page.
403 */
404 void style_footer(void){
405 const char *zFooter;
406 const char *zAd = 0;
407 unsigned int mAdFlags = 0;
408
409 if( !headerHasBeenGenerated ) return;
410
411 /* Go back and put the submenu at the top of the page. We delay the
412 ** creation of the submenu until the end so that we can add elements
@@ -389,12 +425,25 @@
425 @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a>
426 }
427 }
428 @ </div>
429 }
430
431 zAd = style_adunit_text(&mAdFlags);
432 if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
433 @ <div class="content adunit_right_container">
434 @ <div class="adunit_right">
435 cgi_append_content(zAd, -1);
436 @ </div>
437 }else{
438 if( zAd ){
439 @ <div class="adunit_banner">
440 cgi_append_content(zAd, -1);
441 @ </div>
442 }
443 @ <div class="content">
444 }
445 cgi_destination(CGI_BODY);
446
447 if( sideboxUsed ){
448 /* Put the footer at the bottom of the page.
449 ** the additional clear/both is needed to extend the content
@@ -406,11 +455,12 @@
455
456 /* Set the href= field on hyperlinks. Do this before the footer since
457 ** the footer will be generating </html> */
458 style_resolve_href();
459
460 zFooter = db_get("footer", 0);
461 if( zFooter==0 ) zFooter = builtin_text("skins/default/footer.txt");
462 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
463 Th_Render(zFooter);
464 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
465
466 /* Render trace log if TH1 tracing is enabled. */
@@ -436,230 +486,10 @@
486 */
487 void style_sidebox_end(void){
488 @ </div>
489 }
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
492 /* The following table contains bits of default CSS that must
493 ** be included if they are not found in the application-defined
494 ** CSS.
495 */
@@ -666,14 +496,10 @@
496 const struct strctCssDefaults {
497 const char *elementClass; /* Name of element needed */
498 const char *comment; /* Comment text */
499 const char *value; /* CSS text */
500 } cssDefaultList[] = {
 
 
 
 
501 { "div.sidebox",
502 "The nomenclature sidebox for branches,..",
503 @ float: right;
504 @ background-color: white;
505 @ border-width: medium;
@@ -1270,10 +1096,39 @@
1096 "fileage third column (the check-in comment)",
1097 @ word-break: break-all;
1098 @ word-wrap: break-word;
1099 @ max-width: 50%;
1100 },
1101 { ".brlist table", "The list of branches",
1102 @ border-spacing: 0;
1103 },
1104 { ".brlist table th", "Branch list table headers",
1105 @ text-align: left;
1106 @ padding: 0px 1em 0.5ex 0px;
1107 },
1108 { ".brlist table td", "Branch list table headers",
1109 @ padding: 0px 2em 0px 0px;
1110 @ white-space: nowrap;
1111 },
1112 { "th.sort:after",
1113 "General styles for sortable column marker",
1114 @ margin-left: .4em;
1115 @ cursor: pointer;
1116 @ text-shadow: 0 0 0 #000; /* Makes arrow darker */
1117 },
1118 { "th.sort.none:after",
1119 "None sort column marker",
1120 @ content: '\2666';
1121 },
1122 { "th.sort.asc:after",
1123 "Ascending sort column marker",
1124 @ content: '\2193';
1125 },
1126 { "th.sort.desc:after",
1127 "Descending sort column marker",
1128 @ content: '\2191';
1129 },
1130 { 0,
1131 0,
1132 0
1133 }
1134 };
@@ -1282,19 +1137,16 @@
1137 ** Append all of the default CSS to the CGI output.
1138 */
1139 void cgi_append_default_css(void) {
1140 int i;
1141
1142 cgi_printf("%s", builtin_text("skins/default/css.txt"));
1143 for( i=0; cssDefaultList[i].elementClass; i++ ){
1144 if( cssDefaultList[i].elementClass[0] ){
1145 cgi_printf("/* %s */\n%s {\n%s\n}\n\n",
1146 cssDefaultList[i].comment,
1147 cssDefaultList[i].elementClass,
 
 
 
 
1148 cssDefaultList[i].value
1149 );
1150 }
1151 }
1152 }
@@ -1305,11 +1157,11 @@
1157 void page_style_css(void){
1158 Blob css;
1159 int i;
1160
1161 cgi_set_content_type("text/css");
1162 blob_init(&css, db_get("css",(char*)builtin_text("skins/default/css.txt")), -1);
1163
1164 /* add special missing definitions */
1165 for(i=1; cssDefaultList[i].elementClass; i++){
1166 if( strstr(blob_str(&css), cssDefaultList[i].elementClass)==0 ){
1167 blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
1168
+5 -5
--- src/sync.c
+++ src/sync.c
@@ -48,11 +48,11 @@
4848
}
4949
}else{
5050
/* Autosync defaults on. To make it default off, "return" here. */
5151
}
5252
url_parse(0, URL_REMEMBER);
53
- if( g.url.protocol==0 ) return 0;
53
+ if( g.url.protocol==0 ) return 0;
5454
if( g.url.user!=0 && g.url.passwd==0 ){
5555
g.url.passwd = unobscure(db_get("last-sync-pw", 0));
5656
g.url.flags |= URL_PROMPT_PW;
5757
url_prompt_for_password();
5858
}
@@ -61,11 +61,11 @@
6161
#if 0 /* Disabled for now */
6262
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
6363
/* When doing an automatic pull, also automatically pull shuns from
6464
** the server if pull_shuns is enabled.
6565
**
66
- ** TODO: What happens if the shun list gets really big?
66
+ ** TODO: What happens if the shun list gets really big?
6767
** Maybe the shunning list should only be pulled on every 10th
6868
** autosync, or something?
6969
*/
7070
configSync = CONFIGSET_SHUN;
7171
}
@@ -186,11 +186,11 @@
186186
*/
187187
void pull_cmd(void){
188188
unsigned configFlags = 0;
189189
unsigned syncFlags = SYNC_PULL;
190190
process_sync_args(&configFlags, &syncFlags);
191
-
191
+
192192
/* We should be done with options.. */
193193
verify_all_options();
194194
195195
client_sync(syncFlags, configFlags, 0);
196196
}
@@ -221,11 +221,11 @@
221221
*/
222222
void push_cmd(void){
223223
unsigned configFlags = 0;
224224
unsigned syncFlags = SYNC_PUSH;
225225
process_sync_args(&configFlags, &syncFlags);
226
-
226
+
227227
/* We should be done with options.. */
228228
verify_all_options();
229229
230230
if( db_get_boolean("dont-push",0) ){
231231
fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
@@ -261,11 +261,11 @@
261261
*/
262262
void sync_cmd(void){
263263
unsigned configFlags = 0;
264264
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
265265
process_sync_args(&configFlags, &syncFlags);
266
-
266
+
267267
/* We should be done with options.. */
268268
verify_all_options();
269269
270270
if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
271271
client_sync(syncFlags, configFlags, 0);
272272
--- src/sync.c
+++ src/sync.c
@@ -48,11 +48,11 @@
48 }
49 }else{
50 /* Autosync defaults on. To make it default off, "return" here. */
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.url.protocol==0 ) return 0;
54 if( g.url.user!=0 && g.url.passwd==0 ){
55 g.url.passwd = unobscure(db_get("last-sync-pw", 0));
56 g.url.flags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
@@ -61,11 +61,11 @@
61 #if 0 /* Disabled for now */
62 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
63 /* When doing an automatic pull, also automatically pull shuns from
64 ** the server if pull_shuns is enabled.
65 **
66 ** TODO: What happens if the shun list gets really big?
67 ** Maybe the shunning list should only be pulled on every 10th
68 ** autosync, or something?
69 */
70 configSync = CONFIGSET_SHUN;
71 }
@@ -186,11 +186,11 @@
186 */
187 void pull_cmd(void){
188 unsigned configFlags = 0;
189 unsigned syncFlags = SYNC_PULL;
190 process_sync_args(&configFlags, &syncFlags);
191
192 /* We should be done with options.. */
193 verify_all_options();
194
195 client_sync(syncFlags, configFlags, 0);
196 }
@@ -221,11 +221,11 @@
221 */
222 void push_cmd(void){
223 unsigned configFlags = 0;
224 unsigned syncFlags = SYNC_PUSH;
225 process_sync_args(&configFlags, &syncFlags);
226
227 /* We should be done with options.. */
228 verify_all_options();
229
230 if( db_get_boolean("dont-push",0) ){
231 fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
@@ -261,11 +261,11 @@
261 */
262 void sync_cmd(void){
263 unsigned configFlags = 0;
264 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
265 process_sync_args(&configFlags, &syncFlags);
266
267 /* We should be done with options.. */
268 verify_all_options();
269
270 if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
271 client_sync(syncFlags, configFlags, 0);
272
--- src/sync.c
+++ src/sync.c
@@ -48,11 +48,11 @@
48 }
49 }else{
50 /* Autosync defaults on. To make it default off, "return" here. */
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.url.protocol==0 ) return 0;
54 if( g.url.user!=0 && g.url.passwd==0 ){
55 g.url.passwd = unobscure(db_get("last-sync-pw", 0));
56 g.url.flags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
@@ -61,11 +61,11 @@
61 #if 0 /* Disabled for now */
62 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
63 /* When doing an automatic pull, also automatically pull shuns from
64 ** the server if pull_shuns is enabled.
65 **
66 ** TODO: What happens if the shun list gets really big?
67 ** Maybe the shunning list should only be pulled on every 10th
68 ** autosync, or something?
69 */
70 configSync = CONFIGSET_SHUN;
71 }
@@ -186,11 +186,11 @@
186 */
187 void pull_cmd(void){
188 unsigned configFlags = 0;
189 unsigned syncFlags = SYNC_PULL;
190 process_sync_args(&configFlags, &syncFlags);
191
192 /* We should be done with options.. */
193 verify_all_options();
194
195 client_sync(syncFlags, configFlags, 0);
196 }
@@ -221,11 +221,11 @@
221 */
222 void push_cmd(void){
223 unsigned configFlags = 0;
224 unsigned syncFlags = SYNC_PUSH;
225 process_sync_args(&configFlags, &syncFlags);
226
227 /* We should be done with options.. */
228 verify_all_options();
229
230 if( db_get_boolean("dont-push",0) ){
231 fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
@@ -261,11 +261,11 @@
261 */
262 void sync_cmd(void){
263 unsigned configFlags = 0;
264 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
265 process_sync_args(&configFlags, &syncFlags);
266
267 /* We should be done with options.. */
268 verify_all_options();
269
270 if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
271 client_sync(syncFlags, configFlags, 0);
272
+3 -2
--- src/tag.c
+++ src/tag.c
@@ -269,11 +269,11 @@
269269
}
270270
g.markPrivate = content_is_private(rid);
271271
zValue = g.argc==5 ? g.argv[4] : 0;
272272
db_begin_transaction();
273273
tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
274
- db_end_transaction(0);
274
+ db_end_transaction(0);
275275
}
276276
277277
/*
278278
** Add a control record to the repository that either creates
279279
** or cancels a tag.
@@ -535,11 +535,11 @@
535535
tag_cmd_usage:
536536
usage("add|cancel|find|list ...");
537537
}
538538
539539
/*
540
-** WEBPAGE: /taglist
540
+** WEBPAGE: taglist
541541
*/
542542
void taglist_page(void){
543543
Stmt q;
544544
545545
login_check_credentials();
@@ -546,10 +546,11 @@
546546
if( !g.perm.Read ){
547547
login_needed();
548548
}
549549
login_anonymous_available();
550550
style_header("Tags");
551
+ style_adunit_config(ADUNIT_RIGHT_OK);
551552
style_submenu_element("Timeline", "Timeline", "tagtimeline");
552553
@ <h2>Non-propagating tags:</h2>
553554
db_prepare(&q,
554555
"SELECT substr(tagname,5)"
555556
" FROM tag"
556557
--- src/tag.c
+++ src/tag.c
@@ -269,11 +269,11 @@
269 }
270 g.markPrivate = content_is_private(rid);
271 zValue = g.argc==5 ? g.argv[4] : 0;
272 db_begin_transaction();
273 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
274 db_end_transaction(0);
275 }
276
277 /*
278 ** Add a control record to the repository that either creates
279 ** or cancels a tag.
@@ -535,11 +535,11 @@
535 tag_cmd_usage:
536 usage("add|cancel|find|list ...");
537 }
538
539 /*
540 ** WEBPAGE: /taglist
541 */
542 void taglist_page(void){
543 Stmt q;
544
545 login_check_credentials();
@@ -546,10 +546,11 @@
546 if( !g.perm.Read ){
547 login_needed();
548 }
549 login_anonymous_available();
550 style_header("Tags");
 
551 style_submenu_element("Timeline", "Timeline", "tagtimeline");
552 @ <h2>Non-propagating tags:</h2>
553 db_prepare(&q,
554 "SELECT substr(tagname,5)"
555 " FROM tag"
556
--- src/tag.c
+++ src/tag.c
@@ -269,11 +269,11 @@
269 }
270 g.markPrivate = content_is_private(rid);
271 zValue = g.argc==5 ? g.argv[4] : 0;
272 db_begin_transaction();
273 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
274 db_end_transaction(0);
275 }
276
277 /*
278 ** Add a control record to the repository that either creates
279 ** or cancels a tag.
@@ -535,11 +535,11 @@
535 tag_cmd_usage:
536 usage("add|cancel|find|list ...");
537 }
538
539 /*
540 ** WEBPAGE: taglist
541 */
542 void taglist_page(void){
543 Stmt q;
544
545 login_check_credentials();
@@ -546,10 +546,11 @@
546 if( !g.perm.Read ){
547 login_needed();
548 }
549 login_anonymous_available();
550 style_header("Tags");
551 style_adunit_config(ADUNIT_RIGHT_OK);
552 style_submenu_element("Timeline", "Timeline", "tagtimeline");
553 @ <h2>Non-propagating tags:</h2>
554 db_prepare(&q,
555 "SELECT substr(tagname,5)"
556 " FROM tag"
557
+1 -1
--- src/th.h
+++ src/th.h
@@ -1,8 +1,8 @@
11
22
/* This header file defines the external interface to the custom Scripting
3
-** Language (TH) interpreter. TH is very similar to TCL but is not an
3
+** Language (TH) interpreter. TH is very similar to Tcl but is not an
44
** exact clone.
55
*/
66
77
/*
88
** Before creating an interpreter, the application must allocate and
99
--- src/th.h
+++ src/th.h
@@ -1,8 +1,8 @@
1
2 /* This header file defines the external interface to the custom Scripting
3 ** Language (TH) interpreter. TH is very similar to TCL but is not an
4 ** exact clone.
5 */
6
7 /*
8 ** Before creating an interpreter, the application must allocate and
9
--- src/th.h
+++ src/th.h
@@ -1,8 +1,8 @@
1
2 /* This header file defines the external interface to the custom Scripting
3 ** Language (TH) interpreter. TH is very similar to Tcl but is not an
4 ** exact clone.
5 */
6
7 /*
8 ** Before creating an interpreter, the application must allocate and
9
+2 -2
--- src/th_main.c
+++ src/th_main.c
@@ -391,15 +391,15 @@
391391
int argc,
392392
const char **argv,
393393
int *argl
394394
){
395395
int rc = 0;
396
- char const * zArg;
396
+ const char *zArg;
397397
if( argc!=2 ){
398398
return Th_WrongNumArgs(interp, "hasfeature STRING");
399399
}
400
- zArg = (char const*)argv[1];
400
+ zArg = (const char *)argv[1];
401401
if(NULL==zArg){
402402
/* placeholder for following ifdefs... */
403403
}
404404
#if defined(FOSSIL_ENABLE_SSL)
405405
else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){
406406
--- src/th_main.c
+++ src/th_main.c
@@ -391,15 +391,15 @@
391 int argc,
392 const char **argv,
393 int *argl
394 ){
395 int rc = 0;
396 char const * zArg;
397 if( argc!=2 ){
398 return Th_WrongNumArgs(interp, "hasfeature STRING");
399 }
400 zArg = (char const*)argv[1];
401 if(NULL==zArg){
402 /* placeholder for following ifdefs... */
403 }
404 #if defined(FOSSIL_ENABLE_SSL)
405 else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){
406
--- src/th_main.c
+++ src/th_main.c
@@ -391,15 +391,15 @@
391 int argc,
392 const char **argv,
393 int *argl
394 ){
395 int rc = 0;
396 const char *zArg;
397 if( argc!=2 ){
398 return Th_WrongNumArgs(interp, "hasfeature STRING");
399 }
400 zArg = (const char *)argv[1];
401 if(NULL==zArg){
402 /* placeholder for following ifdefs... */
403 }
404 #if defined(FOSSIL_ENABLE_SSL)
405 else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){
406
+13 -689
--- src/timeline.c
+++ src/timeline.c
@@ -87,10 +87,11 @@
8787
#define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
8888
#define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
8989
#define TIMELINE_UCOLOR 0x0080 /* Background color by user */
9090
#define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
9191
#define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */
92
+#define TIMELINE_SHOWRID 0x0400 /* Show RID values in addition to UUIDs */
9293
#endif
9394
9495
/*
9596
** Hash a string and use the hash to determine a background color.
9697
*/
@@ -359,20 +360,20 @@
359360
}
360361
}
361362
}
362363
if( zType[0]=='c' && (pGraph || (tmFlags & TIMELINE_BRCOLOR)!=0) ){
363364
int nParent = 0;
364
- int aParent[32];
365
+ int aParent[GR_MAX_RAIL];
365366
int gidx;
366367
static Stmt qparent;
367368
db_static_prepare(&qparent,
368369
"SELECT pid FROM plink"
369370
" WHERE cid=:rid AND pid NOT IN phantom"
370371
" ORDER BY isprim DESC /*sort*/"
371372
);
372373
db_bind_int(&qparent, ":rid", rid);
373
- while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){
374
+ while( db_step(&qparent)==SQLITE_ROW && nParent<ArraySize(aParent) ){
374375
aParent[nParent++] = db_column_int(&qparent, 0);
375376
}
376377
db_reset(&qparent);
377378
gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
378379
zUuid, isLeaf);
@@ -404,10 +405,13 @@
404405
}
405406
}else if( zType[0]=='e' && tagid ){
406407
hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
407408
}else if( (tmFlags & TIMELINE_ARTID)!=0 ){
408409
hyperlink_to_uuid(zUuid);
410
+ }
411
+ if( tmFlags & TIMELINE_SHOWRID ){
412
+ @ (%d(rid))
409413
}
410414
db_column_blob(pQuery, commentColumn, &comment);
411415
if( zType[0]!='c' ){
412416
/* Comments for anything other than a check-in are generated by
413417
** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
@@ -604,12 +608,12 @@
604608
** for the upward portion of a merge arrow. The merge arrow goes up
605609
** to the row identified by mu:. If this value is zero then
606610
** node has no merge children and no merge-out line is drawn.
607611
** mu: The id of the row which is the top of the merge-out arrow.
608612
** u: Draw a thick child-line out of the top of this node and up to
609
- ** the node with an id equal to this value. 0 if there is no
610
- ** thick-line riser.
613
+ ** the node with an id equal to this value. 0 if it is straight to
614
+ ** the top of the page, -1 if there is no thick-line riser.
611615
** f: 0x01: a leaf node.
612616
** au: An array of integers that define thick-line risers for branches.
613617
** The integers are in pairs. For each pair, the first integer is
614618
** is the rail on which the riser should run and the second integer
615619
** is the id of the node upto which the riser should run.
@@ -1031,11 +1035,10 @@
10311035
** nd Suppress "divider" lines
10321036
** v Show details of files changed
10331037
** f=UUID Show family (immediate parents and children) of UUID
10341038
** from=UUID Path from...
10351039
** to=UUID ... to this
1036
-** nomerge ... avoid merge links on the path
10371040
** shortest ... show only the shortest path
10381041
** uf=FUUID Show only checkins that use given file version
10391042
** brbg Background color from branch name
10401043
** ubg Background color from user
10411044
** namechng Show only checkins that filename changes
@@ -1070,11 +1073,11 @@
10701073
const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
10711074
const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (week-of-year)*/
10721075
int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
10731076
int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
10741077
int tagid; /* Tag ID */
1075
- int tmFlags; /* Timeline flags */
1078
+ int tmFlags = 0; /* Timeline flags */
10761079
const char *zThisTag = 0; /* Suppress links to this tag */
10771080
const char *zThisUser = 0; /* Suppress links to this user */
10781081
HQuery url; /* URL for various branch links */
10791082
int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */
10801083
int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */
@@ -1110,13 +1113,13 @@
11101113
){
11111114
zCirca = zBefore = zAfter = 0;
11121115
nEntry = -1;
11131116
}
11141117
if( zType[0]=='a' ){
1115
- tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
1118
+ tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH;
11161119
}else{
1117
- tmFlags = TIMELINE_GRAPH;
1120
+ tmFlags |= TIMELINE_GRAPH;
11181121
}
11191122
if( nEntry>0 ) url_add_parameter(&url, "n", mprintf("%d", nEntry));
11201123
if( P("ng")!=0 || zSearch!=0 ){
11211124
tmFlags &= ~TIMELINE_GRAPH;
11221125
url_add_parameter(&url, "ng", 0);
@@ -1206,10 +1209,11 @@
12061209
}else if( (p_rid || d_rid) && g.perm.Read ){
12071210
/* If p= or d= is present, ignore all other parameters other than n= */
12081211
char *zUuid;
12091212
int np, nd;
12101213
1214
+ tmFlags |= TIMELINE_DISJOINT;
12111215
if( p_rid && d_rid ){
12121216
if( p_rid!=d_rid ) p_rid = d_rid;
12131217
if( P("n")==0 ) nEntry = 10;
12141218
}
12151219
db_multi_exec(
@@ -1552,10 +1556,11 @@
15521556
}
15531557
}
15541558
if( P("showsql") ){
15551559
@ <blockquote>%h(blob_sql_text(&sql))</blockquote>
15561560
}
1561
+ if( P("showid") ) tmFlags |= TIMELINE_SHOWRID;
15571562
blob_zero(&sql);
15581563
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
15591564
@ <h2>%b(&desc)</h2>
15601565
blob_reset(&desc);
15611566
www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0);
@@ -2039,688 +2044,7 @@
20392044
const char *zUuid = db_column_text(&q, 0);
20402045
@ <li>
20412046
@ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&amp;d=%s(zUuid)&amp;unhide">%S(zUuid)</a>
20422047
}
20432048
db_finalize(&q);
2044
- style_footer();
2045
-}
2046
-
2047
-
2048
-/*
2049
-** Used by stats_report_xxxxx() to remember which type of events
2050
-** to show. Populated by stats_report_init_view() and holds the
2051
-** return value of that function.
2052
-*/
2053
-static int statsReportType = 0;
2054
-
2055
-/*
2056
-** Set by stats_report_init_view() to one of the y=XXXX values
2057
-** accepted by /timeline?y=XXXX.
2058
-*/
2059
-static const char *statsReportTimelineYFlag = NULL;
2060
-
2061
-/*
2062
-** Creates a TEMP VIEW named v_reports which is a wrapper around the
2063
-** EVENT table filtered on event.type. It looks for the request
2064
-** parameter 'type' (reminder: we "should" use 'y' for consistency
2065
-** with /timeline, but /reports uses 'y' for the year) and expects it
2066
-** to contain one of the conventional values from event.type or the
2067
-** value "all", which is treated as equivalent to "*". By default (if
2068
-** no 'y' is specified), "*" is assumed (that is also the default for
2069
-** invalid/unknown filter values). That 'y' filter is the one used for
2070
-** the event list. Note that a filter of "*" or "all" is equivalent to
2071
-** querying against the full event table. The view, however, adds an
2072
-** abstraction level to simplify the implementation code for the
2073
-** various /reports pages.
2074
-**
2075
-** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
2076
-** filter it applies, or '*' if no filter is applied (i.e. if "all" is
2077
-** used).
2078
-*/
2079
-static int stats_report_init_view(){
2080
- const char *zType = PD("type","*"); /* analog to /timeline?y=... */
2081
- const char *zRealType = NULL; /* normalized form of zType */
2082
- int rc = 0; /* result code */
2083
- assert( !statsReportType && "Must not be called more than once." );
2084
- switch( (zType && *zType) ? *zType : 0 ){
2085
- case 'c':
2086
- case 'C':
2087
- zRealType = "ci";
2088
- rc = *zRealType;
2089
- break;
2090
- case 'e':
2091
- case 'E':
2092
- zRealType = "e";
2093
- rc = *zRealType;
2094
- break;
2095
- case 'g':
2096
- case 'G':
2097
- zRealType = "g";
2098
- rc = *zRealType;
2099
- break;
2100
- case 't':
2101
- case 'T':
2102
- zRealType = "t";
2103
- rc = *zRealType;
2104
- break;
2105
- case 'w':
2106
- case 'W':
2107
- zRealType = "w";
2108
- rc = *zRealType;
2109
- break;
2110
- default:
2111
- rc = '*';
2112
- break;
2113
- }
2114
- assert(0 != rc);
2115
- if(zRealType){
2116
- statsReportTimelineYFlag = zRealType;
2117
- db_multi_exec("CREATE TEMP VIEW v_reports AS "
2118
- "SELECT * FROM event WHERE type GLOB %Q",
2119
- zRealType);
2120
- }else{
2121
- statsReportTimelineYFlag = "a";
2122
- db_multi_exec("CREATE TEMP VIEW v_reports AS "
2123
- "SELECT * FROM event");
2124
- }
2125
- return statsReportType = rc;
2126
-}
2127
-
2128
-/*
2129
-** Returns a string suitable (for a given value of suitable) for
2130
-** use in a label with the header of the /reports pages, dependent
2131
-** on the 'type' flag. See stats_report_init_view().
2132
-** The returned bytes are static.
2133
-*/
2134
-static const char *stats_report_label_for_type(){
2135
- assert( statsReportType && "Must call stats_report_init_view() first." );
2136
- switch( statsReportType ){
2137
- case 'c':
2138
- return "checkins";
2139
- case 'e':
2140
- return "events";
2141
- case 'w':
2142
- return "wiki changes";
2143
- case 't':
2144
- return "ticket changes";
2145
- case 'g':
2146
- return "tag changes";
2147
- default:
2148
- return "all types";
2149
- }
2150
-}
2151
-
2152
-/*
2153
-** A helper for the /reports family of pages which prints out a menu
2154
-** of links for the various type=XXX flags. zCurrentViewName must be
2155
-** the name/value of the 'view' parameter which is in effect at the
2156
-** time this is called. e.g. if called from the 'byuser' view then
2157
-** zCurrentViewName must be "byuser". Any URL parameters which need to
2158
-** be added to the generated URLs should be passed in zParam. The
2159
-** caller is expected to have already encoded any zParam in the %T or
2160
-** %t encoding. */
2161
-static void stats_report_event_types_menu(const char *zCurrentViewName,
2162
- const char *zParam){
2163
- char *zTop;
2164
- if(zParam && !*zParam){
2165
- zParam = NULL;
2166
- }
2167
- zTop = mprintf("%s/reports?view=%s%s%s", g.zTop, zCurrentViewName,
2168
- zParam ? "&" : "", zParam);
2169
- cgi_printf("<div>");
2170
- cgi_printf("<span>Types:</span> ");
2171
- if('*' == statsReportType){
2172
- cgi_printf(" <strong>all</strong>", zTop);
2173
- }else{
2174
- cgi_printf(" <a href='%s'>all</a>", zTop);
2175
- }
2176
- if('c' == statsReportType){
2177
- cgi_printf(" <strong>checkins</strong>", zTop);
2178
- }else{
2179
- cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
2180
- }
2181
- if('e' == statsReportType){
2182
- cgi_printf(" <strong>events</strong>", zTop);
2183
- }else{
2184
- cgi_printf(" <a href='%s&type=e'>events</a>", zTop);
2185
- }
2186
- if( 't' == statsReportType ){
2187
- cgi_printf(" <strong>tickets</strong>", zTop);
2188
- }else{
2189
- cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
2190
- }
2191
- if( 'g' == statsReportType ){
2192
- cgi_printf(" <strong>tags</strong>", zTop);
2193
- }else{
2194
- cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
2195
- }
2196
- if( 'w' == statsReportType ){
2197
- cgi_printf(" <strong>wiki</strong>", zTop);
2198
- }else{
2199
- cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
2200
- }
2201
- fossil_free(zTop);
2202
- cgi_printf("</div>");
2203
-}
2204
-
2205
-
2206
-/*
2207
-** Helper for stats_report_by_month_year(), which generates a list of
2208
-** week numbers. zTimeframe should be either a timeframe in the form YYYY
2209
-** or YYYY-MM.
2210
-*/
2211
-static void stats_report_output_week_links(const char *zTimeframe){
2212
- Stmt stWeek = empty_Stmt;
2213
- char yearPart[5] = {0,0,0,0,0};
2214
- memcpy(yearPart, zTimeframe, 4);
2215
- db_prepare(&stWeek,
2216
- "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
2217
- "count(*) AS n, "
2218
- "substr(date(mtime),1,%d) AS ym "
2219
- "FROM v_reports "
2220
- "WHERE ym=%Q AND mtime < current_timestamp "
2221
- "GROUP BY wk ORDER BY wk",
2222
- strlen(zTimeframe),
2223
- zTimeframe);
2224
- while( SQLITE_ROW == db_step(&stWeek) ){
2225
- const char *zWeek = db_column_text(&stWeek,0);
2226
- const int nCount = db_column_int(&stWeek,1);
2227
- cgi_printf("<a href='%s/timeline?"
2228
- "yw=%t-%t&n=%d&y=%s'>%s</a>",
2229
- g.zTop, yearPart, zWeek,
2230
- nCount, statsReportTimelineYFlag, zWeek);
2231
- }
2232
- db_finalize(&stWeek);
2233
-}
2234
-
2235
-/*
2236
-** Implements the "byyear" and "bymonth" reports for /reports.
2237
-** If includeMonth is true then it generates the "bymonth" report,
2238
-** else the "byyear" report. If zUserName is not NULL and not empty
2239
-** then the report is restricted to events created by the named user
2240
-** account.
2241
-*/
2242
-static void stats_report_by_month_year(char includeMonth,
2243
- char includeWeeks,
2244
- const char *zUserName){
2245
- Stmt query = empty_Stmt;
2246
- int nRowNumber = 0; /* current TR number */
2247
- int nEventTotal = 0; /* Total event count */
2248
- int rowClass = 0; /* counter for alternating
2249
- row colors */
2250
- Blob sql = empty_blob; /* SQL */
2251
- const char *zTimeLabel = includeMonth ? "Year/Month" : "Year";
2252
- char zPrevYear[5] = {0}; /* For keeping track of when
2253
- we change years while looping */
2254
- int nEventsPerYear = 0; /* Total event count for the
2255
- current year */
2256
- char showYearTotal = 0; /* Flag telling us when to show
2257
- the per-year event totals */
2258
- Blob header = empty_blob; /* Page header text */
2259
- int nMaxEvents = 1; /* for calculating length of graph
2260
- bars. */
2261
- int iterations = 0; /* number of weeks/months we iterate
2262
- over */
2263
- stats_report_init_view();
2264
- stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear", NULL );
2265
- blob_appendf(&header, "Timeline Events (%s) by year%s",
2266
- stats_report_label_for_type(),
2267
- (includeMonth ? "/month" : ""));
2268
- blob_append_sql(&sql,
2269
- "SELECT substr(date(mtime),1,%d) AS timeframe, "
2270
- "count(*) AS eventCount "
2271
- "FROM v_reports ",
2272
- includeMonth ? 7 : 4);
2273
- if(zUserName&&*zUserName){
2274
- blob_append_sql(&sql, " WHERE user=%Q ", zUserName);
2275
- blob_appendf(&header," for user %q", zUserName);
2276
- }
2277
- blob_append(&sql,
2278
- " GROUP BY timeframe"
2279
- " ORDER BY timeframe DESC",
2280
- -1);
2281
- db_prepare(&query, "%s", blob_sql_text(&sql));
2282
- blob_reset(&sql);
2283
- @ <h1>%b(&header)</h1>
2284
- @ <table class='statistics-report-table-events' border='0' cellpadding='2'
2285
- @ cellspacing='0' id='statsTable'>
2286
- @ <thead>
2287
- @ <th>%s(zTimeLabel)</th>
2288
- @ <th>Events</th>
2289
- @ <th width='90%%'><!-- relative commits graph --></th>
2290
- @ </thead><tbody>
2291
- blob_reset(&header);
2292
- /*
2293
- Run the query twice. The first time we calculate the maximum
2294
- number of events for a given row. Maybe someone with better SQL
2295
- Fu can re-implement this with a single query.
2296
- */
2297
- while( SQLITE_ROW == db_step(&query) ){
2298
- const int nCount = db_column_int(&query, 1);
2299
- if(nCount>nMaxEvents){
2300
- nMaxEvents = nCount;
2301
- }
2302
- ++iterations;
2303
- }
2304
- db_reset(&query);
2305
- while( SQLITE_ROW == db_step(&query) ){
2306
- const char *zTimeframe = db_column_text(&query, 0);
2307
- const int nCount = db_column_int(&query, 1);
2308
- int nSize = nCount
2309
- ? (int)(100 * nCount / nMaxEvents)
2310
- : 1;
2311
- showYearTotal = 0;
2312
- if(!nSize) nSize = 1;
2313
- if(includeMonth){
2314
- /* For Month/year view, add a separator for each distinct year. */
2315
- if(!*zPrevYear ||
2316
- (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
2317
- showYearTotal = *zPrevYear;
2318
- if(showYearTotal){
2319
- rowClass = ++nRowNumber % 2;
2320
- @ <tr class='row%d(rowClass)'>
2321
- @ <td></td>
2322
- @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
2323
- @</tr>
2324
- }
2325
- nEventsPerYear = 0;
2326
- memcpy(zPrevYear,zTimeframe,4);
2327
- rowClass = ++nRowNumber % 2;
2328
- @ <tr class='row%d(rowClass)'>
2329
- @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
2330
- @ </tr>
2331
- }
2332
- }
2333
- rowClass = ++nRowNumber % 2;
2334
- nEventTotal += nCount;
2335
- nEventsPerYear += nCount;
2336
- @<tr class='row%d(rowClass)'>
2337
- @ <td>
2338
- if(includeMonth){
2339
- cgi_printf("<a href='%s/timeline?"
2340
- "ym=%t&n=%d&y=%s",
2341
- g.zTop, zTimeframe, nCount,
2342
- statsReportTimelineYFlag );
2343
- /* Reminder: n=nCount is not actually correct for bymonth unless
2344
- that was the only user who caused events.
2345
- */
2346
- if( zUserName && *zUserName ){
2347
- cgi_printf("&u=%t", zUserName);
2348
- }
2349
- cgi_printf("' target='_new'>%s</a>",zTimeframe);
2350
- }else {
2351
- cgi_printf("<a href='?view=byweek&y=%s&type=%c",
2352
- zTimeframe, (char)statsReportType);
2353
- if(zUserName && *zUserName){
2354
- cgi_printf("&u=%t", zUserName);
2355
- }
2356
- cgi_printf("'>%s</a>", zTimeframe);
2357
- }
2358
- @ </td><td>%d(nCount)</td>
2359
- @ <td>
2360
- @ <div class='statistics-report-graph-line'
2361
- @ style='width:%d(nSize)%%;'>&nbsp;</div>
2362
- @ </td>
2363
- @</tr>
2364
- if(includeWeeks){
2365
- /* This part works fine for months but it terribly slow (4.5s on my PC),
2366
- so it's only shown for by-year for now. Suggestions/patches for
2367
- a better/faster layout are welcomed. */
2368
- @ <tr class='row%d(rowClass)'>
2369
- @ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td>
2370
- @ <td class='statistics-report-week-of-year-list'>
2371
- stats_report_output_week_links(zTimeframe);
2372
- @ </td></tr>
2373
- }
2374
-
2375
- /*
2376
- Potential improvement: calculate the min/max event counts and
2377
- use percent-based graph bars.
2378
- */
2379
- }
2380
- db_finalize(&query);
2381
- if(includeMonth && !showYearTotal && *zPrevYear){
2382
- /* Add final year total separator. */
2383
- rowClass = ++nRowNumber % 2;
2384
- @ <tr class='row%d(rowClass)'>
2385
- @ <td></td>
2386
- @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
2387
- @</tr>
2388
- }
2389
- @ </tbody></table>
2390
- if(nEventTotal){
2391
- const char *zAvgLabel = includeMonth ? "month" : "year";
2392
- int nAvg = iterations ? (nEventTotal/iterations) : 0;
2393
- @ <br><div>Total events: %d(nEventTotal)
2394
- @ <br>Average per active %s(zAvgLabel): %d(nAvg)
2395
- @ </div>
2396
- }
2397
- if( !includeMonth ){
2398
- output_table_sorting_javascript("statsTable","tnx");
2399
- }
2400
-}
2401
-
2402
-/*
2403
-** Implements the "byuser" view for /reports.
2404
-*/
2405
-static void stats_report_by_user(){
2406
- Stmt query = empty_Stmt;
2407
- int nRowNumber = 0; /* current TR number */
2408
- int nEventTotal = 0; /* Total event count */
2409
- int rowClass = 0; /* counter for alternating
2410
- row colors */
2411
- int nMaxEvents = 1; /* max number of events for
2412
- all rows. */
2413
- stats_report_init_view();
2414
- stats_report_event_types_menu("byuser", NULL);
2415
- db_prepare(&query,
2416
- "SELECT user, "
2417
- "COUNT(*) AS eventCount "
2418
- "FROM v_reports "
2419
- "GROUP BY user ORDER BY eventCount DESC");
2420
- @ <h1>Timeline Events
2421
- @ (%s(stats_report_label_for_type())) by User</h1>
2422
- @ <table class='statistics-report-table-events' border='0'
2423
- @ cellpadding='2' cellspacing='0' id='statsTable'>
2424
- @ <thead><tr>
2425
- @ <th>User</th>
2426
- @ <th>Events</th>
2427
- @ <th width='90%%'><!-- relative commits graph --></th>
2428
- @ </tr></thead><tbody>
2429
- while( SQLITE_ROW == db_step(&query) ){
2430
- const int nCount = db_column_int(&query, 1);
2431
- if(nCount>nMaxEvents){
2432
- nMaxEvents = nCount;
2433
- }
2434
- }
2435
- db_reset(&query);
2436
- while( SQLITE_ROW == db_step(&query) ){
2437
- const char *zUser = db_column_text(&query, 0);
2438
- const int nCount = db_column_int(&query, 1);
2439
- int nSize = nCount
2440
- ? (int)(100 * nCount / nMaxEvents)
2441
- : 0;
2442
- if(!nCount) continue /* arguable! Possible? */;
2443
- else if(!nSize) nSize = 1;
2444
- rowClass = ++nRowNumber % 2;
2445
- nEventTotal += nCount;
2446
- @<tr class='row%d(rowClass)'>
2447
- @ <td>
2448
- @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
2449
- @ </td><td>%d(nCount)</td>
2450
- @ <td>
2451
- @ <div class='statistics-report-graph-line'
2452
- @ style='width:%d(nSize)%%;'>&nbsp;</div>
2453
- @ </td>
2454
- @</tr>
2455
- /*
2456
- Potential improvement: calculate the min/max event counts and
2457
- use percent-based graph bars.
2458
- */
2459
- }
2460
- @ </tbody></table>
2461
- db_finalize(&query);
2462
- output_table_sorting_javascript("statsTable","tnx");
2463
-}
2464
-
2465
-/*
2466
-** Implements the "byweekday" view for /reports.
2467
-*/
2468
-static void stats_report_day_of_week(){
2469
- Stmt query = empty_Stmt;
2470
- int nRowNumber = 0; /* current TR number */
2471
- int nEventTotal = 0; /* Total event count */
2472
- int rowClass = 0; /* counter for alternating
2473
- row colors */
2474
- int nMaxEvents = 1; /* max number of events for
2475
- all rows. */
2476
- static const char *const daysOfWeek[] = {
2477
- "Monday", "Tuesday", "Wednesday", "Thursday",
2478
- "Friday", "Saturday", "Sunday"
2479
- };
2480
-
2481
- stats_report_init_view();
2482
- stats_report_event_types_menu("byweekday", NULL);
2483
- db_prepare(&query,
2484
- "SELECT cast(mtime %% 7 AS INTEGER) dow, "
2485
- "COUNT(*) AS eventCount "
2486
- "FROM v_reports "
2487
- "GROUP BY dow ORDER BY dow");
2488
- @ <h1>Timeline Events
2489
- @ (%s(stats_report_label_for_type())) by Day of the Week</h1>
2490
- @ <table class='statistics-report-table-events' border='0'
2491
- @ cellpadding='2' cellspacing='0' id='statsTable'>
2492
- @ <thead><tr>
2493
- @ <th>DoW</th>
2494
- @ <th>Day</th>
2495
- @ <th>Events</th>
2496
- @ <th width='90%%'><!-- relative commits graph --></th>
2497
- @ </tr></thead><tbody>
2498
- while( SQLITE_ROW == db_step(&query) ){
2499
- const int nCount = db_column_int(&query, 1);
2500
- if(nCount>nMaxEvents){
2501
- nMaxEvents = nCount;
2502
- }
2503
- }
2504
- db_reset(&query);
2505
- while( SQLITE_ROW == db_step(&query) ){
2506
- const int dayNum =db_column_int(&query, 0);
2507
- const int nCount = db_column_int(&query, 1);
2508
- int nSize = nCount
2509
- ? (int)(100 * nCount / nMaxEvents)
2510
- : 0;
2511
- if(!nCount) continue /* arguable! Possible? */;
2512
- else if(!nSize) nSize = 1;
2513
- rowClass = ++nRowNumber % 2;
2514
- nEventTotal += nCount;
2515
- @<tr class='row%d(rowClass)'>
2516
- @ <td>%d(dayNum)</td>
2517
- @ <td>%s(daysOfWeek[dayNum])</td>
2518
- @ <td>%d(nCount)</td>
2519
- @ <td>
2520
- @ <div class='statistics-report-graph-line'
2521
- @ style='width:%d(nSize)%%;'>&nbsp;</div>
2522
- @ </td>
2523
- @</tr>
2524
- }
2525
- @ </tbody></table>
2526
- db_finalize(&query);
2527
- output_table_sorting_javascript("statsTable","ntnx");
2528
-}
2529
-
2530
-
2531
-/*
2532
-** Helper for stats_report_by_month_year(), which generates a list of
2533
-** week numbers. zTimeframe should be either a timeframe in the form YYYY
2534
-** or YYYY-MM.
2535
-*/
2536
-static void stats_report_year_weeks(const char *zUserName){
2537
- const char *zYear = P("y");
2538
- int nYear = zYear ? strlen(zYear) : 0;
2539
- int i = 0;
2540
- Stmt qYears = empty_Stmt;
2541
- char *zDefaultYear = NULL;
2542
- Blob sql = empty_blob;
2543
- int nMaxEvents = 1; /* max number of events for
2544
- all rows. */
2545
- int iterations = 0; /* # of active time periods. */
2546
- stats_report_init_view();
2547
- if(4==nYear){
2548
- Blob urlParams = empty_blob;
2549
- blob_appendf(&urlParams, "y=%T", zYear);
2550
- stats_report_event_types_menu("byweek", blob_str(&urlParams));
2551
- blob_reset(&urlParams);
2552
- }else{
2553
- stats_report_event_types_menu("byweek", NULL);
2554
- }
2555
- blob_append(&sql,
2556
- "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2557
- "FROM v_reports WHERE 1 ", -1);
2558
- if(zUserName&&*zUserName){
2559
- blob_append_sql(&sql,"AND user=%Q ", zUserName);
2560
- }
2561
- blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2562
- db_prepare(&qYears, "%s", blob_sql_text(&sql));
2563
- blob_reset(&sql);
2564
- cgi_printf("Select year: ");
2565
- while( SQLITE_ROW == db_step(&qYears) ){
2566
- const char *zT = db_column_text(&qYears, 0);
2567
- if( i++ ){
2568
- cgi_printf(" ");
2569
- }
2570
- cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
2571
- (char)statsReportType);
2572
- if(zUserName && *zUserName){
2573
- cgi_printf("&user=%t",zUserName);
2574
- }
2575
- cgi_printf("'>%s</a>",zT);
2576
- }
2577
- db_finalize(&qYears);
2578
- cgi_printf("<br/>");
2579
- if(!zYear || !*zYear){
2580
- zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
2581
- zYear = zDefaultYear;
2582
- nYear = 4;
2583
- }
2584
- if(4 == nYear){
2585
- Stmt stWeek = empty_Stmt;
2586
- int rowCount = 0;
2587
- int total = 0;
2588
- Blob header = empty_blob;
2589
- blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
2590
- "of %h", stats_report_label_for_type(),
2591
- zYear);
2592
- blob_append_sql(&sql,
2593
- "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
2594
- "count(*) AS n "
2595
- "FROM v_reports "
2596
- "WHERE %Q=substr(date(mtime),1,4) "
2597
- "AND mtime < current_timestamp ",
2598
- zYear);
2599
- if(zUserName&&*zUserName){
2600
- blob_append_sql(&sql, " AND user=%Q ", zUserName);
2601
- blob_appendf(&header," for user %h", zUserName);
2602
- }
2603
- blob_append_sql(&sql, "GROUP BY wk ORDER BY wk DESC");
2604
- cgi_printf("<h1>%h</h1>", blob_str(&header));
2605
- blob_reset(&header);
2606
- cgi_printf("<table class='statistics-report-table-events' "
2607
- "border='0' cellpadding='2' width='100%%' "
2608
- "cellspacing='0' id='statsTable'>");
2609
- cgi_printf("<thead><tr>"
2610
- "<th>Week</th>"
2611
- "<th>Events</th>"
2612
- "<th width='90%%'><!-- relative commits graph --></th>"
2613
- "</tr></thead>"
2614
- "<tbody>");
2615
- db_prepare(&stWeek, "%s", blob_sql_text(&sql));
2616
- blob_reset(&sql);
2617
- while( SQLITE_ROW == db_step(&stWeek) ){
2618
- const int nCount = db_column_int(&stWeek, 1);
2619
- if(nCount>nMaxEvents){
2620
- nMaxEvents = nCount;
2621
- }
2622
- ++iterations;
2623
- }
2624
- db_reset(&stWeek);
2625
- while( SQLITE_ROW == db_step(&stWeek) ){
2626
- const char *zWeek = db_column_text(&stWeek,0);
2627
- const int nCount = db_column_int(&stWeek,1);
2628
- int nSize = nCount
2629
- ? (int)(100 * nCount / nMaxEvents)
2630
- : 0;
2631
- if(!nSize) nSize = 1;
2632
- total += nCount;
2633
- cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2634
- cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
2635
- g.zTop, zYear, zWeek, nCount,
2636
- statsReportTimelineYFlag);
2637
- if(zUserName && *zUserName){
2638
- cgi_printf("&u=%t",zUserName);
2639
- }
2640
- cgi_printf("'>%s</a></td>",zWeek);
2641
-
2642
- cgi_printf("<td>%d</td>",nCount);
2643
- cgi_printf("<td>");
2644
- if(nCount){
2645
- cgi_printf("<div class='statistics-report-graph-line'"
2646
- "style='width:%d%%;'>&nbsp;</div>",
2647
- nSize);
2648
- }
2649
- cgi_printf("</td></tr>");
2650
- }
2651
- db_finalize(&stWeek);
2652
- free(zDefaultYear);
2653
- cgi_printf("</tbody></table>");
2654
- if(total){
2655
- int nAvg = iterations ? (total/iterations) : 0;
2656
- cgi_printf("<br><div>Total events: %d<br>"
2657
- "Average per active week: %d</div>",
2658
- total, nAvg);
2659
- }
2660
- output_table_sorting_javascript("statsTable","tnx");
2661
- }
2662
-}
2663
-
2664
-/*
2665
-** WEBPAGE: reports
2666
-**
2667
-** Shows activity reports for the repository.
2668
-**
2669
-** Query Parameters:
2670
-**
2671
-** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2672
-** user=NAME Restricts statistics to the given user
2673
-** type=TYPE Restricts the report to a specific event type:
2674
-** ci (checkin), w (wiki), t (ticket), g (tag)
2675
-** Defaulting to all event types.
2676
-**
2677
-** The view-specific query parameters include:
2678
-**
2679
-** view=byweek:
2680
-**
2681
-** y=YYYY The year to report (default is the server's
2682
-** current year).
2683
-*/
2684
-void stats_report_page(){
2685
- HQuery url; /* URL for various branch links */
2686
- const char *zView = P("view"); /* Which view/report to show. */
2687
- const char *zUserName = P("user");
2688
-
2689
- login_check_credentials();
2690
- if( !g.perm.Read ){ login_needed(); return; }
2691
- if(!zUserName) zUserName = P("u");
2692
- url_initialize(&url, "reports");
2693
- if(zUserName && *zUserName){
2694
- url_add_parameter(&url,"user", zUserName);
2695
- timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
2696
- }
2697
- timeline_submenu(&url, "By Year", "view", "byyear", 0);
2698
- timeline_submenu(&url, "By Month", "view", "bymonth", 0);
2699
- timeline_submenu(&url, "By Week", "view", "byweek", 0);
2700
- timeline_submenu(&url, "By Weekday", "view", "byweekday", 0);
2701
- timeline_submenu(&url, "By User", "view", "byuser", "user");
2702
- url_reset(&url);
2703
- style_header("Activity Reports");
2704
- if(0==fossil_strcmp(zView,"byyear")){
2705
- stats_report_by_month_year(0, 0, zUserName);
2706
- }else if(0==fossil_strcmp(zView,"bymonth")){
2707
- stats_report_by_month_year(1, 0, zUserName);
2708
- }else if(0==fossil_strcmp(zView,"byweek")){
2709
- stats_report_year_weeks(zUserName);
2710
- }else if(0==fossil_strcmp(zView,"byuser")){
2711
- stats_report_by_user();
2712
- }else if(0==fossil_strcmp(zView,"byweekday")){
2713
- stats_report_day_of_week();
2714
- }else{
2715
- @ <h1>Select a report to show:</h1>
2716
- @ <ul>
2717
- @ <li><a href='?view=byyear'>Events by year</a></li>
2718
- @ <li><a href='?view=bymonth'>Events by month</a></li>
2719
- @ <li><a href='?view=byweek'>Events by calendar week</a></li>
2720
- @ <li><a href='?view=byweekday'>Events by day of the week</a></li>
2721
- @ <li><a href='?view=byuser'>Events by user</a></li>
2722
- @ </ul>
2723
- }
2724
-
27252049
style_footer();
27262050
}
27272051
--- src/timeline.c
+++ src/timeline.c
@@ -87,10 +87,11 @@
87 #define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
88 #define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
89 #define TIMELINE_UCOLOR 0x0080 /* Background color by user */
90 #define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
91 #define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */
 
92 #endif
93
94 /*
95 ** Hash a string and use the hash to determine a background color.
96 */
@@ -359,20 +360,20 @@
359 }
360 }
361 }
362 if( zType[0]=='c' && (pGraph || (tmFlags & TIMELINE_BRCOLOR)!=0) ){
363 int nParent = 0;
364 int aParent[32];
365 int gidx;
366 static Stmt qparent;
367 db_static_prepare(&qparent,
368 "SELECT pid FROM plink"
369 " WHERE cid=:rid AND pid NOT IN phantom"
370 " ORDER BY isprim DESC /*sort*/"
371 );
372 db_bind_int(&qparent, ":rid", rid);
373 while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){
374 aParent[nParent++] = db_column_int(&qparent, 0);
375 }
376 db_reset(&qparent);
377 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
378 zUuid, isLeaf);
@@ -404,10 +405,13 @@
404 }
405 }else if( zType[0]=='e' && tagid ){
406 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
407 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
408 hyperlink_to_uuid(zUuid);
 
 
 
409 }
410 db_column_blob(pQuery, commentColumn, &comment);
411 if( zType[0]!='c' ){
412 /* Comments for anything other than a check-in are generated by
413 ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
@@ -604,12 +608,12 @@
604 ** for the upward portion of a merge arrow. The merge arrow goes up
605 ** to the row identified by mu:. If this value is zero then
606 ** node has no merge children and no merge-out line is drawn.
607 ** mu: The id of the row which is the top of the merge-out arrow.
608 ** u: Draw a thick child-line out of the top of this node and up to
609 ** the node with an id equal to this value. 0 if there is no
610 ** thick-line riser.
611 ** f: 0x01: a leaf node.
612 ** au: An array of integers that define thick-line risers for branches.
613 ** The integers are in pairs. For each pair, the first integer is
614 ** is the rail on which the riser should run and the second integer
615 ** is the id of the node upto which the riser should run.
@@ -1031,11 +1035,10 @@
1031 ** nd Suppress "divider" lines
1032 ** v Show details of files changed
1033 ** f=UUID Show family (immediate parents and children) of UUID
1034 ** from=UUID Path from...
1035 ** to=UUID ... to this
1036 ** nomerge ... avoid merge links on the path
1037 ** shortest ... show only the shortest path
1038 ** uf=FUUID Show only checkins that use given file version
1039 ** brbg Background color from branch name
1040 ** ubg Background color from user
1041 ** namechng Show only checkins that filename changes
@@ -1070,11 +1073,11 @@
1070 const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
1071 const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (week-of-year)*/
1072 int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
1073 int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
1074 int tagid; /* Tag ID */
1075 int tmFlags; /* Timeline flags */
1076 const char *zThisTag = 0; /* Suppress links to this tag */
1077 const char *zThisUser = 0; /* Suppress links to this user */
1078 HQuery url; /* URL for various branch links */
1079 int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */
1080 int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */
@@ -1110,13 +1113,13 @@
1110 ){
1111 zCirca = zBefore = zAfter = 0;
1112 nEntry = -1;
1113 }
1114 if( zType[0]=='a' ){
1115 tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
1116 }else{
1117 tmFlags = TIMELINE_GRAPH;
1118 }
1119 if( nEntry>0 ) url_add_parameter(&url, "n", mprintf("%d", nEntry));
1120 if( P("ng")!=0 || zSearch!=0 ){
1121 tmFlags &= ~TIMELINE_GRAPH;
1122 url_add_parameter(&url, "ng", 0);
@@ -1206,10 +1209,11 @@
1206 }else if( (p_rid || d_rid) && g.perm.Read ){
1207 /* If p= or d= is present, ignore all other parameters other than n= */
1208 char *zUuid;
1209 int np, nd;
1210
 
1211 if( p_rid && d_rid ){
1212 if( p_rid!=d_rid ) p_rid = d_rid;
1213 if( P("n")==0 ) nEntry = 10;
1214 }
1215 db_multi_exec(
@@ -1552,10 +1556,11 @@
1552 }
1553 }
1554 if( P("showsql") ){
1555 @ <blockquote>%h(blob_sql_text(&sql))</blockquote>
1556 }
 
1557 blob_zero(&sql);
1558 db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
1559 @ <h2>%b(&desc)</h2>
1560 blob_reset(&desc);
1561 www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0);
@@ -2039,688 +2044,7 @@
2039 const char *zUuid = db_column_text(&q, 0);
2040 @ <li>
2041 @ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&amp;d=%s(zUuid)&amp;unhide">%S(zUuid)</a>
2042 }
2043 db_finalize(&q);
2044 style_footer();
2045 }
2046
2047
2048 /*
2049 ** Used by stats_report_xxxxx() to remember which type of events
2050 ** to show. Populated by stats_report_init_view() and holds the
2051 ** return value of that function.
2052 */
2053 static int statsReportType = 0;
2054
2055 /*
2056 ** Set by stats_report_init_view() to one of the y=XXXX values
2057 ** accepted by /timeline?y=XXXX.
2058 */
2059 static const char *statsReportTimelineYFlag = NULL;
2060
2061 /*
2062 ** Creates a TEMP VIEW named v_reports which is a wrapper around the
2063 ** EVENT table filtered on event.type. It looks for the request
2064 ** parameter 'type' (reminder: we "should" use 'y' for consistency
2065 ** with /timeline, but /reports uses 'y' for the year) and expects it
2066 ** to contain one of the conventional values from event.type or the
2067 ** value "all", which is treated as equivalent to "*". By default (if
2068 ** no 'y' is specified), "*" is assumed (that is also the default for
2069 ** invalid/unknown filter values). That 'y' filter is the one used for
2070 ** the event list. Note that a filter of "*" or "all" is equivalent to
2071 ** querying against the full event table. The view, however, adds an
2072 ** abstraction level to simplify the implementation code for the
2073 ** various /reports pages.
2074 **
2075 ** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
2076 ** filter it applies, or '*' if no filter is applied (i.e. if "all" is
2077 ** used).
2078 */
2079 static int stats_report_init_view(){
2080 const char *zType = PD("type","*"); /* analog to /timeline?y=... */
2081 const char *zRealType = NULL; /* normalized form of zType */
2082 int rc = 0; /* result code */
2083 assert( !statsReportType && "Must not be called more than once." );
2084 switch( (zType && *zType) ? *zType : 0 ){
2085 case 'c':
2086 case 'C':
2087 zRealType = "ci";
2088 rc = *zRealType;
2089 break;
2090 case 'e':
2091 case 'E':
2092 zRealType = "e";
2093 rc = *zRealType;
2094 break;
2095 case 'g':
2096 case 'G':
2097 zRealType = "g";
2098 rc = *zRealType;
2099 break;
2100 case 't':
2101 case 'T':
2102 zRealType = "t";
2103 rc = *zRealType;
2104 break;
2105 case 'w':
2106 case 'W':
2107 zRealType = "w";
2108 rc = *zRealType;
2109 break;
2110 default:
2111 rc = '*';
2112 break;
2113 }
2114 assert(0 != rc);
2115 if(zRealType){
2116 statsReportTimelineYFlag = zRealType;
2117 db_multi_exec("CREATE TEMP VIEW v_reports AS "
2118 "SELECT * FROM event WHERE type GLOB %Q",
2119 zRealType);
2120 }else{
2121 statsReportTimelineYFlag = "a";
2122 db_multi_exec("CREATE TEMP VIEW v_reports AS "
2123 "SELECT * FROM event");
2124 }
2125 return statsReportType = rc;
2126 }
2127
2128 /*
2129 ** Returns a string suitable (for a given value of suitable) for
2130 ** use in a label with the header of the /reports pages, dependent
2131 ** on the 'type' flag. See stats_report_init_view().
2132 ** The returned bytes are static.
2133 */
2134 static const char *stats_report_label_for_type(){
2135 assert( statsReportType && "Must call stats_report_init_view() first." );
2136 switch( statsReportType ){
2137 case 'c':
2138 return "checkins";
2139 case 'e':
2140 return "events";
2141 case 'w':
2142 return "wiki changes";
2143 case 't':
2144 return "ticket changes";
2145 case 'g':
2146 return "tag changes";
2147 default:
2148 return "all types";
2149 }
2150 }
2151
2152 /*
2153 ** A helper for the /reports family of pages which prints out a menu
2154 ** of links for the various type=XXX flags. zCurrentViewName must be
2155 ** the name/value of the 'view' parameter which is in effect at the
2156 ** time this is called. e.g. if called from the 'byuser' view then
2157 ** zCurrentViewName must be "byuser". Any URL parameters which need to
2158 ** be added to the generated URLs should be passed in zParam. The
2159 ** caller is expected to have already encoded any zParam in the %T or
2160 ** %t encoding. */
2161 static void stats_report_event_types_menu(const char *zCurrentViewName,
2162 const char *zParam){
2163 char *zTop;
2164 if(zParam && !*zParam){
2165 zParam = NULL;
2166 }
2167 zTop = mprintf("%s/reports?view=%s%s%s", g.zTop, zCurrentViewName,
2168 zParam ? "&" : "", zParam);
2169 cgi_printf("<div>");
2170 cgi_printf("<span>Types:</span> ");
2171 if('*' == statsReportType){
2172 cgi_printf(" <strong>all</strong>", zTop);
2173 }else{
2174 cgi_printf(" <a href='%s'>all</a>", zTop);
2175 }
2176 if('c' == statsReportType){
2177 cgi_printf(" <strong>checkins</strong>", zTop);
2178 }else{
2179 cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
2180 }
2181 if('e' == statsReportType){
2182 cgi_printf(" <strong>events</strong>", zTop);
2183 }else{
2184 cgi_printf(" <a href='%s&type=e'>events</a>", zTop);
2185 }
2186 if( 't' == statsReportType ){
2187 cgi_printf(" <strong>tickets</strong>", zTop);
2188 }else{
2189 cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
2190 }
2191 if( 'g' == statsReportType ){
2192 cgi_printf(" <strong>tags</strong>", zTop);
2193 }else{
2194 cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
2195 }
2196 if( 'w' == statsReportType ){
2197 cgi_printf(" <strong>wiki</strong>", zTop);
2198 }else{
2199 cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
2200 }
2201 fossil_free(zTop);
2202 cgi_printf("</div>");
2203 }
2204
2205
2206 /*
2207 ** Helper for stats_report_by_month_year(), which generates a list of
2208 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2209 ** or YYYY-MM.
2210 */
2211 static void stats_report_output_week_links(const char *zTimeframe){
2212 Stmt stWeek = empty_Stmt;
2213 char yearPart[5] = {0,0,0,0,0};
2214 memcpy(yearPart, zTimeframe, 4);
2215 db_prepare(&stWeek,
2216 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
2217 "count(*) AS n, "
2218 "substr(date(mtime),1,%d) AS ym "
2219 "FROM v_reports "
2220 "WHERE ym=%Q AND mtime < current_timestamp "
2221 "GROUP BY wk ORDER BY wk",
2222 strlen(zTimeframe),
2223 zTimeframe);
2224 while( SQLITE_ROW == db_step(&stWeek) ){
2225 const char *zWeek = db_column_text(&stWeek,0);
2226 const int nCount = db_column_int(&stWeek,1);
2227 cgi_printf("<a href='%s/timeline?"
2228 "yw=%t-%t&n=%d&y=%s'>%s</a>",
2229 g.zTop, yearPart, zWeek,
2230 nCount, statsReportTimelineYFlag, zWeek);
2231 }
2232 db_finalize(&stWeek);
2233 }
2234
2235 /*
2236 ** Implements the "byyear" and "bymonth" reports for /reports.
2237 ** If includeMonth is true then it generates the "bymonth" report,
2238 ** else the "byyear" report. If zUserName is not NULL and not empty
2239 ** then the report is restricted to events created by the named user
2240 ** account.
2241 */
2242 static void stats_report_by_month_year(char includeMonth,
2243 char includeWeeks,
2244 const char *zUserName){
2245 Stmt query = empty_Stmt;
2246 int nRowNumber = 0; /* current TR number */
2247 int nEventTotal = 0; /* Total event count */
2248 int rowClass = 0; /* counter for alternating
2249 row colors */
2250 Blob sql = empty_blob; /* SQL */
2251 const char *zTimeLabel = includeMonth ? "Year/Month" : "Year";
2252 char zPrevYear[5] = {0}; /* For keeping track of when
2253 we change years while looping */
2254 int nEventsPerYear = 0; /* Total event count for the
2255 current year */
2256 char showYearTotal = 0; /* Flag telling us when to show
2257 the per-year event totals */
2258 Blob header = empty_blob; /* Page header text */
2259 int nMaxEvents = 1; /* for calculating length of graph
2260 bars. */
2261 int iterations = 0; /* number of weeks/months we iterate
2262 over */
2263 stats_report_init_view();
2264 stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear", NULL );
2265 blob_appendf(&header, "Timeline Events (%s) by year%s",
2266 stats_report_label_for_type(),
2267 (includeMonth ? "/month" : ""));
2268 blob_append_sql(&sql,
2269 "SELECT substr(date(mtime),1,%d) AS timeframe, "
2270 "count(*) AS eventCount "
2271 "FROM v_reports ",
2272 includeMonth ? 7 : 4);
2273 if(zUserName&&*zUserName){
2274 blob_append_sql(&sql, " WHERE user=%Q ", zUserName);
2275 blob_appendf(&header," for user %q", zUserName);
2276 }
2277 blob_append(&sql,
2278 " GROUP BY timeframe"
2279 " ORDER BY timeframe DESC",
2280 -1);
2281 db_prepare(&query, "%s", blob_sql_text(&sql));
2282 blob_reset(&sql);
2283 @ <h1>%b(&header)</h1>
2284 @ <table class='statistics-report-table-events' border='0' cellpadding='2'
2285 @ cellspacing='0' id='statsTable'>
2286 @ <thead>
2287 @ <th>%s(zTimeLabel)</th>
2288 @ <th>Events</th>
2289 @ <th width='90%%'><!-- relative commits graph --></th>
2290 @ </thead><tbody>
2291 blob_reset(&header);
2292 /*
2293 Run the query twice. The first time we calculate the maximum
2294 number of events for a given row. Maybe someone with better SQL
2295 Fu can re-implement this with a single query.
2296 */
2297 while( SQLITE_ROW == db_step(&query) ){
2298 const int nCount = db_column_int(&query, 1);
2299 if(nCount>nMaxEvents){
2300 nMaxEvents = nCount;
2301 }
2302 ++iterations;
2303 }
2304 db_reset(&query);
2305 while( SQLITE_ROW == db_step(&query) ){
2306 const char *zTimeframe = db_column_text(&query, 0);
2307 const int nCount = db_column_int(&query, 1);
2308 int nSize = nCount
2309 ? (int)(100 * nCount / nMaxEvents)
2310 : 1;
2311 showYearTotal = 0;
2312 if(!nSize) nSize = 1;
2313 if(includeMonth){
2314 /* For Month/year view, add a separator for each distinct year. */
2315 if(!*zPrevYear ||
2316 (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
2317 showYearTotal = *zPrevYear;
2318 if(showYearTotal){
2319 rowClass = ++nRowNumber % 2;
2320 @ <tr class='row%d(rowClass)'>
2321 @ <td></td>
2322 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
2323 @</tr>
2324 }
2325 nEventsPerYear = 0;
2326 memcpy(zPrevYear,zTimeframe,4);
2327 rowClass = ++nRowNumber % 2;
2328 @ <tr class='row%d(rowClass)'>
2329 @ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
2330 @ </tr>
2331 }
2332 }
2333 rowClass = ++nRowNumber % 2;
2334 nEventTotal += nCount;
2335 nEventsPerYear += nCount;
2336 @<tr class='row%d(rowClass)'>
2337 @ <td>
2338 if(includeMonth){
2339 cgi_printf("<a href='%s/timeline?"
2340 "ym=%t&n=%d&y=%s",
2341 g.zTop, zTimeframe, nCount,
2342 statsReportTimelineYFlag );
2343 /* Reminder: n=nCount is not actually correct for bymonth unless
2344 that was the only user who caused events.
2345 */
2346 if( zUserName && *zUserName ){
2347 cgi_printf("&u=%t", zUserName);
2348 }
2349 cgi_printf("' target='_new'>%s</a>",zTimeframe);
2350 }else {
2351 cgi_printf("<a href='?view=byweek&y=%s&type=%c",
2352 zTimeframe, (char)statsReportType);
2353 if(zUserName && *zUserName){
2354 cgi_printf("&u=%t", zUserName);
2355 }
2356 cgi_printf("'>%s</a>", zTimeframe);
2357 }
2358 @ </td><td>%d(nCount)</td>
2359 @ <td>
2360 @ <div class='statistics-report-graph-line'
2361 @ style='width:%d(nSize)%%;'>&nbsp;</div>
2362 @ </td>
2363 @</tr>
2364 if(includeWeeks){
2365 /* This part works fine for months but it terribly slow (4.5s on my PC),
2366 so it's only shown for by-year for now. Suggestions/patches for
2367 a better/faster layout are welcomed. */
2368 @ <tr class='row%d(rowClass)'>
2369 @ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td>
2370 @ <td class='statistics-report-week-of-year-list'>
2371 stats_report_output_week_links(zTimeframe);
2372 @ </td></tr>
2373 }
2374
2375 /*
2376 Potential improvement: calculate the min/max event counts and
2377 use percent-based graph bars.
2378 */
2379 }
2380 db_finalize(&query);
2381 if(includeMonth && !showYearTotal && *zPrevYear){
2382 /* Add final year total separator. */
2383 rowClass = ++nRowNumber % 2;
2384 @ <tr class='row%d(rowClass)'>
2385 @ <td></td>
2386 @ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
2387 @</tr>
2388 }
2389 @ </tbody></table>
2390 if(nEventTotal){
2391 const char *zAvgLabel = includeMonth ? "month" : "year";
2392 int nAvg = iterations ? (nEventTotal/iterations) : 0;
2393 @ <br><div>Total events: %d(nEventTotal)
2394 @ <br>Average per active %s(zAvgLabel): %d(nAvg)
2395 @ </div>
2396 }
2397 if( !includeMonth ){
2398 output_table_sorting_javascript("statsTable","tnx");
2399 }
2400 }
2401
2402 /*
2403 ** Implements the "byuser" view for /reports.
2404 */
2405 static void stats_report_by_user(){
2406 Stmt query = empty_Stmt;
2407 int nRowNumber = 0; /* current TR number */
2408 int nEventTotal = 0; /* Total event count */
2409 int rowClass = 0; /* counter for alternating
2410 row colors */
2411 int nMaxEvents = 1; /* max number of events for
2412 all rows. */
2413 stats_report_init_view();
2414 stats_report_event_types_menu("byuser", NULL);
2415 db_prepare(&query,
2416 "SELECT user, "
2417 "COUNT(*) AS eventCount "
2418 "FROM v_reports "
2419 "GROUP BY user ORDER BY eventCount DESC");
2420 @ <h1>Timeline Events
2421 @ (%s(stats_report_label_for_type())) by User</h1>
2422 @ <table class='statistics-report-table-events' border='0'
2423 @ cellpadding='2' cellspacing='0' id='statsTable'>
2424 @ <thead><tr>
2425 @ <th>User</th>
2426 @ <th>Events</th>
2427 @ <th width='90%%'><!-- relative commits graph --></th>
2428 @ </tr></thead><tbody>
2429 while( SQLITE_ROW == db_step(&query) ){
2430 const int nCount = db_column_int(&query, 1);
2431 if(nCount>nMaxEvents){
2432 nMaxEvents = nCount;
2433 }
2434 }
2435 db_reset(&query);
2436 while( SQLITE_ROW == db_step(&query) ){
2437 const char *zUser = db_column_text(&query, 0);
2438 const int nCount = db_column_int(&query, 1);
2439 int nSize = nCount
2440 ? (int)(100 * nCount / nMaxEvents)
2441 : 0;
2442 if(!nCount) continue /* arguable! Possible? */;
2443 else if(!nSize) nSize = 1;
2444 rowClass = ++nRowNumber % 2;
2445 nEventTotal += nCount;
2446 @<tr class='row%d(rowClass)'>
2447 @ <td>
2448 @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
2449 @ </td><td>%d(nCount)</td>
2450 @ <td>
2451 @ <div class='statistics-report-graph-line'
2452 @ style='width:%d(nSize)%%;'>&nbsp;</div>
2453 @ </td>
2454 @</tr>
2455 /*
2456 Potential improvement: calculate the min/max event counts and
2457 use percent-based graph bars.
2458 */
2459 }
2460 @ </tbody></table>
2461 db_finalize(&query);
2462 output_table_sorting_javascript("statsTable","tnx");
2463 }
2464
2465 /*
2466 ** Implements the "byweekday" view for /reports.
2467 */
2468 static void stats_report_day_of_week(){
2469 Stmt query = empty_Stmt;
2470 int nRowNumber = 0; /* current TR number */
2471 int nEventTotal = 0; /* Total event count */
2472 int rowClass = 0; /* counter for alternating
2473 row colors */
2474 int nMaxEvents = 1; /* max number of events for
2475 all rows. */
2476 static const char *const daysOfWeek[] = {
2477 "Monday", "Tuesday", "Wednesday", "Thursday",
2478 "Friday", "Saturday", "Sunday"
2479 };
2480
2481 stats_report_init_view();
2482 stats_report_event_types_menu("byweekday", NULL);
2483 db_prepare(&query,
2484 "SELECT cast(mtime %% 7 AS INTEGER) dow, "
2485 "COUNT(*) AS eventCount "
2486 "FROM v_reports "
2487 "GROUP BY dow ORDER BY dow");
2488 @ <h1>Timeline Events
2489 @ (%s(stats_report_label_for_type())) by Day of the Week</h1>
2490 @ <table class='statistics-report-table-events' border='0'
2491 @ cellpadding='2' cellspacing='0' id='statsTable'>
2492 @ <thead><tr>
2493 @ <th>DoW</th>
2494 @ <th>Day</th>
2495 @ <th>Events</th>
2496 @ <th width='90%%'><!-- relative commits graph --></th>
2497 @ </tr></thead><tbody>
2498 while( SQLITE_ROW == db_step(&query) ){
2499 const int nCount = db_column_int(&query, 1);
2500 if(nCount>nMaxEvents){
2501 nMaxEvents = nCount;
2502 }
2503 }
2504 db_reset(&query);
2505 while( SQLITE_ROW == db_step(&query) ){
2506 const int dayNum =db_column_int(&query, 0);
2507 const int nCount = db_column_int(&query, 1);
2508 int nSize = nCount
2509 ? (int)(100 * nCount / nMaxEvents)
2510 : 0;
2511 if(!nCount) continue /* arguable! Possible? */;
2512 else if(!nSize) nSize = 1;
2513 rowClass = ++nRowNumber % 2;
2514 nEventTotal += nCount;
2515 @<tr class='row%d(rowClass)'>
2516 @ <td>%d(dayNum)</td>
2517 @ <td>%s(daysOfWeek[dayNum])</td>
2518 @ <td>%d(nCount)</td>
2519 @ <td>
2520 @ <div class='statistics-report-graph-line'
2521 @ style='width:%d(nSize)%%;'>&nbsp;</div>
2522 @ </td>
2523 @</tr>
2524 }
2525 @ </tbody></table>
2526 db_finalize(&query);
2527 output_table_sorting_javascript("statsTable","ntnx");
2528 }
2529
2530
2531 /*
2532 ** Helper for stats_report_by_month_year(), which generates a list of
2533 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2534 ** or YYYY-MM.
2535 */
2536 static void stats_report_year_weeks(const char *zUserName){
2537 const char *zYear = P("y");
2538 int nYear = zYear ? strlen(zYear) : 0;
2539 int i = 0;
2540 Stmt qYears = empty_Stmt;
2541 char *zDefaultYear = NULL;
2542 Blob sql = empty_blob;
2543 int nMaxEvents = 1; /* max number of events for
2544 all rows. */
2545 int iterations = 0; /* # of active time periods. */
2546 stats_report_init_view();
2547 if(4==nYear){
2548 Blob urlParams = empty_blob;
2549 blob_appendf(&urlParams, "y=%T", zYear);
2550 stats_report_event_types_menu("byweek", blob_str(&urlParams));
2551 blob_reset(&urlParams);
2552 }else{
2553 stats_report_event_types_menu("byweek", NULL);
2554 }
2555 blob_append(&sql,
2556 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2557 "FROM v_reports WHERE 1 ", -1);
2558 if(zUserName&&*zUserName){
2559 blob_append_sql(&sql,"AND user=%Q ", zUserName);
2560 }
2561 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2562 db_prepare(&qYears, "%s", blob_sql_text(&sql));
2563 blob_reset(&sql);
2564 cgi_printf("Select year: ");
2565 while( SQLITE_ROW == db_step(&qYears) ){
2566 const char *zT = db_column_text(&qYears, 0);
2567 if( i++ ){
2568 cgi_printf(" ");
2569 }
2570 cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
2571 (char)statsReportType);
2572 if(zUserName && *zUserName){
2573 cgi_printf("&user=%t",zUserName);
2574 }
2575 cgi_printf("'>%s</a>",zT);
2576 }
2577 db_finalize(&qYears);
2578 cgi_printf("<br/>");
2579 if(!zYear || !*zYear){
2580 zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
2581 zYear = zDefaultYear;
2582 nYear = 4;
2583 }
2584 if(4 == nYear){
2585 Stmt stWeek = empty_Stmt;
2586 int rowCount = 0;
2587 int total = 0;
2588 Blob header = empty_blob;
2589 blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
2590 "of %h", stats_report_label_for_type(),
2591 zYear);
2592 blob_append_sql(&sql,
2593 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
2594 "count(*) AS n "
2595 "FROM v_reports "
2596 "WHERE %Q=substr(date(mtime),1,4) "
2597 "AND mtime < current_timestamp ",
2598 zYear);
2599 if(zUserName&&*zUserName){
2600 blob_append_sql(&sql, " AND user=%Q ", zUserName);
2601 blob_appendf(&header," for user %h", zUserName);
2602 }
2603 blob_append_sql(&sql, "GROUP BY wk ORDER BY wk DESC");
2604 cgi_printf("<h1>%h</h1>", blob_str(&header));
2605 blob_reset(&header);
2606 cgi_printf("<table class='statistics-report-table-events' "
2607 "border='0' cellpadding='2' width='100%%' "
2608 "cellspacing='0' id='statsTable'>");
2609 cgi_printf("<thead><tr>"
2610 "<th>Week</th>"
2611 "<th>Events</th>"
2612 "<th width='90%%'><!-- relative commits graph --></th>"
2613 "</tr></thead>"
2614 "<tbody>");
2615 db_prepare(&stWeek, "%s", blob_sql_text(&sql));
2616 blob_reset(&sql);
2617 while( SQLITE_ROW == db_step(&stWeek) ){
2618 const int nCount = db_column_int(&stWeek, 1);
2619 if(nCount>nMaxEvents){
2620 nMaxEvents = nCount;
2621 }
2622 ++iterations;
2623 }
2624 db_reset(&stWeek);
2625 while( SQLITE_ROW == db_step(&stWeek) ){
2626 const char *zWeek = db_column_text(&stWeek,0);
2627 const int nCount = db_column_int(&stWeek,1);
2628 int nSize = nCount
2629 ? (int)(100 * nCount / nMaxEvents)
2630 : 0;
2631 if(!nSize) nSize = 1;
2632 total += nCount;
2633 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2634 cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
2635 g.zTop, zYear, zWeek, nCount,
2636 statsReportTimelineYFlag);
2637 if(zUserName && *zUserName){
2638 cgi_printf("&u=%t",zUserName);
2639 }
2640 cgi_printf("'>%s</a></td>",zWeek);
2641
2642 cgi_printf("<td>%d</td>",nCount);
2643 cgi_printf("<td>");
2644 if(nCount){
2645 cgi_printf("<div class='statistics-report-graph-line'"
2646 "style='width:%d%%;'>&nbsp;</div>",
2647 nSize);
2648 }
2649 cgi_printf("</td></tr>");
2650 }
2651 db_finalize(&stWeek);
2652 free(zDefaultYear);
2653 cgi_printf("</tbody></table>");
2654 if(total){
2655 int nAvg = iterations ? (total/iterations) : 0;
2656 cgi_printf("<br><div>Total events: %d<br>"
2657 "Average per active week: %d</div>",
2658 total, nAvg);
2659 }
2660 output_table_sorting_javascript("statsTable","tnx");
2661 }
2662 }
2663
2664 /*
2665 ** WEBPAGE: reports
2666 **
2667 ** Shows activity reports for the repository.
2668 **
2669 ** Query Parameters:
2670 **
2671 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2672 ** user=NAME Restricts statistics to the given user
2673 ** type=TYPE Restricts the report to a specific event type:
2674 ** ci (checkin), w (wiki), t (ticket), g (tag)
2675 ** Defaulting to all event types.
2676 **
2677 ** The view-specific query parameters include:
2678 **
2679 ** view=byweek:
2680 **
2681 ** y=YYYY The year to report (default is the server's
2682 ** current year).
2683 */
2684 void stats_report_page(){
2685 HQuery url; /* URL for various branch links */
2686 const char *zView = P("view"); /* Which view/report to show. */
2687 const char *zUserName = P("user");
2688
2689 login_check_credentials();
2690 if( !g.perm.Read ){ login_needed(); return; }
2691 if(!zUserName) zUserName = P("u");
2692 url_initialize(&url, "reports");
2693 if(zUserName && *zUserName){
2694 url_add_parameter(&url,"user", zUserName);
2695 timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
2696 }
2697 timeline_submenu(&url, "By Year", "view", "byyear", 0);
2698 timeline_submenu(&url, "By Month", "view", "bymonth", 0);
2699 timeline_submenu(&url, "By Week", "view", "byweek", 0);
2700 timeline_submenu(&url, "By Weekday", "view", "byweekday", 0);
2701 timeline_submenu(&url, "By User", "view", "byuser", "user");
2702 url_reset(&url);
2703 style_header("Activity Reports");
2704 if(0==fossil_strcmp(zView,"byyear")){
2705 stats_report_by_month_year(0, 0, zUserName);
2706 }else if(0==fossil_strcmp(zView,"bymonth")){
2707 stats_report_by_month_year(1, 0, zUserName);
2708 }else if(0==fossil_strcmp(zView,"byweek")){
2709 stats_report_year_weeks(zUserName);
2710 }else if(0==fossil_strcmp(zView,"byuser")){
2711 stats_report_by_user();
2712 }else if(0==fossil_strcmp(zView,"byweekday")){
2713 stats_report_day_of_week();
2714 }else{
2715 @ <h1>Select a report to show:</h1>
2716 @ <ul>
2717 @ <li><a href='?view=byyear'>Events by year</a></li>
2718 @ <li><a href='?view=bymonth'>Events by month</a></li>
2719 @ <li><a href='?view=byweek'>Events by calendar week</a></li>
2720 @ <li><a href='?view=byweekday'>Events by day of the week</a></li>
2721 @ <li><a href='?view=byuser'>Events by user</a></li>
2722 @ </ul>
2723 }
2724
2725 style_footer();
2726 }
2727
--- src/timeline.c
+++ src/timeline.c
@@ -87,10 +87,11 @@
87 #define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
88 #define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
89 #define TIMELINE_UCOLOR 0x0080 /* Background color by user */
90 #define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
91 #define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */
92 #define TIMELINE_SHOWRID 0x0400 /* Show RID values in addition to UUIDs */
93 #endif
94
95 /*
96 ** Hash a string and use the hash to determine a background color.
97 */
@@ -359,20 +360,20 @@
360 }
361 }
362 }
363 if( zType[0]=='c' && (pGraph || (tmFlags & TIMELINE_BRCOLOR)!=0) ){
364 int nParent = 0;
365 int aParent[GR_MAX_RAIL];
366 int gidx;
367 static Stmt qparent;
368 db_static_prepare(&qparent,
369 "SELECT pid FROM plink"
370 " WHERE cid=:rid AND pid NOT IN phantom"
371 " ORDER BY isprim DESC /*sort*/"
372 );
373 db_bind_int(&qparent, ":rid", rid);
374 while( db_step(&qparent)==SQLITE_ROW && nParent<ArraySize(aParent) ){
375 aParent[nParent++] = db_column_int(&qparent, 0);
376 }
377 db_reset(&qparent);
378 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
379 zUuid, isLeaf);
@@ -404,10 +405,13 @@
405 }
406 }else if( zType[0]=='e' && tagid ){
407 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
408 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
409 hyperlink_to_uuid(zUuid);
410 }
411 if( tmFlags & TIMELINE_SHOWRID ){
412 @ (%d(rid))
413 }
414 db_column_blob(pQuery, commentColumn, &comment);
415 if( zType[0]!='c' ){
416 /* Comments for anything other than a check-in are generated by
417 ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
@@ -604,12 +608,12 @@
608 ** for the upward portion of a merge arrow. The merge arrow goes up
609 ** to the row identified by mu:. If this value is zero then
610 ** node has no merge children and no merge-out line is drawn.
611 ** mu: The id of the row which is the top of the merge-out arrow.
612 ** u: Draw a thick child-line out of the top of this node and up to
613 ** the node with an id equal to this value. 0 if it is straight to
614 ** the top of the page, -1 if there is no thick-line riser.
615 ** f: 0x01: a leaf node.
616 ** au: An array of integers that define thick-line risers for branches.
617 ** The integers are in pairs. For each pair, the first integer is
618 ** is the rail on which the riser should run and the second integer
619 ** is the id of the node upto which the riser should run.
@@ -1031,11 +1035,10 @@
1035 ** nd Suppress "divider" lines
1036 ** v Show details of files changed
1037 ** f=UUID Show family (immediate parents and children) of UUID
1038 ** from=UUID Path from...
1039 ** to=UUID ... to this
 
1040 ** shortest ... show only the shortest path
1041 ** uf=FUUID Show only checkins that use given file version
1042 ** brbg Background color from branch name
1043 ** ubg Background color from user
1044 ** namechng Show only checkins that filename changes
@@ -1070,11 +1073,11 @@
1073 const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
1074 const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (week-of-year)*/
1075 int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
1076 int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
1077 int tagid; /* Tag ID */
1078 int tmFlags = 0; /* Timeline flags */
1079 const char *zThisTag = 0; /* Suppress links to this tag */
1080 const char *zThisUser = 0; /* Suppress links to this user */
1081 HQuery url; /* URL for various branch links */
1082 int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */
1083 int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */
@@ -1110,13 +1113,13 @@
1113 ){
1114 zCirca = zBefore = zAfter = 0;
1115 nEntry = -1;
1116 }
1117 if( zType[0]=='a' ){
1118 tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH;
1119 }else{
1120 tmFlags |= TIMELINE_GRAPH;
1121 }
1122 if( nEntry>0 ) url_add_parameter(&url, "n", mprintf("%d", nEntry));
1123 if( P("ng")!=0 || zSearch!=0 ){
1124 tmFlags &= ~TIMELINE_GRAPH;
1125 url_add_parameter(&url, "ng", 0);
@@ -1206,10 +1209,11 @@
1209 }else if( (p_rid || d_rid) && g.perm.Read ){
1210 /* If p= or d= is present, ignore all other parameters other than n= */
1211 char *zUuid;
1212 int np, nd;
1213
1214 tmFlags |= TIMELINE_DISJOINT;
1215 if( p_rid && d_rid ){
1216 if( p_rid!=d_rid ) p_rid = d_rid;
1217 if( P("n")==0 ) nEntry = 10;
1218 }
1219 db_multi_exec(
@@ -1552,10 +1556,11 @@
1556 }
1557 }
1558 if( P("showsql") ){
1559 @ <blockquote>%h(blob_sql_text(&sql))</blockquote>
1560 }
1561 if( P("showid") ) tmFlags |= TIMELINE_SHOWRID;
1562 blob_zero(&sql);
1563 db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
1564 @ <h2>%b(&desc)</h2>
1565 blob_reset(&desc);
1566 www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0);
@@ -2039,688 +2044,7 @@
2044 const char *zUuid = db_column_text(&q, 0);
2045 @ <li>
2046 @ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&amp;d=%s(zUuid)&amp;unhide">%S(zUuid)</a>
2047 }
2048 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2049 style_footer();
2050 }
2051
+1 -1
--- src/translate.c
+++ src/translate.c
@@ -42,11 +42,11 @@
4242
**
4343
** Enhancement #2:
4444
**
4545
** Comments of the form: "/* @-comment: CC" cause CC to become a
4646
** comment character for the @-substitution. Typical values for CC are
47
-** "--" (for SQL text) or "#" (for TCL script) or "//" (for C++ code).
47
+** "--" (for SQL text) or "#" (for Tcl script) or "//" (for C++ code).
4848
** Lines of subsequent @-blocks that begin with CC are omitted from the
4949
** output.
5050
**
5151
*/
5252
#include <stdio.h>
5353
--- src/translate.c
+++ src/translate.c
@@ -42,11 +42,11 @@
42 **
43 ** Enhancement #2:
44 **
45 ** Comments of the form: "/* @-comment: CC" cause CC to become a
46 ** comment character for the @-substitution. Typical values for CC are
47 ** "--" (for SQL text) or "#" (for TCL script) or "//" (for C++ code).
48 ** Lines of subsequent @-blocks that begin with CC are omitted from the
49 ** output.
50 **
51 */
52 #include <stdio.h>
53
--- src/translate.c
+++ src/translate.c
@@ -42,11 +42,11 @@
42 **
43 ** Enhancement #2:
44 **
45 ** Comments of the form: "/* @-comment: CC" cause CC to become a
46 ** comment character for the @-substitution. Typical values for CC are
47 ** "--" (for SQL text) or "#" (for Tcl script) or "//" (for C++ code).
48 ** Lines of subsequent @-blocks that begin with CC are omitted from the
49 ** output.
50 **
51 */
52 #include <stdio.h>
53
+17 -17
--- src/update.c
+++ src/update.c
@@ -34,11 +34,11 @@
3434
*/
3535
static int internalUpdate = 0;
3636
static int internalConflictCnt = 0;
3737
3838
/*
39
-** Do an update to version vid.
39
+** Do an update to version vid.
4040
**
4141
** Start an undo session but do not terminate it. Do not autosync.
4242
*/
4343
int update_to(int vid){
4444
int savedArgc;
@@ -157,11 +157,11 @@
157157
if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag,
158158
db_get_int("autosync-tries", 1)) ){
159159
fossil_fatal("Cannot proceed with update");
160160
}
161161
}
162
-
162
+
163163
/* Create any empty directories now, as well as after the update,
164164
** so changes in settings are reflected now */
165165
if( !dryRunFlag ) ensure_empty_dirs_created();
166166
167167
if( internalUpdate ){
@@ -182,11 +182,11 @@
182182
}else if( !is_a_version(tid) ){
183183
fossil_fatal("no such version: %s", g.argv[2]);
184184
}
185185
}
186186
}
187
-
187
+
188188
/* If no VERSION is specified on the command-line, then look for a
189189
** descendent of the current version. If there are multiple descendants,
190190
** look for one from the same branch as the current version. If there
191191
** are still multiple descendants, show them all and refuse to update
192192
** until the user selects one.
@@ -207,11 +207,11 @@
207207
" WHERE tagid=%d AND rid=%d))",
208208
TAG_BRANCH, TAG_BRANCH, vid
209209
);
210210
if( db_int(0, "SELECT count(*) FROM leaves")>1 ){
211211
compute_leaves(vid, closeCode);
212
- db_prepare(&q,
212
+ db_prepare(&q,
213213
"%s "
214214
" AND event.objid IN leaves"
215215
" ORDER BY event.mtime DESC",
216216
timeline_query_for_tty()
217217
);
@@ -220,11 +220,11 @@
220220
fossil_fatal("Multiple descendants");
221221
}
222222
}
223223
tid = db_int(0, "SELECT rid FROM leaves, event"
224224
" WHERE event.objid=leaves.rid"
225
- " ORDER BY event.mtime DESC");
225
+ " ORDER BY event.mtime DESC");
226226
if( tid==0 ) tid = vid;
227227
}
228228
229229
if( tid==0 ){
230230
return;
@@ -357,11 +357,11 @@
357357
zSep = "";
358358
for(i=3; i<g.argc; i++){
359359
file_tree_name(g.argv[i], &treename, 1);
360360
if( file_wd_isdir(g.argv[i])==1 ){
361361
if( blob_size(&treename) != 1 || blob_str(&treename)[0] != '.' ){
362
- blob_append_sql(&sql, "%sfn NOT GLOB '%q/*' ",
362
+ blob_append_sql(&sql, "%sfn NOT GLOB '%q/*' ",
363363
zSep /*safe-for-%s*/, blob_str(&treename));
364364
}else{
365365
blob_reset(&sql);
366366
break;
367367
}
@@ -378,11 +378,11 @@
378378
379379
/*
380380
** Alter the content of the checkout so that it conforms with the
381381
** target
382382
*/
383
- db_prepare(&q,
383
+ db_prepare(&q,
384384
"SELECT fn, idv, ridv, idt, ridt, chnged, fnt,"
385385
" isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
386386
);
387387
db_prepare(&mtimeXfer,
388388
"UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
@@ -470,11 +470,11 @@
470470
}else{
471471
fossil_print("MERGE %s\n", zName);
472472
}
473473
if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
474474
fossil_print("***** Cannot merge symlink %s\n", zNewName);
475
- nConflict++;
475
+ nConflict++;
476476
}else{
477477
unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
478478
undo_save(zName);
479479
content_get(ridt, &t);
480480
content_get(ridv, &v);
@@ -544,11 +544,11 @@
544544
fossil_warning("uncommitted %s against %S.",
545545
zLabel, db_column_text(&q, 0));
546546
nMerge++;
547547
}
548548
db_finalize(&q);
549
-
549
+
550550
if( nConflict ){
551551
if( internalUpdate ){
552552
internalConflictCnt = nConflict;
553553
nConflict = 0;
554554
}else{
@@ -561,11 +561,11 @@
561561
}
562562
if( nMerge ){
563563
fossil_warning("WARNING: %d uncommitted prior merges", nMerge);
564564
}
565565
}
566
-
566
+
567567
/*
568568
** Clean up the mid and pid VFILE entries. Then commit the changes.
569569
*/
570570
if( dryRunFlag ){
571571
db_end_transaction(1); /* With --dry-run, rollback changes */
@@ -615,27 +615,27 @@
615615
Blob path;
616616
const char *zPath;
617617
618618
blob_zero(&path);
619619
blob_appendf(&path, "%s/%s", g.zLocalRoot, zDir);
620
- zPath = blob_str(&path);
620
+ zPath = blob_str(&path);
621621
/* Handle various cases of existence of the directory */
622622
switch( file_wd_isdir(zPath) ){
623623
case 0: { /* doesn't exist */
624624
if( file_mkdir(zPath, 0)!=0 ) {
625625
fossil_warning("couldn't create directory %s as "
626626
"required by empty-dirs setting", zDir);
627
- }
627
+ }
628628
break;
629629
}
630630
case 1: { /* exists, and is a directory */
631631
/* do nothing - required directory exists already */
632632
break;
633633
}
634634
case 2: { /* exists, but isn't a directory */
635635
fossil_warning("file %s found, but a directory is required "
636
- "by empty-dirs setting", zDir);
636
+ "by empty-dirs setting", zDir);
637637
}
638638
}
639639
blob_reset(&path);
640640
}
641641
}
@@ -656,11 +656,11 @@
656656
int errCode /* Error code if file not found. Panic if 0. */
657657
){
658658
Manifest *pManifest;
659659
ManifestFile *pFile;
660660
int rid=0;
661
-
661
+
662662
if( revision ){
663663
rid = name_to_typed_rid(revision,"ci");
664664
}else if( !g.localOpen ){
665665
rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
666666
}else{
@@ -669,11 +669,11 @@
669669
if( !is_a_version(rid) ){
670670
if( errCode>0 ) return errCode;
671671
fossil_fatal("no such checkin: %s", revision);
672672
}
673673
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
674
-
674
+
675675
if( pManifest ){
676676
pFile = manifest_file_find(pManifest, file);
677677
if( pFile ){
678678
int rc;
679679
rid = uuid_to_rid(pFile->zUuid, 0);
@@ -728,14 +728,14 @@
728728
Blob record;
729729
int i;
730730
int errCode;
731731
Stmt q;
732732
733
- undo_capture_command_line();
733
+ undo_capture_command_line();
734734
zRevision = find_option("revision", "r", 1);
735735
verify_all_options();
736
-
736
+
737737
if( g.argc<2 ){
738738
usage("?OPTIONS? [FILE] ...");
739739
}
740740
if( zRevision && g.argc<3 ){
741741
fossil_fatal("the --revision option does not work for the entire tree");
742742
--- src/update.c
+++ src/update.c
@@ -34,11 +34,11 @@
34 */
35 static int internalUpdate = 0;
36 static int internalConflictCnt = 0;
37
38 /*
39 ** Do an update to version vid.
40 **
41 ** Start an undo session but do not terminate it. Do not autosync.
42 */
43 int update_to(int vid){
44 int savedArgc;
@@ -157,11 +157,11 @@
157 if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag,
158 db_get_int("autosync-tries", 1)) ){
159 fossil_fatal("Cannot proceed with update");
160 }
161 }
162
163 /* Create any empty directories now, as well as after the update,
164 ** so changes in settings are reflected now */
165 if( !dryRunFlag ) ensure_empty_dirs_created();
166
167 if( internalUpdate ){
@@ -182,11 +182,11 @@
182 }else if( !is_a_version(tid) ){
183 fossil_fatal("no such version: %s", g.argv[2]);
184 }
185 }
186 }
187
188 /* If no VERSION is specified on the command-line, then look for a
189 ** descendent of the current version. If there are multiple descendants,
190 ** look for one from the same branch as the current version. If there
191 ** are still multiple descendants, show them all and refuse to update
192 ** until the user selects one.
@@ -207,11 +207,11 @@
207 " WHERE tagid=%d AND rid=%d))",
208 TAG_BRANCH, TAG_BRANCH, vid
209 );
210 if( db_int(0, "SELECT count(*) FROM leaves")>1 ){
211 compute_leaves(vid, closeCode);
212 db_prepare(&q,
213 "%s "
214 " AND event.objid IN leaves"
215 " ORDER BY event.mtime DESC",
216 timeline_query_for_tty()
217 );
@@ -220,11 +220,11 @@
220 fossil_fatal("Multiple descendants");
221 }
222 }
223 tid = db_int(0, "SELECT rid FROM leaves, event"
224 " WHERE event.objid=leaves.rid"
225 " ORDER BY event.mtime DESC");
226 if( tid==0 ) tid = vid;
227 }
228
229 if( tid==0 ){
230 return;
@@ -357,11 +357,11 @@
357 zSep = "";
358 for(i=3; i<g.argc; i++){
359 file_tree_name(g.argv[i], &treename, 1);
360 if( file_wd_isdir(g.argv[i])==1 ){
361 if( blob_size(&treename) != 1 || blob_str(&treename)[0] != '.' ){
362 blob_append_sql(&sql, "%sfn NOT GLOB '%q/*' ",
363 zSep /*safe-for-%s*/, blob_str(&treename));
364 }else{
365 blob_reset(&sql);
366 break;
367 }
@@ -378,11 +378,11 @@
378
379 /*
380 ** Alter the content of the checkout so that it conforms with the
381 ** target
382 */
383 db_prepare(&q,
384 "SELECT fn, idv, ridv, idt, ridt, chnged, fnt,"
385 " isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
386 );
387 db_prepare(&mtimeXfer,
388 "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
@@ -470,11 +470,11 @@
470 }else{
471 fossil_print("MERGE %s\n", zName);
472 }
473 if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
474 fossil_print("***** Cannot merge symlink %s\n", zNewName);
475 nConflict++;
476 }else{
477 unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
478 undo_save(zName);
479 content_get(ridt, &t);
480 content_get(ridv, &v);
@@ -544,11 +544,11 @@
544 fossil_warning("uncommitted %s against %S.",
545 zLabel, db_column_text(&q, 0));
546 nMerge++;
547 }
548 db_finalize(&q);
549
550 if( nConflict ){
551 if( internalUpdate ){
552 internalConflictCnt = nConflict;
553 nConflict = 0;
554 }else{
@@ -561,11 +561,11 @@
561 }
562 if( nMerge ){
563 fossil_warning("WARNING: %d uncommitted prior merges", nMerge);
564 }
565 }
566
567 /*
568 ** Clean up the mid and pid VFILE entries. Then commit the changes.
569 */
570 if( dryRunFlag ){
571 db_end_transaction(1); /* With --dry-run, rollback changes */
@@ -615,27 +615,27 @@
615 Blob path;
616 const char *zPath;
617
618 blob_zero(&path);
619 blob_appendf(&path, "%s/%s", g.zLocalRoot, zDir);
620 zPath = blob_str(&path);
621 /* Handle various cases of existence of the directory */
622 switch( file_wd_isdir(zPath) ){
623 case 0: { /* doesn't exist */
624 if( file_mkdir(zPath, 0)!=0 ) {
625 fossil_warning("couldn't create directory %s as "
626 "required by empty-dirs setting", zDir);
627 }
628 break;
629 }
630 case 1: { /* exists, and is a directory */
631 /* do nothing - required directory exists already */
632 break;
633 }
634 case 2: { /* exists, but isn't a directory */
635 fossil_warning("file %s found, but a directory is required "
636 "by empty-dirs setting", zDir);
637 }
638 }
639 blob_reset(&path);
640 }
641 }
@@ -656,11 +656,11 @@
656 int errCode /* Error code if file not found. Panic if 0. */
657 ){
658 Manifest *pManifest;
659 ManifestFile *pFile;
660 int rid=0;
661
662 if( revision ){
663 rid = name_to_typed_rid(revision,"ci");
664 }else if( !g.localOpen ){
665 rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
666 }else{
@@ -669,11 +669,11 @@
669 if( !is_a_version(rid) ){
670 if( errCode>0 ) return errCode;
671 fossil_fatal("no such checkin: %s", revision);
672 }
673 pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
674
675 if( pManifest ){
676 pFile = manifest_file_find(pManifest, file);
677 if( pFile ){
678 int rc;
679 rid = uuid_to_rid(pFile->zUuid, 0);
@@ -728,14 +728,14 @@
728 Blob record;
729 int i;
730 int errCode;
731 Stmt q;
732
733 undo_capture_command_line();
734 zRevision = find_option("revision", "r", 1);
735 verify_all_options();
736
737 if( g.argc<2 ){
738 usage("?OPTIONS? [FILE] ...");
739 }
740 if( zRevision && g.argc<3 ){
741 fossil_fatal("the --revision option does not work for the entire tree");
742
--- src/update.c
+++ src/update.c
@@ -34,11 +34,11 @@
34 */
35 static int internalUpdate = 0;
36 static int internalConflictCnt = 0;
37
38 /*
39 ** Do an update to version vid.
40 **
41 ** Start an undo session but do not terminate it. Do not autosync.
42 */
43 int update_to(int vid){
44 int savedArgc;
@@ -157,11 +157,11 @@
157 if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag,
158 db_get_int("autosync-tries", 1)) ){
159 fossil_fatal("Cannot proceed with update");
160 }
161 }
162
163 /* Create any empty directories now, as well as after the update,
164 ** so changes in settings are reflected now */
165 if( !dryRunFlag ) ensure_empty_dirs_created();
166
167 if( internalUpdate ){
@@ -182,11 +182,11 @@
182 }else if( !is_a_version(tid) ){
183 fossil_fatal("no such version: %s", g.argv[2]);
184 }
185 }
186 }
187
188 /* If no VERSION is specified on the command-line, then look for a
189 ** descendent of the current version. If there are multiple descendants,
190 ** look for one from the same branch as the current version. If there
191 ** are still multiple descendants, show them all and refuse to update
192 ** until the user selects one.
@@ -207,11 +207,11 @@
207 " WHERE tagid=%d AND rid=%d))",
208 TAG_BRANCH, TAG_BRANCH, vid
209 );
210 if( db_int(0, "SELECT count(*) FROM leaves")>1 ){
211 compute_leaves(vid, closeCode);
212 db_prepare(&q,
213 "%s "
214 " AND event.objid IN leaves"
215 " ORDER BY event.mtime DESC",
216 timeline_query_for_tty()
217 );
@@ -220,11 +220,11 @@
220 fossil_fatal("Multiple descendants");
221 }
222 }
223 tid = db_int(0, "SELECT rid FROM leaves, event"
224 " WHERE event.objid=leaves.rid"
225 " ORDER BY event.mtime DESC");
226 if( tid==0 ) tid = vid;
227 }
228
229 if( tid==0 ){
230 return;
@@ -357,11 +357,11 @@
357 zSep = "";
358 for(i=3; i<g.argc; i++){
359 file_tree_name(g.argv[i], &treename, 1);
360 if( file_wd_isdir(g.argv[i])==1 ){
361 if( blob_size(&treename) != 1 || blob_str(&treename)[0] != '.' ){
362 blob_append_sql(&sql, "%sfn NOT GLOB '%q/*' ",
363 zSep /*safe-for-%s*/, blob_str(&treename));
364 }else{
365 blob_reset(&sql);
366 break;
367 }
@@ -378,11 +378,11 @@
378
379 /*
380 ** Alter the content of the checkout so that it conforms with the
381 ** target
382 */
383 db_prepare(&q,
384 "SELECT fn, idv, ridv, idt, ridt, chnged, fnt,"
385 " isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
386 );
387 db_prepare(&mtimeXfer,
388 "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
@@ -470,11 +470,11 @@
470 }else{
471 fossil_print("MERGE %s\n", zName);
472 }
473 if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
474 fossil_print("***** Cannot merge symlink %s\n", zNewName);
475 nConflict++;
476 }else{
477 unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0;
478 undo_save(zName);
479 content_get(ridt, &t);
480 content_get(ridv, &v);
@@ -544,11 +544,11 @@
544 fossil_warning("uncommitted %s against %S.",
545 zLabel, db_column_text(&q, 0));
546 nMerge++;
547 }
548 db_finalize(&q);
549
550 if( nConflict ){
551 if( internalUpdate ){
552 internalConflictCnt = nConflict;
553 nConflict = 0;
554 }else{
@@ -561,11 +561,11 @@
561 }
562 if( nMerge ){
563 fossil_warning("WARNING: %d uncommitted prior merges", nMerge);
564 }
565 }
566
567 /*
568 ** Clean up the mid and pid VFILE entries. Then commit the changes.
569 */
570 if( dryRunFlag ){
571 db_end_transaction(1); /* With --dry-run, rollback changes */
@@ -615,27 +615,27 @@
615 Blob path;
616 const char *zPath;
617
618 blob_zero(&path);
619 blob_appendf(&path, "%s/%s", g.zLocalRoot, zDir);
620 zPath = blob_str(&path);
621 /* Handle various cases of existence of the directory */
622 switch( file_wd_isdir(zPath) ){
623 case 0: { /* doesn't exist */
624 if( file_mkdir(zPath, 0)!=0 ) {
625 fossil_warning("couldn't create directory %s as "
626 "required by empty-dirs setting", zDir);
627 }
628 break;
629 }
630 case 1: { /* exists, and is a directory */
631 /* do nothing - required directory exists already */
632 break;
633 }
634 case 2: { /* exists, but isn't a directory */
635 fossil_warning("file %s found, but a directory is required "
636 "by empty-dirs setting", zDir);
637 }
638 }
639 blob_reset(&path);
640 }
641 }
@@ -656,11 +656,11 @@
656 int errCode /* Error code if file not found. Panic if 0. */
657 ){
658 Manifest *pManifest;
659 ManifestFile *pFile;
660 int rid=0;
661
662 if( revision ){
663 rid = name_to_typed_rid(revision,"ci");
664 }else if( !g.localOpen ){
665 rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
666 }else{
@@ -669,11 +669,11 @@
669 if( !is_a_version(rid) ){
670 if( errCode>0 ) return errCode;
671 fossil_fatal("no such checkin: %s", revision);
672 }
673 pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
674
675 if( pManifest ){
676 pFile = manifest_file_find(pManifest, file);
677 if( pFile ){
678 int rc;
679 rid = uuid_to_rid(pFile->zUuid, 0);
@@ -728,14 +728,14 @@
728 Blob record;
729 int i;
730 int errCode;
731 Stmt q;
732
733 undo_capture_command_line();
734 zRevision = find_option("revision", "r", 1);
735 verify_all_options();
736
737 if( g.argc<2 ){
738 usage("?OPTIONS? [FILE] ...");
739 }
740 if( zRevision && g.argc<3 ){
741 fossil_fatal("the --revision option does not work for the entire tree");
742
+12 -1
--- src/url.c
+++ src/url.c
@@ -158,12 +158,22 @@
158158
zLogin = mprintf("%t@", pUrlData->user);
159159
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
160160
pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
161161
i = j;
162162
}else{
163
- for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
163
+ int inSquare = 0;
164
+ int n;
165
+ for(i=iStart; (c=zUrl[i])!=0 && c!='/' && (inSquare || c!=':'); i++){
166
+ if( c=='[' ) inSquare = 1;
167
+ if( c==']' ) inSquare = 0;
168
+ }
164169
pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
170
+ n = strlen(pUrlData->name);
171
+ if( pUrlData->name[0]=='[' && n>2 && pUrlData->name[n-1]==']' ){
172
+ pUrlData->name++;
173
+ pUrlData->name[n-2] = 0;
174
+ }
165175
zLogin = mprintf("");
166176
}
167177
url_tolower(pUrlData->name);
168178
if( c==':' ){
169179
pUrlData->port = 0;
@@ -362,10 +372,11 @@
362372
** feature.
363373
*/
364374
void url_proxy_options(void){
365375
zProxyOpt = find_option("proxy", 0, 1);
366376
if( find_option("nosync",0,0) ) g.fNoSync = 1;
377
+ if( find_option("ipv4",0,0) ) g.fIPv4 = 1;
367378
}
368379
369380
/*
370381
** If the "proxy" setting is defined, then change the URL settings
371382
** (initialized by a prior call to url_parse()) so that the HTTP
372383
--- src/url.c
+++ src/url.c
@@ -158,12 +158,22 @@
158 zLogin = mprintf("%t@", pUrlData->user);
159 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
160 pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
161 i = j;
162 }else{
163 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
 
 
 
 
 
164 pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
 
 
 
 
 
165 zLogin = mprintf("");
166 }
167 url_tolower(pUrlData->name);
168 if( c==':' ){
169 pUrlData->port = 0;
@@ -362,10 +372,11 @@
362 ** feature.
363 */
364 void url_proxy_options(void){
365 zProxyOpt = find_option("proxy", 0, 1);
366 if( find_option("nosync",0,0) ) g.fNoSync = 1;
 
367 }
368
369 /*
370 ** If the "proxy" setting is defined, then change the URL settings
371 ** (initialized by a prior call to url_parse()) so that the HTTP
372
--- src/url.c
+++ src/url.c
@@ -158,12 +158,22 @@
158 zLogin = mprintf("%t@", pUrlData->user);
159 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
160 pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
161 i = j;
162 }else{
163 int inSquare = 0;
164 int n;
165 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && (inSquare || c!=':'); i++){
166 if( c=='[' ) inSquare = 1;
167 if( c==']' ) inSquare = 0;
168 }
169 pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
170 n = strlen(pUrlData->name);
171 if( pUrlData->name[0]=='[' && n>2 && pUrlData->name[n-1]==']' ){
172 pUrlData->name++;
173 pUrlData->name[n-2] = 0;
174 }
175 zLogin = mprintf("");
176 }
177 url_tolower(pUrlData->name);
178 if( c==':' ){
179 pUrlData->port = 0;
@@ -362,10 +372,11 @@
372 ** feature.
373 */
374 void url_proxy_options(void){
375 zProxyOpt = find_option("proxy", 0, 1);
376 if( find_option("nosync",0,0) ) g.fNoSync = 1;
377 if( find_option("ipv4",0,0) ) g.fIPv4 = 1;
378 }
379
380 /*
381 ** If the "proxy" setting is defined, then change the URL settings
382 ** (initialized by a prior call to url_parse()) so that the HTTP
383
+5 -4
--- src/user.c
+++ src/user.c
@@ -467,13 +467,13 @@
467467
style_submenu_element("Newer", "Newer entries",
468468
"%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0,
469469
n, y);
470470
}
471471
rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql));
472
- @ <center><table border="1" cellpadding="5">
473
- @ <tr><th width="33%%">Date</th><th width="34%%">User</th>
474
- @ <th width="33%%">IP Address</th></tr>
472
+ @ <center><table border="1" cellpadding="5" id='logtable'>
473
+ @ <thead><tr><th width="33%%">Date</th><th width="34%%">User</th>
474
+ @ <th width="33%%">IP Address</th></tr></thead><tbody>
475475
while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){
476476
const char *zName = db_column_text(&q, 0);
477477
const char *zIP = db_column_text(&q, 1);
478478
const char *zDate = db_column_text(&q, 2);
479479
int bSuccess = db_column_int(&q, 3);
@@ -492,11 +492,11 @@
492492
}
493493
if( skip>0 || cnt>n ){
494494
style_submenu_element("All", "All entries",
495495
"%s/access_log?n=10000000", g.zTop);
496496
}
497
- @ </table></center>
497
+ @ </tbody></table></center>
498498
db_finalize(&q);
499499
@ <hr>
500500
@ <form method="post" action="%s(g.zTop)/access_log">
501501
@ <label><input type="checkbox" name="delold">
502502
@ Delete all but the most recent 200 entries</input></label>
@@ -515,7 +515,8 @@
515515
@ <form method="post" action="%s(g.zTop)/access_log">
516516
@ <label><input type="checkbox" name="delall">
517517
@ Delete all entries</input></label>
518518
@ <input type="submit" name="delallbtn" value="Delete"></input>
519519
@ </form>
520
+ output_table_sorting_javascript("logtable", "Ttt", 1);
520521
style_footer();
521522
}
522523
--- src/user.c
+++ src/user.c
@@ -467,13 +467,13 @@
467 style_submenu_element("Newer", "Newer entries",
468 "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0,
469 n, y);
470 }
471 rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql));
472 @ <center><table border="1" cellpadding="5">
473 @ <tr><th width="33%%">Date</th><th width="34%%">User</th>
474 @ <th width="33%%">IP Address</th></tr>
475 while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){
476 const char *zName = db_column_text(&q, 0);
477 const char *zIP = db_column_text(&q, 1);
478 const char *zDate = db_column_text(&q, 2);
479 int bSuccess = db_column_int(&q, 3);
@@ -492,11 +492,11 @@
492 }
493 if( skip>0 || cnt>n ){
494 style_submenu_element("All", "All entries",
495 "%s/access_log?n=10000000", g.zTop);
496 }
497 @ </table></center>
498 db_finalize(&q);
499 @ <hr>
500 @ <form method="post" action="%s(g.zTop)/access_log">
501 @ <label><input type="checkbox" name="delold">
502 @ Delete all but the most recent 200 entries</input></label>
@@ -515,7 +515,8 @@
515 @ <form method="post" action="%s(g.zTop)/access_log">
516 @ <label><input type="checkbox" name="delall">
517 @ Delete all entries</input></label>
518 @ <input type="submit" name="delallbtn" value="Delete"></input>
519 @ </form>
 
520 style_footer();
521 }
522
--- src/user.c
+++ src/user.c
@@ -467,13 +467,13 @@
467 style_submenu_element("Newer", "Newer entries",
468 "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0,
469 n, y);
470 }
471 rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql));
472 @ <center><table border="1" cellpadding="5" id='logtable'>
473 @ <thead><tr><th width="33%%">Date</th><th width="34%%">User</th>
474 @ <th width="33%%">IP Address</th></tr></thead><tbody>
475 while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){
476 const char *zName = db_column_text(&q, 0);
477 const char *zIP = db_column_text(&q, 1);
478 const char *zDate = db_column_text(&q, 2);
479 int bSuccess = db_column_int(&q, 3);
@@ -492,11 +492,11 @@
492 }
493 if( skip>0 || cnt>n ){
494 style_submenu_element("All", "All entries",
495 "%s/access_log?n=10000000", g.zTop);
496 }
497 @ </tbody></table></center>
498 db_finalize(&q);
499 @ <hr>
500 @ <form method="post" action="%s(g.zTop)/access_log">
501 @ <label><input type="checkbox" name="delold">
502 @ Delete all but the most recent 200 entries</input></label>
@@ -515,7 +515,8 @@
515 @ <form method="post" action="%s(g.zTop)/access_log">
516 @ <label><input type="checkbox" name="delall">
517 @ Delete all entries</input></label>
518 @ <input type="submit" name="delallbtn" value="Delete"></input>
519 @ </form>
520 output_table_sorting_javascript("logtable", "Ttt", 1);
521 style_footer();
522 }
523
+10
--- src/util.c
+++ src/util.c
@@ -331,5 +331,15 @@
331331
int fossil_is_uuid(const char *zSym){
332332
return zSym
333333
&& (UUID_SIZE==strlen(zSym))
334334
&& validate16(zSym, UUID_SIZE);
335335
}
336
+
337
+/*
338
+** Return true if the input string is NULL or all whitespace.
339
+** Return false if the input string contains text.
340
+*/
341
+int fossil_all_whitespace(const char *z){
342
+ if( z==0 ) return 1;
343
+ while( fossil_isspace(z[0]) ){ z++; }
344
+ return z[0]==0;
345
+}
336346
--- src/util.c
+++ src/util.c
@@ -331,5 +331,15 @@
331 int fossil_is_uuid(const char *zSym){
332 return zSym
333 && (UUID_SIZE==strlen(zSym))
334 && validate16(zSym, UUID_SIZE);
335 }
 
 
 
 
 
 
 
 
 
 
336
--- src/util.c
+++ src/util.c
@@ -331,5 +331,15 @@
331 int fossil_is_uuid(const char *zSym){
332 return zSym
333 && (UUID_SIZE==strlen(zSym))
334 && validate16(zSym, UUID_SIZE);
335 }
336
337 /*
338 ** Return true if the input string is NULL or all whitespace.
339 ** Return false if the input string contains text.
340 */
341 int fossil_all_whitespace(const char *z){
342 if( z==0 ) return 1;
343 while( fossil_isspace(z[0]) ){ z++; }
344 return z[0]==0;
345 }
346
+2 -2
--- src/verify.c
+++ src/verify.c
@@ -63,11 +63,11 @@
6363
*/
6464
static Bag toVerify;
6565
static int inFinalVerify = 0;
6666
6767
/*
68
-** This routine is called just prior to each commit operation.
68
+** This routine is called just prior to each commit operation.
6969
**
7070
** Invoke verify_rid() on every record that has been added or modified
7171
** in the repository, in order to make sure that the repository is sane.
7272
*/
7373
static int verify_at_commit(void){
@@ -84,11 +84,11 @@
8484
return 0;
8585
}
8686
8787
/*
8888
** Arrange to verify a particular record prior to committing.
89
-**
89
+**
9090
** If the record rid is less than 1, then just initialize the
9191
** verification system but do not record anything as needing
9292
** verification.
9393
*/
9494
void verify_before_commit(int rid){
9595
--- src/verify.c
+++ src/verify.c
@@ -63,11 +63,11 @@
63 */
64 static Bag toVerify;
65 static int inFinalVerify = 0;
66
67 /*
68 ** This routine is called just prior to each commit operation.
69 **
70 ** Invoke verify_rid() on every record that has been added or modified
71 ** in the repository, in order to make sure that the repository is sane.
72 */
73 static int verify_at_commit(void){
@@ -84,11 +84,11 @@
84 return 0;
85 }
86
87 /*
88 ** Arrange to verify a particular record prior to committing.
89 **
90 ** If the record rid is less than 1, then just initialize the
91 ** verification system but do not record anything as needing
92 ** verification.
93 */
94 void verify_before_commit(int rid){
95
--- src/verify.c
+++ src/verify.c
@@ -63,11 +63,11 @@
63 */
64 static Bag toVerify;
65 static int inFinalVerify = 0;
66
67 /*
68 ** This routine is called just prior to each commit operation.
69 **
70 ** Invoke verify_rid() on every record that has been added or modified
71 ** in the repository, in order to make sure that the repository is sane.
72 */
73 static int verify_at_commit(void){
@@ -84,11 +84,11 @@
84 return 0;
85 }
86
87 /*
88 ** Arrange to verify a particular record prior to committing.
89 **
90 ** If the record rid is less than 1, then just initialize the
91 ** verification system but do not record anything as needing
92 ** verification.
93 */
94 void verify_before_commit(int rid){
95
+32 -8
--- src/wiki.c
+++ src/wiki.c
@@ -155,10 +155,30 @@
155155
@ <pre>
156156
@ %h(blob_str(pWiki))
157157
@ </pre>
158158
}
159159
}
160
+
161
+/*
162
+** WEBPAGE: md_rules
163
+**
164
+** Show a summary of the Markdown wiki formatting rules.
165
+*/
166
+void markdown_rules_page(void){
167
+ Blob x;
168
+ int fTxt = P("txt")!=0;
169
+ style_header("Markdown Formatting Rules");
170
+ if( fTxt ){
171
+ style_submenu_element("Formatted", "Formatted", "%R/md_rules");
172
+ }else{
173
+ style_submenu_element("Plain-Text", "Plain-Text", "%R/md_rules?txt=1");
174
+ }
175
+ blob_init(&x, builtin_text("markdown.md"), -1);
176
+ wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
177
+ blob_reset(&x);
178
+ style_footer();
179
+}
160180
161181
/*
162182
** Returns non-zero if moderation is required for wiki changes and wiki
163183
** attachments.
164184
*/
@@ -213,11 +233,12 @@
213233
@ <li> %z(href("%R/wiki?name=%t",zHomePageName))
214234
@ %h(zHomePageName)</a> project home page.</li>
215235
}
216236
}
217237
@ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
218
- @ <li> %z(href("%R/wiki_rules"))Formatting rules</a> for wiki.</li>
238
+ @ <li> Formatting rules for %z(href("%R/wiki_rules"))Fossil Wiki</a> and for
239
+ @ %z(href("%R/md_rules"))Markdown Wiki</a>.</li>
219240
@ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a>
220241
@ to experiment.</li>
221242
if( g.perm.NewWiki ){
222243
@ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li>
223244
if( g.perm.Write ){
@@ -243,17 +264,20 @@
243264
if( isSandbox ){
244265
zBody = db_get("sandbox",zBody);
245266
zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
246267
rid = 0;
247268
}else{
248
- zTag = mprintf("wiki-%s", zPageName);
249
- rid = db_int(0,
250
- "SELECT rid FROM tagxref"
251
- " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
252
- " ORDER BY mtime DESC", zTag
253
- );
254
- free(zTag);
269
+ const char *zUuid = P("id");
270
+ if( zUuid==0 || (rid = symbolic_name_to_rid(zUuid,"w"))==0 ){
271
+ zTag = mprintf("wiki-%s", zPageName);
272
+ rid = db_int(0,
273
+ "SELECT rid FROM tagxref"
274
+ " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
275
+ " ORDER BY mtime DESC", zTag
276
+ );
277
+ free(zTag);
278
+ }
255279
pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
256280
if( pWiki ){
257281
zBody = pWiki->zWiki;
258282
zMimetype = pWiki->zMimetype;
259283
}
260284
--- src/wiki.c
+++ src/wiki.c
@@ -155,10 +155,30 @@
155 @ <pre>
156 @ %h(blob_str(pWiki))
157 @ </pre>
158 }
159 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
161 /*
162 ** Returns non-zero if moderation is required for wiki changes and wiki
163 ** attachments.
164 */
@@ -213,11 +233,12 @@
213 @ <li> %z(href("%R/wiki?name=%t",zHomePageName))
214 @ %h(zHomePageName)</a> project home page.</li>
215 }
216 }
217 @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
218 @ <li> %z(href("%R/wiki_rules"))Formatting rules</a> for wiki.</li>
 
219 @ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a>
220 @ to experiment.</li>
221 if( g.perm.NewWiki ){
222 @ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li>
223 if( g.perm.Write ){
@@ -243,17 +264,20 @@
243 if( isSandbox ){
244 zBody = db_get("sandbox",zBody);
245 zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
246 rid = 0;
247 }else{
248 zTag = mprintf("wiki-%s", zPageName);
249 rid = db_int(0,
250 "SELECT rid FROM tagxref"
251 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
252 " ORDER BY mtime DESC", zTag
253 );
254 free(zTag);
 
 
 
255 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
256 if( pWiki ){
257 zBody = pWiki->zWiki;
258 zMimetype = pWiki->zMimetype;
259 }
260
--- src/wiki.c
+++ src/wiki.c
@@ -155,10 +155,30 @@
155 @ <pre>
156 @ %h(blob_str(pWiki))
157 @ </pre>
158 }
159 }
160
161 /*
162 ** WEBPAGE: md_rules
163 **
164 ** Show a summary of the Markdown wiki formatting rules.
165 */
166 void markdown_rules_page(void){
167 Blob x;
168 int fTxt = P("txt")!=0;
169 style_header("Markdown Formatting Rules");
170 if( fTxt ){
171 style_submenu_element("Formatted", "Formatted", "%R/md_rules");
172 }else{
173 style_submenu_element("Plain-Text", "Plain-Text", "%R/md_rules?txt=1");
174 }
175 blob_init(&x, builtin_text("markdown.md"), -1);
176 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
177 blob_reset(&x);
178 style_footer();
179 }
180
181 /*
182 ** Returns non-zero if moderation is required for wiki changes and wiki
183 ** attachments.
184 */
@@ -213,11 +233,12 @@
233 @ <li> %z(href("%R/wiki?name=%t",zHomePageName))
234 @ %h(zHomePageName)</a> project home page.</li>
235 }
236 }
237 @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
238 @ <li> Formatting rules for %z(href("%R/wiki_rules"))Fossil Wiki</a> and for
239 @ %z(href("%R/md_rules"))Markdown Wiki</a>.</li>
240 @ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a>
241 @ to experiment.</li>
242 if( g.perm.NewWiki ){
243 @ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li>
244 if( g.perm.Write ){
@@ -243,17 +264,20 @@
264 if( isSandbox ){
265 zBody = db_get("sandbox",zBody);
266 zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
267 rid = 0;
268 }else{
269 const char *zUuid = P("id");
270 if( zUuid==0 || (rid = symbolic_name_to_rid(zUuid,"w"))==0 ){
271 zTag = mprintf("wiki-%s", zPageName);
272 rid = db_int(0,
273 "SELECT rid FROM tagxref"
274 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
275 " ORDER BY mtime DESC", zTag
276 );
277 free(zTag);
278 }
279 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
280 if( pWiki ){
281 zBody = pWiki->zWiki;
282 zMimetype = pWiki->zMimetype;
283 }
284
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2092,9 +2092,81 @@
20922092
for(i=2; i<g.argc; i++){
20932093
blob_read_from_file(&in, g.argv[i]);
20942094
blob_zero(&out);
20952095
htmlTidy(blob_str(&in), &out);
20962096
blob_reset(&in);
2097
+ fossil_puts(blob_str(&out), 0);
2098
+ blob_reset(&out);
2099
+ }
2100
+}
2101
+
2102
+/*
2103
+** Remove all HTML markup from the input text. The output written into
2104
+** pOut is pure text.
2105
+*/
2106
+void html_to_plaintext(const char *zIn, Blob *pOut){
2107
+ int n;
2108
+ int i, j;
2109
+ int nNL = 0; /* Number of \n characters at the end of pOut */
2110
+ int nWS = 0; /* True if pOut ends with whitespace */
2111
+ while( zIn[0] ){
2112
+ n = nextHtmlToken(zIn);
2113
+ if( zIn[0]=='<' && n>1 ){
2114
+ int isCloseTag;
2115
+ int eTag;
2116
+ int eType;
2117
+ char zTag[32];
2118
+ isCloseTag = zIn[1]=='/';
2119
+ for(i=0, j=1+isCloseTag; i<30 && fossil_isalnum(zIn[j]); i++, j++){
2120
+ zTag[i] = fossil_tolower(zIn[j]);
2121
+ }
2122
+ zTag[i] = 0;
2123
+ eTag = findTag(zTag);
2124
+ eType = aMarkup[eTag].iType;
2125
+ if( eTag==MARKUP_INVALID && fossil_strnicmp(zIn,"<style",6)==0 ){
2126
+ zIn += n;
2127
+ while( zIn[0] ){
2128
+ n = nextHtmlToken(zIn);
2129
+ if( fossil_strnicmp(zIn, "</style",7)==0 ) break;
2130
+ zIn += n;
2131
+ }
2132
+ if( zIn[0]=='<' ) zIn += n;
2133
+ continue;
2134
+ }
2135
+ if( !isCloseTag && (eType & (MUTYPE_BLOCK|MUTYPE_TABLE))!=0 ){
2136
+ if( nNL==0 ){
2137
+ blob_append(pOut, "\n", 1);
2138
+ nNL++;
2139
+ }
2140
+ nWS = 1;
2141
+ }
2142
+ }else if( fossil_isspace(zIn[0]) ){
2143
+ for(i=nNL=0; i<n; i++) if( zIn[i]=='\n' ) nNL++;
2144
+ if( !nWS ){
2145
+ blob_append(pOut, nNL ? "\n" : " ", 1);
2146
+ nWS = 1;
2147
+ }
2148
+ }else{
2149
+ blob_append(pOut, zIn, n);
2150
+ nNL = nWS = 0;
2151
+ }
2152
+ zIn += n;
2153
+ }
2154
+ if( nNL==0 ) blob_append(pOut, "\n", 1);
2155
+}
2156
+
2157
+/*
2158
+** COMMAND: test-html-to-text
2159
+*/
2160
+void test_html_to_text(void){
2161
+ Blob in, out;
2162
+ int i;
2163
+
2164
+ for(i=2; i<g.argc; i++){
2165
+ blob_read_from_file(&in, g.argv[i]);
2166
+ blob_zero(&out);
2167
+ html_to_plaintext(blob_str(&in), &out);
2168
+ blob_reset(&in);
20972169
fossil_puts(blob_str(&out), 0);
20982170
blob_reset(&out);
20992171
}
21002172
}
21012173
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2092,9 +2092,81 @@
2092 for(i=2; i<g.argc; i++){
2093 blob_read_from_file(&in, g.argv[i]);
2094 blob_zero(&out);
2095 htmlTidy(blob_str(&in), &out);
2096 blob_reset(&in);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2097 fossil_puts(blob_str(&out), 0);
2098 blob_reset(&out);
2099 }
2100 }
2101
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2092,9 +2092,81 @@
2092 for(i=2; i<g.argc; i++){
2093 blob_read_from_file(&in, g.argv[i]);
2094 blob_zero(&out);
2095 htmlTidy(blob_str(&in), &out);
2096 blob_reset(&in);
2097 fossil_puts(blob_str(&out), 0);
2098 blob_reset(&out);
2099 }
2100 }
2101
2102 /*
2103 ** Remove all HTML markup from the input text. The output written into
2104 ** pOut is pure text.
2105 */
2106 void html_to_plaintext(const char *zIn, Blob *pOut){
2107 int n;
2108 int i, j;
2109 int nNL = 0; /* Number of \n characters at the end of pOut */
2110 int nWS = 0; /* True if pOut ends with whitespace */
2111 while( zIn[0] ){
2112 n = nextHtmlToken(zIn);
2113 if( zIn[0]=='<' && n>1 ){
2114 int isCloseTag;
2115 int eTag;
2116 int eType;
2117 char zTag[32];
2118 isCloseTag = zIn[1]=='/';
2119 for(i=0, j=1+isCloseTag; i<30 && fossil_isalnum(zIn[j]); i++, j++){
2120 zTag[i] = fossil_tolower(zIn[j]);
2121 }
2122 zTag[i] = 0;
2123 eTag = findTag(zTag);
2124 eType = aMarkup[eTag].iType;
2125 if( eTag==MARKUP_INVALID && fossil_strnicmp(zIn,"<style",6)==0 ){
2126 zIn += n;
2127 while( zIn[0] ){
2128 n = nextHtmlToken(zIn);
2129 if( fossil_strnicmp(zIn, "</style",7)==0 ) break;
2130 zIn += n;
2131 }
2132 if( zIn[0]=='<' ) zIn += n;
2133 continue;
2134 }
2135 if( !isCloseTag && (eType & (MUTYPE_BLOCK|MUTYPE_TABLE))!=0 ){
2136 if( nNL==0 ){
2137 blob_append(pOut, "\n", 1);
2138 nNL++;
2139 }
2140 nWS = 1;
2141 }
2142 }else if( fossil_isspace(zIn[0]) ){
2143 for(i=nNL=0; i<n; i++) if( zIn[i]=='\n' ) nNL++;
2144 if( !nWS ){
2145 blob_append(pOut, nNL ? "\n" : " ", 1);
2146 nWS = 1;
2147 }
2148 }else{
2149 blob_append(pOut, zIn, n);
2150 nNL = nWS = 0;
2151 }
2152 zIn += n;
2153 }
2154 if( nNL==0 ) blob_append(pOut, "\n", 1);
2155 }
2156
2157 /*
2158 ** COMMAND: test-html-to-text
2159 */
2160 void test_html_to_text(void){
2161 Blob in, out;
2162 int i;
2163
2164 for(i=2; i<g.argc; i++){
2165 blob_read_from_file(&in, g.argv[i]);
2166 blob_zero(&out);
2167 html_to_plaintext(blob_str(&in), &out);
2168 blob_reset(&in);
2169 fossil_puts(blob_str(&out), 0);
2170 blob_reset(&out);
2171 }
2172 }
2173
+2 -2
--- src/xfer.c
+++ src/xfer.c
@@ -1966,12 +1966,12 @@
19661966
g.clockSkewSeen = 1;
19671967
}
19681968
19691969
fossil_force_newline();
19701970
fossil_print(
1971
- "%s finished with %lld bytes sent, %lld bytes received\n",
1972
- zOpType, nSent, nRcvd);
1971
+ "%s done, sent: %lld received: %lld ip: %s\n",
1972
+ zOpType, nSent, nRcvd, g.zIpAddr);
19731973
transport_close(&g.url);
19741974
transport_global_shutdown(&g.url);
19751975
if( nErr && go==2 ){
19761976
db_multi_exec("DROP TABLE onremote");
19771977
manifest_crosslink_end(MC_PERMIT_HOOKS);
19781978
--- src/xfer.c
+++ src/xfer.c
@@ -1966,12 +1966,12 @@
1966 g.clockSkewSeen = 1;
1967 }
1968
1969 fossil_force_newline();
1970 fossil_print(
1971 "%s finished with %lld bytes sent, %lld bytes received\n",
1972 zOpType, nSent, nRcvd);
1973 transport_close(&g.url);
1974 transport_global_shutdown(&g.url);
1975 if( nErr && go==2 ){
1976 db_multi_exec("DROP TABLE onremote");
1977 manifest_crosslink_end(MC_PERMIT_HOOKS);
1978
--- src/xfer.c
+++ src/xfer.c
@@ -1966,12 +1966,12 @@
1966 g.clockSkewSeen = 1;
1967 }
1968
1969 fossil_force_newline();
1970 fossil_print(
1971 "%s done, sent: %lld received: %lld ip: %s\n",
1972 zOpType, nSent, nRcvd, g.zIpAddr);
1973 transport_close(&g.url);
1974 transport_global_shutdown(&g.url);
1975 if( nErr && go==2 ){
1976 db_multi_exec("DROP TABLE onremote");
1977 manifest_crosslink_end(MC_PERMIT_HOOKS);
1978
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -17,11 +17,11 @@
1717
The edit of a line with multibyte characters is the first chunk.
1818
* <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
1919
target="testwindow">Large diff of sqlite3.c</a>. This diff was very
2020
slow prior to the performance enhancement change [9e15437e97].
2121
* <a href="../../../info/bda00cbada#chunk49" target="testwindow">
22
- A difficult indentation change.
22
+ A difficult indentation change.</a> (show-version-diffs must be enabled)
2323
* <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
2424
target="testwindow">Another tricky indentation.</a> Notice especially
2525
lines 59398 and 59407 on the left.
2626
* <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
2727
target="testwindow">Inverse of the previous.</a>
2828
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -17,11 +17,11 @@
17 The edit of a line with multibyte characters is the first chunk.
18 * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
19 target="testwindow">Large diff of sqlite3.c</a>. This diff was very
20 slow prior to the performance enhancement change [9e15437e97].
21 * <a href="../../../info/bda00cbada#chunk49" target="testwindow">
22 A difficult indentation change.
23 * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
24 target="testwindow">Another tricky indentation.</a> Notice especially
25 lines 59398 and 59407 on the left.
26 * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
27 target="testwindow">Inverse of the previous.</a>
28
--- test/diff-test-1.wiki
+++ test/diff-test-1.wiki
@@ -17,11 +17,11 @@
17 The edit of a line with multibyte characters is the first chunk.
18 * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
19 target="testwindow">Large diff of sqlite3.c</a>. This diff was very
20 slow prior to the performance enhancement change [9e15437e97].
21 * <a href="../../../info/bda00cbada#chunk49" target="testwindow">
22 A difficult indentation change.</a> (show-version-diffs must be enabled)
23 * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
24 target="testwindow">Another tricky indentation.</a> Notice especially
25 lines 59398 and 59407 on the left.
26 * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
27 target="testwindow">Inverse of the previous.</a>
28
--- test/graph-test-1.wiki
+++ test/graph-test-1.wiki
@@ -28,23 +28,21 @@
2828
multiple branch risers.</a>
2929
* <a href="../../../timeline?y=ci&a=2010-12-20&n=18" target="testwindow">
3030
multiple branch risers, n=18.</a>
3131
* <a href="../../../timeline?y=ci&a=2010-12-20&n=9" target="testwindow">
3232
multiple branch risers, n=9.</a>
33
- * <a href="../../../timeline?r=experimental" target="testwindow">
33
+ * <a href="../../../timeline?r=experimental&n=0" target="testwindow">
3434
Experimental branch with related check-ins.</a>
35
- * <a href="../../../timeline?r=experimental&mionly" target="testwindow">
35
+ * <a href="../../../timeline?r=experimental&mionly&n=0" target="testwindow">
3636
Experimental branch with merge-ins only.</a>
37
- * <a href="../../../timeline?t=experimental" target="testwindow">
37
+ * <a href="../../../timeline?t=experimental&n=0" target="testwindow">
3838
Experimental branch check-ins only.</a>
39
- * <a href="../../../timeline?r=experimental&n=1000" target="testwindow">
40
- Experimental branch using and related check-ins - 1000 elements.</a>
41
- * <a href="../../../timeline?r=release" target="testwindow">
39
+ * <a href="../../../timeline?r=release&n=0" target="testwindow">
4240
Check-ins tagged "release" and related check-ins</a>
43
- * <a href="../../../timeline?r=release&mionly" target="testwindow">
41
+ * <a href="../../../timeline?r=release&mionly&n=0" target="testwindow">
4442
Check-ins tagged "release" and merge-ins</a>
45
- * <a href="../../../timeline?t=release" target="testwindow">
43
+ * <a href="../../../timeline?t=release&n=0" target="testwindow">
4644
Only check-ins tagged "release"</a>
4745
* <a href="../../../finfo?name=Makefile" target="testwindow">
4846
History of source file "Makefile".</a>
4947
* <a href="../../../timeline?a=1970-01-01" target="testwindow">
5048
20 elements after 1970-01-01.</a>
@@ -51,22 +49,25 @@
5149
* <a href="../../../timeline?n=100000000&y=ci" target="testwindow">
5250
All check-ins - a huge graph.</a>
5351
* <a href="../../../timeline?f=8dfed953f7530442" target="testwindow">
5452
This malformed commit has a
5553
merge parent which is not a valid checkin.</a>
56
- * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9"
54
+ * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9&shortest"
5755
target="testwindow">
5856
From e663bac6f7 to a298a0e2f9 by shortest path.</a>
59
- * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9&nomerge"
57
+ * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9"
6058
target="testwindow">
6159
From e663bac6f7 to a298a0e2f9 without merge links.</a>
6260
* <a href="../../../timeline?me=e663bac6f7&you=a298a0e2f9"
6361
target="testwindow">
6462
Common ancestor path of e663bac6f7 to a298a0e2f9.</a>
65
- * <a href="../../../timeline?f=65dd90fb95a2af55">
63
+ * <a href="../../../timeline?f=65dd90fb95a2af55" target="testwindow">
6664
Merge on the same branch does not result in a leaf.
6765
</a>
66
+ * <a href="../../../timeline?c=20015206bc"
67
+ target="testwindow">
68
+ This timeline has a hidden commit.</a> Click Unhide to reveal.
6869
6970
External:
7071
7172
* <a href="http://www.sqlite.org/src/timeline?c=2010-09-29&nd"
7273
target="testwindow">Timewarp due to a mis-configured system clock.</a>
7374
--- test/graph-test-1.wiki
+++ test/graph-test-1.wiki
@@ -28,23 +28,21 @@
28 multiple branch risers.</a>
29 * <a href="../../../timeline?y=ci&a=2010-12-20&n=18" target="testwindow">
30 multiple branch risers, n=18.</a>
31 * <a href="../../../timeline?y=ci&a=2010-12-20&n=9" target="testwindow">
32 multiple branch risers, n=9.</a>
33 * <a href="../../../timeline?r=experimental" target="testwindow">
34 Experimental branch with related check-ins.</a>
35 * <a href="../../../timeline?r=experimental&mionly" target="testwindow">
36 Experimental branch with merge-ins only.</a>
37 * <a href="../../../timeline?t=experimental" target="testwindow">
38 Experimental branch check-ins only.</a>
39 * <a href="../../../timeline?r=experimental&n=1000" target="testwindow">
40 Experimental branch using and related check-ins - 1000 elements.</a>
41 * <a href="../../../timeline?r=release" target="testwindow">
42 Check-ins tagged "release" and related check-ins</a>
43 * <a href="../../../timeline?r=release&mionly" target="testwindow">
44 Check-ins tagged "release" and merge-ins</a>
45 * <a href="../../../timeline?t=release" target="testwindow">
46 Only check-ins tagged "release"</a>
47 * <a href="../../../finfo?name=Makefile" target="testwindow">
48 History of source file "Makefile".</a>
49 * <a href="../../../timeline?a=1970-01-01" target="testwindow">
50 20 elements after 1970-01-01.</a>
@@ -51,22 +49,25 @@
51 * <a href="../../../timeline?n=100000000&y=ci" target="testwindow">
52 All check-ins - a huge graph.</a>
53 * <a href="../../../timeline?f=8dfed953f7530442" target="testwindow">
54 This malformed commit has a
55 merge parent which is not a valid checkin.</a>
56 * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9"
57 target="testwindow">
58 From e663bac6f7 to a298a0e2f9 by shortest path.</a>
59 * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9&nomerge"
60 target="testwindow">
61 From e663bac6f7 to a298a0e2f9 without merge links.</a>
62 * <a href="../../../timeline?me=e663bac6f7&you=a298a0e2f9"
63 target="testwindow">
64 Common ancestor path of e663bac6f7 to a298a0e2f9.</a>
65 * <a href="../../../timeline?f=65dd90fb95a2af55">
66 Merge on the same branch does not result in a leaf.
67 </a>
 
 
 
68
69 External:
70
71 * <a href="http://www.sqlite.org/src/timeline?c=2010-09-29&nd"
72 target="testwindow">Timewarp due to a mis-configured system clock.</a>
73
--- test/graph-test-1.wiki
+++ test/graph-test-1.wiki
@@ -28,23 +28,21 @@
28 multiple branch risers.</a>
29 * <a href="../../../timeline?y=ci&a=2010-12-20&n=18" target="testwindow">
30 multiple branch risers, n=18.</a>
31 * <a href="../../../timeline?y=ci&a=2010-12-20&n=9" target="testwindow">
32 multiple branch risers, n=9.</a>
33 * <a href="../../../timeline?r=experimental&n=0" target="testwindow">
34 Experimental branch with related check-ins.</a>
35 * <a href="../../../timeline?r=experimental&mionly&n=0" target="testwindow">
36 Experimental branch with merge-ins only.</a>
37 * <a href="../../../timeline?t=experimental&n=0" target="testwindow">
38 Experimental branch check-ins only.</a>
39 * <a href="../../../timeline?r=release&n=0" target="testwindow">
 
 
40 Check-ins tagged "release" and related check-ins</a>
41 * <a href="../../../timeline?r=release&mionly&n=0" target="testwindow">
42 Check-ins tagged "release" and merge-ins</a>
43 * <a href="../../../timeline?t=release&n=0" target="testwindow">
44 Only check-ins tagged "release"</a>
45 * <a href="../../../finfo?name=Makefile" target="testwindow">
46 History of source file "Makefile".</a>
47 * <a href="../../../timeline?a=1970-01-01" target="testwindow">
48 20 elements after 1970-01-01.</a>
@@ -51,22 +49,25 @@
49 * <a href="../../../timeline?n=100000000&y=ci" target="testwindow">
50 All check-ins - a huge graph.</a>
51 * <a href="../../../timeline?f=8dfed953f7530442" target="testwindow">
52 This malformed commit has a
53 merge parent which is not a valid checkin.</a>
54 * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9&shortest"
55 target="testwindow">
56 From e663bac6f7 to a298a0e2f9 by shortest path.</a>
57 * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9"
58 target="testwindow">
59 From e663bac6f7 to a298a0e2f9 without merge links.</a>
60 * <a href="../../../timeline?me=e663bac6f7&you=a298a0e2f9"
61 target="testwindow">
62 Common ancestor path of e663bac6f7 to a298a0e2f9.</a>
63 * <a href="../../../timeline?f=65dd90fb95a2af55" target="testwindow">
64 Merge on the same branch does not result in a leaf.
65 </a>
66 * <a href="../../../timeline?c=20015206bc"
67 target="testwindow">
68 This timeline has a hidden commit.</a> Click Unhide to reveal.
69
70 External:
71
72 * <a href="http://www.sqlite.org/src/timeline?c=2010-09-29&nd"
73 target="testwindow">Timewarp due to a mis-configured system clock.</a>
74
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -141,11 +141,11 @@
141141
# generate the index source, containing all web references,..
142142
page_index.h: $(TRANSLATEDSRC) mkindex.exe
143143
mkindex.exe $(TRANSLATEDSRC) >$@
144144
145145
builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe
146
- mkbuiltin.exe $(EXTRA_FILES) >$@
146
+ mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
147147
148148
# extracting version info from manifest
149149
VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION
150150
version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@
151151
152152
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -141,11 +141,11 @@
141 # generate the index source, containing all web references,..
142 page_index.h: $(TRANSLATEDSRC) mkindex.exe
143 mkindex.exe $(TRANSLATEDSRC) >$@
144
145 builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe
146 mkbuiltin.exe $(EXTRA_FILES) >$@
147
148 # extracting version info from manifest
149 VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION
150 version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@
151
152
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -141,11 +141,11 @@
141 # generate the index source, containing all web references,..
142 page_index.h: $(TRANSLATEDSRC) mkindex.exe
143 mkindex.exe $(TRANSLATEDSRC) >$@
144
145 builtin_data.h: $(EXTRA_FILES) mkbuiltin.exe
146 mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
147
148 # extracting version info from manifest
149 VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION
150 version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@
151
152
+11 -5
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
2828
2929
SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS
3030
3131
SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
3232
33
-SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.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 pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
33
+SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.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 pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
3434
35
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$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)\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)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$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)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$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)\allrepo$O $(OBJDIR)\attach$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)\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)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$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)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$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)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$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
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 allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip 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 pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
54
+ +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip 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 pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
5555
+echo fossil >> $@
5656
+echo fossil >> $@
5757
+echo $(LIBS) >> $@
5858
+echo. >> $@
5959
+echo fossil >> $@
@@ -96,11 +96,11 @@
9696
9797
page_index.h: mkindex$E $(SRC)
9898
+$** > $@
9999
100100
builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
101
- +$** > $@
101
+ mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
102102
103103
clean:
104104
-del $(OBJDIR)\*.obj
105105
-del *.obj *_.c *.h *.map
106106
@@ -674,10 +674,16 @@
674674
$(OBJDIR)\stat$O : stat_.c stat.h
675675
$(TCC) -o$@ -c stat_.c
676676
677677
stat_.c : $(SRCDIR)\stat.c
678678
+translate$E $** > $@
679
+
680
+$(OBJDIR)\statrep$O : statrep_.c statrep.h
681
+ $(TCC) -o$@ -c statrep_.c
682
+
683
+statrep_.c : $(SRCDIR)\statrep.c
684
+ +translate$E $** > $@
679685
680686
$(OBJDIR)\style$O : style_.c style.h
681687
$(TCC) -o$@ -c style_.c
682688
683689
style_.c : $(SRCDIR)\style.c
@@ -826,7 +832,7 @@
826832
827833
zip_.c : $(SRCDIR)\zip.c
828834
+translate$E $** > $@
829835
830836
headers: makeheaders$E page_index.h builtin_data.h VERSION.h
831
- +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.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 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 db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 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 report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.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 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 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
837
+ +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.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 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 db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 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 report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.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 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 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 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
832838
@copy /Y nul: headers
833839
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS
30
31 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.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 pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$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)\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)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$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)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$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 allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip 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 pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile 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 >> $@
@@ -96,11 +96,11 @@
96
97 page_index.h: mkindex$E $(SRC)
98 +$** > $@
99
100 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
101 +$** > $@
102
103 clean:
104 -del $(OBJDIR)\*.obj
105 -del *.obj *_.c *.h *.map
106
@@ -674,10 +674,16 @@
674 $(OBJDIR)\stat$O : stat_.c stat.h
675 $(TCC) -o$@ -c stat_.c
676
677 stat_.c : $(SRCDIR)\stat.c
678 +translate$E $** > $@
 
 
 
 
 
 
679
680 $(OBJDIR)\style$O : style_.c style.h
681 $(TCC) -o$@ -c style_.c
682
683 style_.c : $(SRCDIR)\style.c
@@ -826,7 +832,7 @@
826
827 zip_.c : $(SRCDIR)\zip.c
828 +translate$E $** > $@
829
830 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
831 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.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 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 db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 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 report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.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 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 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
832 @copy /Y nul: headers
833
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS
30
31 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.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 pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$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)\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)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$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)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$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)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$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 allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip 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 pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile 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 >> $@
@@ -96,11 +96,11 @@
96
97 page_index.h: mkindex$E $(SRC)
98 +$** > $@
99
100 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
101 mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
102
103 clean:
104 -del $(OBJDIR)\*.obj
105 -del *.obj *_.c *.h *.map
106
@@ -674,10 +674,16 @@
674 $(OBJDIR)\stat$O : stat_.c stat.h
675 $(TCC) -o$@ -c stat_.c
676
677 stat_.c : $(SRCDIR)\stat.c
678 +translate$E $** > $@
679
680 $(OBJDIR)\statrep$O : statrep_.c statrep.h
681 $(TCC) -o$@ -c statrep_.c
682
683 statrep_.c : $(SRCDIR)\statrep.c
684 +translate$E $** > $@
685
686 $(OBJDIR)\style$O : style_.c style.h
687 $(TCC) -o$@ -c style_.c
688
689 style_.c : $(SRCDIR)\style.c
@@ -826,7 +832,7 @@
832
833 zip_.c : $(SRCDIR)\zip.c
834 +translate$E $** > $@
835
836 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
837 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.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 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 db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 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 report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.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 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 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 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
838 @copy /Y nul: headers
839
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -146,12 +146,13 @@
146146
#### The directories where the OpenSSL include and library files are located.
147147
# The recommended usage here is to use the Sysinternals junction tool
148148
# to create a hard link between an "openssl-1.x" sub-directory of the
149149
# Fossil source code directory and the target OpenSSL source directory.
150150
#
151
-OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include
152
-OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j
151
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
152
+OPENSSLINCDIR = $(OPENSSLDIR)/include
153
+OPENSSLLIBDIR = $(OPENSSLDIR)
153154
154155
#### Either the directory where the Tcl library is installed or the Tcl
155156
# source code directory resides (depending on the value of the macro
156157
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
157158
# this directory must have "include" and "lib" sub-directories. If
@@ -456,10 +457,11 @@
456457
$(SRCDIR)/sitemap.c \
457458
$(SRCDIR)/skins.c \
458459
$(SRCDIR)/sqlcmd.c \
459460
$(SRCDIR)/stash.c \
460461
$(SRCDIR)/stat.c \
462
+ $(SRCDIR)/statrep.c \
461463
$(SRCDIR)/style.c \
462464
$(SRCDIR)/sync.c \
463465
$(SRCDIR)/tag.c \
464466
$(SRCDIR)/tar.c \
465467
$(SRCDIR)/th_main.c \
@@ -483,11 +485,36 @@
483485
$(SRCDIR)/xfer.c \
484486
$(SRCDIR)/xfersetup.c \
485487
$(SRCDIR)/zip.c
486488
487489
EXTRA_FILES = \
488
- $(SRCDIR)/diff.tcl
490
+ $(SRCDIR)/../skins/black_and_white/css.txt \
491
+ $(SRCDIR)/../skins/black_and_white/footer.txt \
492
+ $(SRCDIR)/../skins/black_and_white/header.txt \
493
+ $(SRCDIR)/../skins/default/css.txt \
494
+ $(SRCDIR)/../skins/default/footer.txt \
495
+ $(SRCDIR)/../skins/default/header.txt \
496
+ $(SRCDIR)/../skins/eagle/css.txt \
497
+ $(SRCDIR)/../skins/eagle/footer.txt \
498
+ $(SRCDIR)/../skins/eagle/header.txt \
499
+ $(SRCDIR)/../skins/enhanced1/css.txt \
500
+ $(SRCDIR)/../skins/enhanced1/footer.txt \
501
+ $(SRCDIR)/../skins/enhanced1/header.txt \
502
+ $(SRCDIR)/../skins/etienne1/css.txt \
503
+ $(SRCDIR)/../skins/etienne1/footer.txt \
504
+ $(SRCDIR)/../skins/etienne1/header.txt \
505
+ $(SRCDIR)/../skins/khaki/css.txt \
506
+ $(SRCDIR)/../skins/khaki/footer.txt \
507
+ $(SRCDIR)/../skins/khaki/header.txt \
508
+ $(SRCDIR)/../skins/plain_gray/css.txt \
509
+ $(SRCDIR)/../skins/plain_gray/footer.txt \
510
+ $(SRCDIR)/../skins/plain_gray/header.txt \
511
+ $(SRCDIR)/../skins/rounded1/css.txt \
512
+ $(SRCDIR)/../skins/rounded1/footer.txt \
513
+ $(SRCDIR)/../skins/rounded1/header.txt \
514
+ $(SRCDIR)/diff.tcl \
515
+ $(SRCDIR)/markdown.md
489516
490517
TRANS_SRC = \
491518
$(OBJDIR)/add_.c \
492519
$(OBJDIR)/allrepo_.c \
493520
$(OBJDIR)/attach_.c \
@@ -578,10 +605,11 @@
578605
$(OBJDIR)/sitemap_.c \
579606
$(OBJDIR)/skins_.c \
580607
$(OBJDIR)/sqlcmd_.c \
581608
$(OBJDIR)/stash_.c \
582609
$(OBJDIR)/stat_.c \
610
+ $(OBJDIR)/statrep_.c \
583611
$(OBJDIR)/style_.c \
584612
$(OBJDIR)/sync_.c \
585613
$(OBJDIR)/tag_.c \
586614
$(OBJDIR)/tar_.c \
587615
$(OBJDIR)/th_main_.c \
@@ -697,10 +725,11 @@
697725
$(OBJDIR)/sitemap.o \
698726
$(OBJDIR)/skins.o \
699727
$(OBJDIR)/sqlcmd.o \
700728
$(OBJDIR)/stash.o \
701729
$(OBJDIR)/stat.o \
730
+ $(OBJDIR)/statrep.o \
702731
$(OBJDIR)/style.o \
703732
$(OBJDIR)/sync.o \
704733
$(OBJDIR)/tag.o \
705734
$(OBJDIR)/tar.o \
706735
$(OBJDIR)/th_main.o \
@@ -914,11 +943,11 @@
914943
915944
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX)
916945
$(MKINDEX) $(TRANS_SRC) >$@
917946
918947
$(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES)
919
- $(MKBUILTIN) $(EXTRA_FILES) >$@
948
+ $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
920949
921950
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
922951
$(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
923952
$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
924953
$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -1009,10 +1038,11 @@
10091038
$(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
10101039
$(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
10111040
$(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
10121041
$(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
10131042
$(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
1043
+ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
10141044
$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
10151045
$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
10161046
$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
10171047
$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
10181048
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1778,10 +1808,18 @@
17781808
17791809
$(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
17801810
$(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
17811811
17821812
$(OBJDIR)/stat.h: $(OBJDIR)/headers
1813
+
1814
+$(OBJDIR)/statrep_.c: $(SRCDIR)/statrep.c $(TRANSLATE)
1815
+ $(TRANSLATE) $(SRCDIR)/statrep.c >$@
1816
+
1817
+$(OBJDIR)/statrep.o: $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
1818
+ $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c
1819
+
1820
+$(OBJDIR)/statrep.h: $(OBJDIR)/headers
17831821
17841822
$(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE)
17851823
$(TRANSLATE) $(SRCDIR)/style.c >$@
17861824
17871825
$(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
17881826
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -146,12 +146,13 @@
146 #### The directories where the OpenSSL include and library files are located.
147 # The recommended usage here is to use the Sysinternals junction tool
148 # to create a hard link between an "openssl-1.x" sub-directory of the
149 # Fossil source code directory and the target OpenSSL source directory.
150 #
151 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include
152 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j
 
153
154 #### Either the directory where the Tcl library is installed or the Tcl
155 # source code directory resides (depending on the value of the macro
156 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
157 # this directory must have "include" and "lib" sub-directories. If
@@ -456,10 +457,11 @@
456 $(SRCDIR)/sitemap.c \
457 $(SRCDIR)/skins.c \
458 $(SRCDIR)/sqlcmd.c \
459 $(SRCDIR)/stash.c \
460 $(SRCDIR)/stat.c \
 
461 $(SRCDIR)/style.c \
462 $(SRCDIR)/sync.c \
463 $(SRCDIR)/tag.c \
464 $(SRCDIR)/tar.c \
465 $(SRCDIR)/th_main.c \
@@ -483,11 +485,36 @@
483 $(SRCDIR)/xfer.c \
484 $(SRCDIR)/xfersetup.c \
485 $(SRCDIR)/zip.c
486
487 EXTRA_FILES = \
488 $(SRCDIR)/diff.tcl
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
490 TRANS_SRC = \
491 $(OBJDIR)/add_.c \
492 $(OBJDIR)/allrepo_.c \
493 $(OBJDIR)/attach_.c \
@@ -578,10 +605,11 @@
578 $(OBJDIR)/sitemap_.c \
579 $(OBJDIR)/skins_.c \
580 $(OBJDIR)/sqlcmd_.c \
581 $(OBJDIR)/stash_.c \
582 $(OBJDIR)/stat_.c \
 
583 $(OBJDIR)/style_.c \
584 $(OBJDIR)/sync_.c \
585 $(OBJDIR)/tag_.c \
586 $(OBJDIR)/tar_.c \
587 $(OBJDIR)/th_main_.c \
@@ -697,10 +725,11 @@
697 $(OBJDIR)/sitemap.o \
698 $(OBJDIR)/skins.o \
699 $(OBJDIR)/sqlcmd.o \
700 $(OBJDIR)/stash.o \
701 $(OBJDIR)/stat.o \
 
702 $(OBJDIR)/style.o \
703 $(OBJDIR)/sync.o \
704 $(OBJDIR)/tag.o \
705 $(OBJDIR)/tar.o \
706 $(OBJDIR)/th_main.o \
@@ -914,11 +943,11 @@
914
915 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX)
916 $(MKINDEX) $(TRANS_SRC) >$@
917
918 $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES)
919 $(MKBUILTIN) $(EXTRA_FILES) >$@
920
921 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
922 $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
923 $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
924 $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -1009,10 +1038,11 @@
1009 $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
1010 $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
1011 $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
1012 $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
1013 $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
 
1014 $(OBJDIR)/style_.c:$(OBJDIR)/style.h \
1015 $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
1016 $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
1017 $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
1018 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1778,10 +1808,18 @@
1778
1779 $(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
1780 $(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
1781
1782 $(OBJDIR)/stat.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1783
1784 $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE)
1785 $(TRANSLATE) $(SRCDIR)/style.c >$@
1786
1787 $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
1788
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -146,12 +146,13 @@
146 #### The directories where the OpenSSL include and library files are located.
147 # The recommended usage here is to use the Sysinternals junction tool
148 # to create a hard link between an "openssl-1.x" sub-directory of the
149 # Fossil source code directory and the target OpenSSL source directory.
150 #
151 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
152 OPENSSLINCDIR = $(OPENSSLDIR)/include
153 OPENSSLLIBDIR = $(OPENSSLDIR)
154
155 #### Either the directory where the Tcl library is installed or the Tcl
156 # source code directory resides (depending on the value of the macro
157 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
158 # this directory must have "include" and "lib" sub-directories. If
@@ -456,10 +457,11 @@
457 $(SRCDIR)/sitemap.c \
458 $(SRCDIR)/skins.c \
459 $(SRCDIR)/sqlcmd.c \
460 $(SRCDIR)/stash.c \
461 $(SRCDIR)/stat.c \
462 $(SRCDIR)/statrep.c \
463 $(SRCDIR)/style.c \
464 $(SRCDIR)/sync.c \
465 $(SRCDIR)/tag.c \
466 $(SRCDIR)/tar.c \
467 $(SRCDIR)/th_main.c \
@@ -483,11 +485,36 @@
485 $(SRCDIR)/xfer.c \
486 $(SRCDIR)/xfersetup.c \
487 $(SRCDIR)/zip.c
488
489 EXTRA_FILES = \
490 $(SRCDIR)/../skins/black_and_white/css.txt \
491 $(SRCDIR)/../skins/black_and_white/footer.txt \
492 $(SRCDIR)/../skins/black_and_white/header.txt \
493 $(SRCDIR)/../skins/default/css.txt \
494 $(SRCDIR)/../skins/default/footer.txt \
495 $(SRCDIR)/../skins/default/header.txt \
496 $(SRCDIR)/../skins/eagle/css.txt \
497 $(SRCDIR)/../skins/eagle/footer.txt \
498 $(SRCDIR)/../skins/eagle/header.txt \
499 $(SRCDIR)/../skins/enhanced1/css.txt \
500 $(SRCDIR)/../skins/enhanced1/footer.txt \
501 $(SRCDIR)/../skins/enhanced1/header.txt \
502 $(SRCDIR)/../skins/etienne1/css.txt \
503 $(SRCDIR)/../skins/etienne1/footer.txt \
504 $(SRCDIR)/../skins/etienne1/header.txt \
505 $(SRCDIR)/../skins/khaki/css.txt \
506 $(SRCDIR)/../skins/khaki/footer.txt \
507 $(SRCDIR)/../skins/khaki/header.txt \
508 $(SRCDIR)/../skins/plain_gray/css.txt \
509 $(SRCDIR)/../skins/plain_gray/footer.txt \
510 $(SRCDIR)/../skins/plain_gray/header.txt \
511 $(SRCDIR)/../skins/rounded1/css.txt \
512 $(SRCDIR)/../skins/rounded1/footer.txt \
513 $(SRCDIR)/../skins/rounded1/header.txt \
514 $(SRCDIR)/diff.tcl \
515 $(SRCDIR)/markdown.md
516
517 TRANS_SRC = \
518 $(OBJDIR)/add_.c \
519 $(OBJDIR)/allrepo_.c \
520 $(OBJDIR)/attach_.c \
@@ -578,10 +605,11 @@
605 $(OBJDIR)/sitemap_.c \
606 $(OBJDIR)/skins_.c \
607 $(OBJDIR)/sqlcmd_.c \
608 $(OBJDIR)/stash_.c \
609 $(OBJDIR)/stat_.c \
610 $(OBJDIR)/statrep_.c \
611 $(OBJDIR)/style_.c \
612 $(OBJDIR)/sync_.c \
613 $(OBJDIR)/tag_.c \
614 $(OBJDIR)/tar_.c \
615 $(OBJDIR)/th_main_.c \
@@ -697,10 +725,11 @@
725 $(OBJDIR)/sitemap.o \
726 $(OBJDIR)/skins.o \
727 $(OBJDIR)/sqlcmd.o \
728 $(OBJDIR)/stash.o \
729 $(OBJDIR)/stat.o \
730 $(OBJDIR)/statrep.o \
731 $(OBJDIR)/style.o \
732 $(OBJDIR)/sync.o \
733 $(OBJDIR)/tag.o \
734 $(OBJDIR)/tar.o \
735 $(OBJDIR)/th_main.o \
@@ -914,11 +943,11 @@
943
944 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX)
945 $(MKINDEX) $(TRANS_SRC) >$@
946
947 $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES)
948 $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
949
950 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
951 $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
952 $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
953 $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -1009,10 +1038,11 @@
1038 $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
1039 $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
1040 $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
1041 $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
1042 $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
1043 $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
1044 $(OBJDIR)/style_.c:$(OBJDIR)/style.h \
1045 $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
1046 $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
1047 $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
1048 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1778,10 +1808,18 @@
1808
1809 $(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
1810 $(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
1811
1812 $(OBJDIR)/stat.h: $(OBJDIR)/headers
1813
1814 $(OBJDIR)/statrep_.c: $(SRCDIR)/statrep.c $(TRANSLATE)
1815 $(TRANSLATE) $(SRCDIR)/statrep.c >$@
1816
1817 $(OBJDIR)/statrep.o: $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
1818 $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c
1819
1820 $(OBJDIR)/statrep.h: $(OBJDIR)/headers
1821
1822 $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE)
1823 $(TRANSLATE) $(SRCDIR)/style.c >$@
1824
1825 $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
1826
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -146,12 +146,13 @@
146146
#### The directories where the OpenSSL include and library files are located.
147147
# The recommended usage here is to use the Sysinternals junction tool
148148
# to create a hard link between an "openssl-1.x" sub-directory of the
149149
# Fossil source code directory and the target OpenSSL source directory.
150150
#
151
-OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include
152
-OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j
151
+OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
152
+OPENSSLINCDIR = $(OPENSSLDIR)/include
153
+OPENSSLLIBDIR = $(OPENSSLDIR)
153154
154155
#### Either the directory where the Tcl library is installed or the Tcl
155156
# source code directory resides (depending on the value of the macro
156157
# FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
157158
# this directory must have "include" and "lib" sub-directories. If
@@ -456,10 +457,11 @@
456457
$(SRCDIR)/sitemap.c \
457458
$(SRCDIR)/skins.c \
458459
$(SRCDIR)/sqlcmd.c \
459460
$(SRCDIR)/stash.c \
460461
$(SRCDIR)/stat.c \
462
+ $(SRCDIR)/statrep.c \
461463
$(SRCDIR)/style.c \
462464
$(SRCDIR)/sync.c \
463465
$(SRCDIR)/tag.c \
464466
$(SRCDIR)/tar.c \
465467
$(SRCDIR)/th_main.c \
@@ -483,11 +485,36 @@
483485
$(SRCDIR)/xfer.c \
484486
$(SRCDIR)/xfersetup.c \
485487
$(SRCDIR)/zip.c
486488
487489
EXTRA_FILES = \
488
- $(SRCDIR)/diff.tcl
490
+ $(SRCDIR)/../skins/black_and_white/css.txt \
491
+ $(SRCDIR)/../skins/black_and_white/footer.txt \
492
+ $(SRCDIR)/../skins/black_and_white/header.txt \
493
+ $(SRCDIR)/../skins/default/css.txt \
494
+ $(SRCDIR)/../skins/default/footer.txt \
495
+ $(SRCDIR)/../skins/default/header.txt \
496
+ $(SRCDIR)/../skins/eagle/css.txt \
497
+ $(SRCDIR)/../skins/eagle/footer.txt \
498
+ $(SRCDIR)/../skins/eagle/header.txt \
499
+ $(SRCDIR)/../skins/enhanced1/css.txt \
500
+ $(SRCDIR)/../skins/enhanced1/footer.txt \
501
+ $(SRCDIR)/../skins/enhanced1/header.txt \
502
+ $(SRCDIR)/../skins/etienne1/css.txt \
503
+ $(SRCDIR)/../skins/etienne1/footer.txt \
504
+ $(SRCDIR)/../skins/etienne1/header.txt \
505
+ $(SRCDIR)/../skins/khaki/css.txt \
506
+ $(SRCDIR)/../skins/khaki/footer.txt \
507
+ $(SRCDIR)/../skins/khaki/header.txt \
508
+ $(SRCDIR)/../skins/plain_gray/css.txt \
509
+ $(SRCDIR)/../skins/plain_gray/footer.txt \
510
+ $(SRCDIR)/../skins/plain_gray/header.txt \
511
+ $(SRCDIR)/../skins/rounded1/css.txt \
512
+ $(SRCDIR)/../skins/rounded1/footer.txt \
513
+ $(SRCDIR)/../skins/rounded1/header.txt \
514
+ $(SRCDIR)/diff.tcl \
515
+ $(SRCDIR)/markdown.md
489516
490517
TRANS_SRC = \
491518
$(OBJDIR)/add_.c \
492519
$(OBJDIR)/allrepo_.c \
493520
$(OBJDIR)/attach_.c \
@@ -578,10 +605,11 @@
578605
$(OBJDIR)/sitemap_.c \
579606
$(OBJDIR)/skins_.c \
580607
$(OBJDIR)/sqlcmd_.c \
581608
$(OBJDIR)/stash_.c \
582609
$(OBJDIR)/stat_.c \
610
+ $(OBJDIR)/statrep_.c \
583611
$(OBJDIR)/style_.c \
584612
$(OBJDIR)/sync_.c \
585613
$(OBJDIR)/tag_.c \
586614
$(OBJDIR)/tar_.c \
587615
$(OBJDIR)/th_main_.c \
@@ -697,10 +725,11 @@
697725
$(OBJDIR)/sitemap.o \
698726
$(OBJDIR)/skins.o \
699727
$(OBJDIR)/sqlcmd.o \
700728
$(OBJDIR)/stash.o \
701729
$(OBJDIR)/stat.o \
730
+ $(OBJDIR)/statrep.o \
702731
$(OBJDIR)/style.o \
703732
$(OBJDIR)/sync.o \
704733
$(OBJDIR)/tag.o \
705734
$(OBJDIR)/tar.o \
706735
$(OBJDIR)/th_main.o \
@@ -914,11 +943,11 @@
914943
915944
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX)
916945
$(MKINDEX) $(TRANS_SRC) >$@
917946
918947
$(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES)
919
- $(MKBUILTIN) $(EXTRA_FILES) >$@
948
+ $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
920949
921950
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
922951
$(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
923952
$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
924953
$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -1009,10 +1038,11 @@
10091038
$(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
10101039
$(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
10111040
$(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
10121041
$(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
10131042
$(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
1043
+ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
10141044
$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
10151045
$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
10161046
$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
10171047
$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
10181048
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1778,10 +1808,18 @@
17781808
17791809
$(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
17801810
$(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
17811811
17821812
$(OBJDIR)/stat.h: $(OBJDIR)/headers
1813
+
1814
+$(OBJDIR)/statrep_.c: $(SRCDIR)/statrep.c $(TRANSLATE)
1815
+ $(TRANSLATE) $(SRCDIR)/statrep.c >$@
1816
+
1817
+$(OBJDIR)/statrep.o: $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
1818
+ $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c
1819
+
1820
+$(OBJDIR)/statrep.h: $(OBJDIR)/headers
17831821
17841822
$(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE)
17851823
$(TRANSLATE) $(SRCDIR)/style.c >$@
17861824
17871825
$(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
17881826
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -146,12 +146,13 @@
146 #### The directories where the OpenSSL include and library files are located.
147 # The recommended usage here is to use the Sysinternals junction tool
148 # to create a hard link between an "openssl-1.x" sub-directory of the
149 # Fossil source code directory and the target OpenSSL source directory.
150 #
151 OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include
152 OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j
 
153
154 #### Either the directory where the Tcl library is installed or the Tcl
155 # source code directory resides (depending on the value of the macro
156 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
157 # this directory must have "include" and "lib" sub-directories. If
@@ -456,10 +457,11 @@
456 $(SRCDIR)/sitemap.c \
457 $(SRCDIR)/skins.c \
458 $(SRCDIR)/sqlcmd.c \
459 $(SRCDIR)/stash.c \
460 $(SRCDIR)/stat.c \
 
461 $(SRCDIR)/style.c \
462 $(SRCDIR)/sync.c \
463 $(SRCDIR)/tag.c \
464 $(SRCDIR)/tar.c \
465 $(SRCDIR)/th_main.c \
@@ -483,11 +485,36 @@
483 $(SRCDIR)/xfer.c \
484 $(SRCDIR)/xfersetup.c \
485 $(SRCDIR)/zip.c
486
487 EXTRA_FILES = \
488 $(SRCDIR)/diff.tcl
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
490 TRANS_SRC = \
491 $(OBJDIR)/add_.c \
492 $(OBJDIR)/allrepo_.c \
493 $(OBJDIR)/attach_.c \
@@ -578,10 +605,11 @@
578 $(OBJDIR)/sitemap_.c \
579 $(OBJDIR)/skins_.c \
580 $(OBJDIR)/sqlcmd_.c \
581 $(OBJDIR)/stash_.c \
582 $(OBJDIR)/stat_.c \
 
583 $(OBJDIR)/style_.c \
584 $(OBJDIR)/sync_.c \
585 $(OBJDIR)/tag_.c \
586 $(OBJDIR)/tar_.c \
587 $(OBJDIR)/th_main_.c \
@@ -697,10 +725,11 @@
697 $(OBJDIR)/sitemap.o \
698 $(OBJDIR)/skins.o \
699 $(OBJDIR)/sqlcmd.o \
700 $(OBJDIR)/stash.o \
701 $(OBJDIR)/stat.o \
 
702 $(OBJDIR)/style.o \
703 $(OBJDIR)/sync.o \
704 $(OBJDIR)/tag.o \
705 $(OBJDIR)/tar.o \
706 $(OBJDIR)/th_main.o \
@@ -914,11 +943,11 @@
914
915 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX)
916 $(MKINDEX) $(TRANS_SRC) >$@
917
918 $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES)
919 $(MKBUILTIN) $(EXTRA_FILES) >$@
920
921 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
922 $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
923 $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
924 $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -1009,10 +1038,11 @@
1009 $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
1010 $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
1011 $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
1012 $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
1013 $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
 
1014 $(OBJDIR)/style_.c:$(OBJDIR)/style.h \
1015 $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
1016 $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
1017 $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
1018 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1778,10 +1808,18 @@
1778
1779 $(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
1780 $(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
1781
1782 $(OBJDIR)/stat.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1783
1784 $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE)
1785 $(TRANSLATE) $(SRCDIR)/style.c >$@
1786
1787 $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
1788
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -146,12 +146,13 @@
146 #### The directories where the OpenSSL include and library files are located.
147 # The recommended usage here is to use the Sysinternals junction tool
148 # to create a hard link between an "openssl-1.x" sub-directory of the
149 # Fossil source code directory and the target OpenSSL source directory.
150 #
151 OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
152 OPENSSLINCDIR = $(OPENSSLDIR)/include
153 OPENSSLLIBDIR = $(OPENSSLDIR)
154
155 #### Either the directory where the Tcl library is installed or the Tcl
156 # source code directory resides (depending on the value of the macro
157 # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory,
158 # this directory must have "include" and "lib" sub-directories. If
@@ -456,10 +457,11 @@
457 $(SRCDIR)/sitemap.c \
458 $(SRCDIR)/skins.c \
459 $(SRCDIR)/sqlcmd.c \
460 $(SRCDIR)/stash.c \
461 $(SRCDIR)/stat.c \
462 $(SRCDIR)/statrep.c \
463 $(SRCDIR)/style.c \
464 $(SRCDIR)/sync.c \
465 $(SRCDIR)/tag.c \
466 $(SRCDIR)/tar.c \
467 $(SRCDIR)/th_main.c \
@@ -483,11 +485,36 @@
485 $(SRCDIR)/xfer.c \
486 $(SRCDIR)/xfersetup.c \
487 $(SRCDIR)/zip.c
488
489 EXTRA_FILES = \
490 $(SRCDIR)/../skins/black_and_white/css.txt \
491 $(SRCDIR)/../skins/black_and_white/footer.txt \
492 $(SRCDIR)/../skins/black_and_white/header.txt \
493 $(SRCDIR)/../skins/default/css.txt \
494 $(SRCDIR)/../skins/default/footer.txt \
495 $(SRCDIR)/../skins/default/header.txt \
496 $(SRCDIR)/../skins/eagle/css.txt \
497 $(SRCDIR)/../skins/eagle/footer.txt \
498 $(SRCDIR)/../skins/eagle/header.txt \
499 $(SRCDIR)/../skins/enhanced1/css.txt \
500 $(SRCDIR)/../skins/enhanced1/footer.txt \
501 $(SRCDIR)/../skins/enhanced1/header.txt \
502 $(SRCDIR)/../skins/etienne1/css.txt \
503 $(SRCDIR)/../skins/etienne1/footer.txt \
504 $(SRCDIR)/../skins/etienne1/header.txt \
505 $(SRCDIR)/../skins/khaki/css.txt \
506 $(SRCDIR)/../skins/khaki/footer.txt \
507 $(SRCDIR)/../skins/khaki/header.txt \
508 $(SRCDIR)/../skins/plain_gray/css.txt \
509 $(SRCDIR)/../skins/plain_gray/footer.txt \
510 $(SRCDIR)/../skins/plain_gray/header.txt \
511 $(SRCDIR)/../skins/rounded1/css.txt \
512 $(SRCDIR)/../skins/rounded1/footer.txt \
513 $(SRCDIR)/../skins/rounded1/header.txt \
514 $(SRCDIR)/diff.tcl \
515 $(SRCDIR)/markdown.md
516
517 TRANS_SRC = \
518 $(OBJDIR)/add_.c \
519 $(OBJDIR)/allrepo_.c \
520 $(OBJDIR)/attach_.c \
@@ -578,10 +605,11 @@
605 $(OBJDIR)/sitemap_.c \
606 $(OBJDIR)/skins_.c \
607 $(OBJDIR)/sqlcmd_.c \
608 $(OBJDIR)/stash_.c \
609 $(OBJDIR)/stat_.c \
610 $(OBJDIR)/statrep_.c \
611 $(OBJDIR)/style_.c \
612 $(OBJDIR)/sync_.c \
613 $(OBJDIR)/tag_.c \
614 $(OBJDIR)/tar_.c \
615 $(OBJDIR)/th_main_.c \
@@ -697,10 +725,11 @@
725 $(OBJDIR)/sitemap.o \
726 $(OBJDIR)/skins.o \
727 $(OBJDIR)/sqlcmd.o \
728 $(OBJDIR)/stash.o \
729 $(OBJDIR)/stat.o \
730 $(OBJDIR)/statrep.o \
731 $(OBJDIR)/style.o \
732 $(OBJDIR)/sync.o \
733 $(OBJDIR)/tag.o \
734 $(OBJDIR)/tar.o \
735 $(OBJDIR)/th_main.o \
@@ -914,11 +943,11 @@
943
944 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(MKINDEX)
945 $(MKINDEX) $(TRANS_SRC) >$@
946
947 $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES)
948 $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@
949
950 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h
951 $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
952 $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
953 $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
@@ -1009,10 +1038,11 @@
1038 $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
1039 $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
1040 $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
1041 $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
1042 $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
1043 $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
1044 $(OBJDIR)/style_.c:$(OBJDIR)/style.h \
1045 $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
1046 $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
1047 $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
1048 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
@@ -1778,10 +1808,18 @@
1808
1809 $(OBJDIR)/stat.o: $(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
1810 $(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c
1811
1812 $(OBJDIR)/stat.h: $(OBJDIR)/headers
1813
1814 $(OBJDIR)/statrep_.c: $(SRCDIR)/statrep.c $(TRANSLATE)
1815 $(TRANSLATE) $(SRCDIR)/statrep.c >$@
1816
1817 $(OBJDIR)/statrep.o: $(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
1818 $(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c
1819
1820 $(OBJDIR)/statrep.h: $(OBJDIR)/headers
1821
1822 $(OBJDIR)/style_.c: $(SRCDIR)/style.c $(TRANSLATE)
1823 $(TRANSLATE) $(SRCDIR)/style.c >$@
1824
1825 $(OBJDIR)/style.o: $(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
1826
+38 -3
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -55,11 +55,11 @@
5555
5656
# Uncomment to enable Tcl support
5757
# FOSSIL_ENABLE_TCL = 1
5858
5959
!ifdef FOSSIL_ENABLE_SSL
60
-SSLDIR = $(B)\compat\openssl-1.0.1j
60
+SSLDIR = $(B)\compat\openssl-1.0.2
6161
SSLINCDIR = $(SSLDIR)\inc32
6262
SSLLIBDIR = $(SSLDIR)\out32
6363
SSLLFLAGS = /nologo /opt:ref /debug
6464
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
6565
!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
@@ -296,10 +296,11 @@
296296
sitemap_.c \
297297
skins_.c \
298298
sqlcmd_.c \
299299
stash_.c \
300300
stat_.c \
301
+ statrep_.c \
301302
style_.c \
302303
sync_.c \
303304
tag_.c \
304305
tar_.c \
305306
th_main_.c \
@@ -322,11 +323,36 @@
322323
wysiwyg_.c \
323324
xfer_.c \
324325
xfersetup_.c \
325326
zip_.c
326327
327
-EXTRA_FILES = $(SRCDIR)\diff.tcl
328
+EXTRA_FILES = $(SRCDIR)\../skins/black_and_white/css.txt \
329
+ $(SRCDIR)\../skins/black_and_white/footer.txt \
330
+ $(SRCDIR)\../skins/black_and_white/header.txt \
331
+ $(SRCDIR)\../skins/default/css.txt \
332
+ $(SRCDIR)\../skins/default/footer.txt \
333
+ $(SRCDIR)\../skins/default/header.txt \
334
+ $(SRCDIR)\../skins/eagle/css.txt \
335
+ $(SRCDIR)\../skins/eagle/footer.txt \
336
+ $(SRCDIR)\../skins/eagle/header.txt \
337
+ $(SRCDIR)\../skins/enhanced1/css.txt \
338
+ $(SRCDIR)\../skins/enhanced1/footer.txt \
339
+ $(SRCDIR)\../skins/enhanced1/header.txt \
340
+ $(SRCDIR)\../skins/etienne1/css.txt \
341
+ $(SRCDIR)\../skins/etienne1/footer.txt \
342
+ $(SRCDIR)\../skins/etienne1/header.txt \
343
+ $(SRCDIR)\../skins/khaki/css.txt \
344
+ $(SRCDIR)\../skins/khaki/footer.txt \
345
+ $(SRCDIR)\../skins/khaki/header.txt \
346
+ $(SRCDIR)\../skins/plain_gray/css.txt \
347
+ $(SRCDIR)\../skins/plain_gray/footer.txt \
348
+ $(SRCDIR)\../skins/plain_gray/header.txt \
349
+ $(SRCDIR)\../skins/rounded1/css.txt \
350
+ $(SRCDIR)\../skins/rounded1/footer.txt \
351
+ $(SRCDIR)\../skins/rounded1/header.txt \
352
+ $(SRCDIR)\diff.tcl \
353
+ $(SRCDIR)\markdown.md
328354
329355
OBJ = $(OX)\add$O \
330356
$(OX)\allrepo$O \
331357
$(OX)\attach$O \
332358
$(OX)\bag$O \
@@ -419,10 +445,11 @@
419445
$(OX)\skins$O \
420446
$(OX)\sqlcmd$O \
421447
$(OX)\sqlite3$O \
422448
$(OX)\stash$O \
423449
$(OX)\stat$O \
450
+ $(OX)\statrep$O \
424451
$(OX)\style$O \
425452
$(OX)\sync$O \
426453
$(OX)\tag$O \
427454
$(OX)\tar$O \
428455
$(OX)\th$O \
@@ -593,10 +620,11 @@
593620
echo $(OX)\skins.obj >> $@
594621
echo $(OX)\sqlcmd.obj >> $@
595622
echo $(OX)\sqlite3.obj >> $@
596623
echo $(OX)\stash.obj >> $@
597624
echo $(OX)\stat.obj >> $@
625
+ echo $(OX)\statrep.obj >> $@
598626
echo $(OX)\style.obj >> $@
599627
echo $(OX)\sync.obj >> $@
600628
echo $(OX)\tag.obj >> $@
601629
echo $(OX)\tar.obj >> $@
602630
echo $(OX)\th.obj >> $@
@@ -674,11 +702,11 @@
674702
675703
page_index.h: mkindex$E $(SRC)
676704
$** > $@
677705
678706
builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
679
- $** > $@
707
+ mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
680708
681709
clean:
682710
-del $(OX)\*.obj
683711
-del *.obj
684712
-del *_.c
@@ -1271,10 +1299,16 @@
12711299
$(OX)\stat$O : stat_.c stat.h
12721300
$(TCC) /Fo$@ -c stat_.c
12731301
12741302
stat_.c : $(SRCDIR)\stat.c
12751303
translate$E $** > $@
1304
+
1305
+$(OX)\statrep$O : statrep_.c statrep.h
1306
+ $(TCC) /Fo$@ -c statrep_.c
1307
+
1308
+statrep_.c : $(SRCDIR)\statrep.c
1309
+ translate$E $** > $@
12761310
12771311
$(OX)\style$O : style_.c style.h
12781312
$(TCC) /Fo$@ -c style_.c
12791313
12801314
style_.c : $(SRCDIR)\style.c
@@ -1518,10 +1552,11 @@
15181552
sitemap_.c:sitemap.h \
15191553
skins_.c:skins.h \
15201554
sqlcmd_.c:sqlcmd.h \
15211555
stash_.c:stash.h \
15221556
stat_.c:stat.h \
1557
+ statrep_.c:statrep.h \
15231558
style_.c:style.h \
15241559
sync_.c:sync.h \
15251560
tag_.c:tag.h \
15261561
tar_.c:tar.h \
15271562
th_main_.c:th_main.h \
15281563
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -55,11 +55,11 @@
55
56 # Uncomment to enable Tcl support
57 # FOSSIL_ENABLE_TCL = 1
58
59 !ifdef FOSSIL_ENABLE_SSL
60 SSLDIR = $(B)\compat\openssl-1.0.1j
61 SSLINCDIR = $(SSLDIR)\inc32
62 SSLLIBDIR = $(SSLDIR)\out32
63 SSLLFLAGS = /nologo /opt:ref /debug
64 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
65 !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
@@ -296,10 +296,11 @@
296 sitemap_.c \
297 skins_.c \
298 sqlcmd_.c \
299 stash_.c \
300 stat_.c \
 
301 style_.c \
302 sync_.c \
303 tag_.c \
304 tar_.c \
305 th_main_.c \
@@ -322,11 +323,36 @@
322 wysiwyg_.c \
323 xfer_.c \
324 xfersetup_.c \
325 zip_.c
326
327 EXTRA_FILES = $(SRCDIR)\diff.tcl
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
329 OBJ = $(OX)\add$O \
330 $(OX)\allrepo$O \
331 $(OX)\attach$O \
332 $(OX)\bag$O \
@@ -419,10 +445,11 @@
419 $(OX)\skins$O \
420 $(OX)\sqlcmd$O \
421 $(OX)\sqlite3$O \
422 $(OX)\stash$O \
423 $(OX)\stat$O \
 
424 $(OX)\style$O \
425 $(OX)\sync$O \
426 $(OX)\tag$O \
427 $(OX)\tar$O \
428 $(OX)\th$O \
@@ -593,10 +620,11 @@
593 echo $(OX)\skins.obj >> $@
594 echo $(OX)\sqlcmd.obj >> $@
595 echo $(OX)\sqlite3.obj >> $@
596 echo $(OX)\stash.obj >> $@
597 echo $(OX)\stat.obj >> $@
 
598 echo $(OX)\style.obj >> $@
599 echo $(OX)\sync.obj >> $@
600 echo $(OX)\tag.obj >> $@
601 echo $(OX)\tar.obj >> $@
602 echo $(OX)\th.obj >> $@
@@ -674,11 +702,11 @@
674
675 page_index.h: mkindex$E $(SRC)
676 $** > $@
677
678 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
679 $** > $@
680
681 clean:
682 -del $(OX)\*.obj
683 -del *.obj
684 -del *_.c
@@ -1271,10 +1299,16 @@
1271 $(OX)\stat$O : stat_.c stat.h
1272 $(TCC) /Fo$@ -c stat_.c
1273
1274 stat_.c : $(SRCDIR)\stat.c
1275 translate$E $** > $@
 
 
 
 
 
 
1276
1277 $(OX)\style$O : style_.c style.h
1278 $(TCC) /Fo$@ -c style_.c
1279
1280 style_.c : $(SRCDIR)\style.c
@@ -1518,10 +1552,11 @@
1518 sitemap_.c:sitemap.h \
1519 skins_.c:skins.h \
1520 sqlcmd_.c:sqlcmd.h \
1521 stash_.c:stash.h \
1522 stat_.c:stat.h \
 
1523 style_.c:style.h \
1524 sync_.c:sync.h \
1525 tag_.c:tag.h \
1526 tar_.c:tar.h \
1527 th_main_.c:th_main.h \
1528
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -55,11 +55,11 @@
55
56 # Uncomment to enable Tcl support
57 # FOSSIL_ENABLE_TCL = 1
58
59 !ifdef FOSSIL_ENABLE_SSL
60 SSLDIR = $(B)\compat\openssl-1.0.2
61 SSLINCDIR = $(SSLDIR)\inc32
62 SSLLIBDIR = $(SSLDIR)\out32
63 SSLLFLAGS = /nologo /opt:ref /debug
64 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
65 !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
@@ -296,10 +296,11 @@
296 sitemap_.c \
297 skins_.c \
298 sqlcmd_.c \
299 stash_.c \
300 stat_.c \
301 statrep_.c \
302 style_.c \
303 sync_.c \
304 tag_.c \
305 tar_.c \
306 th_main_.c \
@@ -322,11 +323,36 @@
323 wysiwyg_.c \
324 xfer_.c \
325 xfersetup_.c \
326 zip_.c
327
328 EXTRA_FILES = $(SRCDIR)\../skins/black_and_white/css.txt \
329 $(SRCDIR)\../skins/black_and_white/footer.txt \
330 $(SRCDIR)\../skins/black_and_white/header.txt \
331 $(SRCDIR)\../skins/default/css.txt \
332 $(SRCDIR)\../skins/default/footer.txt \
333 $(SRCDIR)\../skins/default/header.txt \
334 $(SRCDIR)\../skins/eagle/css.txt \
335 $(SRCDIR)\../skins/eagle/footer.txt \
336 $(SRCDIR)\../skins/eagle/header.txt \
337 $(SRCDIR)\../skins/enhanced1/css.txt \
338 $(SRCDIR)\../skins/enhanced1/footer.txt \
339 $(SRCDIR)\../skins/enhanced1/header.txt \
340 $(SRCDIR)\../skins/etienne1/css.txt \
341 $(SRCDIR)\../skins/etienne1/footer.txt \
342 $(SRCDIR)\../skins/etienne1/header.txt \
343 $(SRCDIR)\../skins/khaki/css.txt \
344 $(SRCDIR)\../skins/khaki/footer.txt \
345 $(SRCDIR)\../skins/khaki/header.txt \
346 $(SRCDIR)\../skins/plain_gray/css.txt \
347 $(SRCDIR)\../skins/plain_gray/footer.txt \
348 $(SRCDIR)\../skins/plain_gray/header.txt \
349 $(SRCDIR)\../skins/rounded1/css.txt \
350 $(SRCDIR)\../skins/rounded1/footer.txt \
351 $(SRCDIR)\../skins/rounded1/header.txt \
352 $(SRCDIR)\diff.tcl \
353 $(SRCDIR)\markdown.md
354
355 OBJ = $(OX)\add$O \
356 $(OX)\allrepo$O \
357 $(OX)\attach$O \
358 $(OX)\bag$O \
@@ -419,10 +445,11 @@
445 $(OX)\skins$O \
446 $(OX)\sqlcmd$O \
447 $(OX)\sqlite3$O \
448 $(OX)\stash$O \
449 $(OX)\stat$O \
450 $(OX)\statrep$O \
451 $(OX)\style$O \
452 $(OX)\sync$O \
453 $(OX)\tag$O \
454 $(OX)\tar$O \
455 $(OX)\th$O \
@@ -593,10 +620,11 @@
620 echo $(OX)\skins.obj >> $@
621 echo $(OX)\sqlcmd.obj >> $@
622 echo $(OX)\sqlite3.obj >> $@
623 echo $(OX)\stash.obj >> $@
624 echo $(OX)\stat.obj >> $@
625 echo $(OX)\statrep.obj >> $@
626 echo $(OX)\style.obj >> $@
627 echo $(OX)\sync.obj >> $@
628 echo $(OX)\tag.obj >> $@
629 echo $(OX)\tar.obj >> $@
630 echo $(OX)\th.obj >> $@
@@ -674,11 +702,11 @@
702
703 page_index.h: mkindex$E $(SRC)
704 $** > $@
705
706 builtin_data.h: mkbuiltin$E $(EXTRA_FILES)
707 mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@
708
709 clean:
710 -del $(OX)\*.obj
711 -del *.obj
712 -del *_.c
@@ -1271,10 +1299,16 @@
1299 $(OX)\stat$O : stat_.c stat.h
1300 $(TCC) /Fo$@ -c stat_.c
1301
1302 stat_.c : $(SRCDIR)\stat.c
1303 translate$E $** > $@
1304
1305 $(OX)\statrep$O : statrep_.c statrep.h
1306 $(TCC) /Fo$@ -c statrep_.c
1307
1308 statrep_.c : $(SRCDIR)\statrep.c
1309 translate$E $** > $@
1310
1311 $(OX)\style$O : style_.c style.h
1312 $(TCC) /Fo$@ -c style_.c
1313
1314 style_.c : $(SRCDIR)\style.c
@@ -1518,10 +1552,11 @@
1552 sitemap_.c:sitemap.h \
1553 skins_.c:skins.h \
1554 sqlcmd_.c:sqlcmd.h \
1555 stash_.c:stash.h \
1556 stat_.c:stat.h \
1557 statrep_.c:statrep.h \
1558 style_.c:style.h \
1559 sync_.c:sync.h \
1560 tag_.c:tag.h \
1561 tar_.c:tar.h \
1562 th_main_.c:th_main.h \
1563
--- win/include/unistd.h
+++ win/include/unistd.h
@@ -1,11 +1,11 @@
11
#ifndef _UNISTD_H
22
#define _UNISTD_H 1
33
4
-/* This file intended to serve as a drop-in replacement for
4
+/* This file intended to serve as a drop-in replacement for
55
* unistd.h on Windows
6
- * Please add functionality as neeeded
6
+ * Please add functionality as neeeded
77
*/
88
99
#include <stdlib.h>
1010
#include <io.h>
1111
#define srandom srand
1212
--- win/include/unistd.h
+++ win/include/unistd.h
@@ -1,11 +1,11 @@
1 #ifndef _UNISTD_H
2 #define _UNISTD_H 1
3
4 /* This file intended to serve as a drop-in replacement for
5 * unistd.h on Windows
6 * Please add functionality as neeeded
7 */
8
9 #include <stdlib.h>
10 #include <io.h>
11 #define srandom srand
12
--- win/include/unistd.h
+++ win/include/unistd.h
@@ -1,11 +1,11 @@
1 #ifndef _UNISTD_H
2 #define _UNISTD_H 1
3
4 /* This file intended to serve as a drop-in replacement for
5 * unistd.h on Windows
6 * Please add functionality as neeeded
7 */
8
9 #include <stdlib.h>
10 #include <io.h>
11 #define srandom srand
12
+1 -1
--- www/build.wiki
+++ www/build.wiki
@@ -122,11 +122,11 @@
122122
the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
123123
first <a href="https://www.openssl.org/source/">download the official
124124
source code for OpenSSL</a> and extract it to an appropriately named
125125
"<b>openssl-X.Y.ZA</b>" subdirectory within the local
126126
[/tree?ci=trunk&name=compat | compat] directory (e.g.
127
-"<b>compat/openssl-1.0.1j</b>"), then make sure that some recent
127
+"<b>compat/openssl-1.0.2</b>"), then make sure that some recent
128128
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
129129
and finally run one of the following commands:
130130
<blockquote><pre>
131131
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
132132
</pre></blockquote>
133133
--- www/build.wiki
+++ www/build.wiki
@@ -122,11 +122,11 @@
122 the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
123 first <a href="https://www.openssl.org/source/">download the official
124 source code for OpenSSL</a> and extract it to an appropriately named
125 "<b>openssl-X.Y.ZA</b>" subdirectory within the local
126 [/tree?ci=trunk&name=compat | compat] directory (e.g.
127 "<b>compat/openssl-1.0.1j</b>"), then make sure that some recent
128 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
129 and finally run one of the following commands:
130 <blockquote><pre>
131 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
132 </pre></blockquote>
133
--- www/build.wiki
+++ www/build.wiki
@@ -122,11 +122,11 @@
122 the optional <a href="https://www.openssl.org/">OpenSSL</a> support,
123 first <a href="https://www.openssl.org/source/">download the official
124 source code for OpenSSL</a> and extract it to an appropriately named
125 "<b>openssl-X.Y.ZA</b>" subdirectory within the local
126 [/tree?ci=trunk&name=compat | compat] directory (e.g.
127 "<b>compat/openssl-1.0.2</b>"), then make sure that some recent
128 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
129 and finally run one of the following commands:
130 <blockquote><pre>
131 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
132 </pre></blockquote>
133
+75 -13
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,34 +1,96 @@
11
<title>Change Log</title>
22
3
-<h2>Changes For Version 1.30 (as yet unreleased)</h2>
4
- * Add setting to control the number of times autosync will be tried before
5
- returning an error.
3
+<h2>Changes For Version 1.31 (2015-??-??)</h2>
4
+ * Add direct Subversion import support to
5
+ [/help?cmd=import|fossil import]. (??)
6
+ * Add IPv6 support to [/help?cmd=sync|fossil sync] and
7
+ [/help?cmd=clone|fossil clone]
8
+ * Add more skins such as "San Francisco Modern" and "Eagle".
9
+ * Update SQLite to version 3.8.9. (??)
10
+ * Improve the display of the history of changes to a single
11
+ file. A [/help?cmd=rebuild|fossil rebuild] is needed for that.
12
+ * Enable ZIP and Tarball downloads for user "nobody" by default.
13
+ * Make the now() SQL function available in the
14
+ [/help?cmd=sqlite|fossil sqlite] command.
15
+ * Improve table sorting in various pages.
16
+ * Add support for setting environment variables from within CGI script
17
+ files.
18
+ * Enhance the Ad-Unit processing to allow a choice of two different
19
+ ad-units.
20
+ * During shutdown, check to see if the check-out database (".fslckout")
21
+ contains a lot of free space, and if it does, VACUUM it.
22
+
23
+<h2>Changes For Version 1.30 (2015-01-19)</h2>
24
+ * Added the [/help?cmd=bundle|fossil bundle] command.
25
+ * Added the [/help?cmd=purge|fossil purge] command.
26
+ * Added the [/help?cmd=publish|fossil publish] command.
27
+ * Added the [/help?cmd=unpublished|fossil unpublished] command.
28
+ * Enhance the [/tree] webpage to show the age of each file with the option
29
+ to sort by age.
30
+ * Enhance the [/brlist] webpage to show additional information about each branch
31
+ and to be sortable by clicking on column headers.
32
+ * Add support for Docker. Just install docker and type
33
+ "sudo docker run -d -p 8080:8080 nijtmans/fossil" to get it running.
634
* Add the [/help/fusefs|fossil fusefs DIRECTORY] command that mounts a
735
Fuse Filesystem at the given DIRECTORY and populates it with read-only
836
copies of all historical check-ins. This only works on systems that
937
support FuseFS.
38
+ * Add the administrative log that records all configuration.
39
+ * Added the [/sitemap] webpage.
40
+ * Added the [/bloblist] web page.
41
+ * Let [/help?cmd=new|fossil new] no longer create an initial empty commit
42
+ by default. The first commit after checking out an empty repository will
43
+ become the initial commit.
44
+ * Added the [/help?cmd=all|fossil all dbstat] and
45
+ [/help?cmd=all|fossil all info] commands.
46
+ * Update SQLite to version 3.8.8.
47
+ * Added the --verily option to the [/help?cmd=clean|fossil clean] command.
48
+ * Add the "autosync-tries" setting to control the number of autosync attempts
49
+ before returning an error.
1050
* Added a compile-time option (--with-miniz) to build using miniz instead
1151
of zlib. Disabled by default.
12
- * Several fixes to the TH1 expression parser.
1352
* Support customization of commands and webpages, including the ability to
1453
add new ones, via the "TH1 hooks" feature. Disabled by default. Enabled
1554
via a compile-time option.
1655
* Add the <nowiki>[checkout], [render], [styleHeader], [styleFooter],
1756
[trace], [getParameter], [setParameter], [artifact], and
1857
[globalState]</nowiki> commands to TH1, primarily for use by TH1 hooks.
19
- * Bring in the latest version of autosetup from upstream.
20
- * When committing a (non-binary) file which contains bytes forming an
21
- invalid UTF-8 stream, fossil now adds the possibility to convert it
22
- to a valid UTF-8 stream ('c') if you like.
23
- * Let [/help?cmd=new|fossil new] no longer create an initial empty commit
24
- by default. The first commit after checking out an empty repository will
25
- become the initial commit. (NOT PLANNED FOR 1.30, BUT DONE TO EXPOSE
26
- [/help?cmd=new|fossil new --empty] TO MORE FIELD TESTING BEFORE
27
- MAKING ANY DECISION ON IT!)
58
+ * Automatically adjust the width of command-line timeline output according to the
59
+ detected width of the terminal.
60
+ * Prompt the user to optionally fix invalid UTF-8 at check-in.
2861
* Added a line-number toggle option to the [/help?cmd=/info|/info]
2962
and [/help?cmd=/artifact|/artifact] pages.
63
+ * Most commands now issue errors rather than silently ignoring unrecognized
64
+ command-line options.
65
+ * Use full 40-character SHA1 hashes (instead of abbreviations) in most
66
+ internal URLs.
67
+ * The "ssh:" sync method on windows now uses "plink.exe" instead of "ssh" as
68
+ the secure-shell client program.
69
+ * Prevent a partial clone when the connection is lost.
70
+ * Make the distinction between 301 and 302 redirects.
71
+ * Allow commits against a closed check-in as long as the commit goes onto
72
+ a different branch.
73
+ * Improved cache control in the web interface reduces unnecessary requests
74
+ for common resources like the page logo and CSS.
75
+ * Fix a rare and long-standing sync protocol bug
76
+ that would silently prevent the sync from running to completion. Before
77
+ this bug-fix it was sometimes necessary to do "fossil sync --verily" to
78
+ get two repositories in sync.
79
+ * Add the [/finfo?name=src/foci.c|files_of_checkin] virtual table - useful
80
+ for ad hoc queries in the [/help?cmd=sqlite3|fossil sql] interface,
81
+ and also used internally.
82
+ * Added the "$secureurl" TH1 variable for use in headers and footers.
83
+ * (Internal:) Add the ability to include resources as separate files in the
84
+ source tree that are converted into constant byte arrays in the compiled
85
+ binary. Use this feature to store the Tk script that implements the --tk
86
+ diff option in a separate file for easier editing.
87
+ * (Internal:) Implement a system of compile-time checks to help ensure
88
+ the correctness of printf-style formatting strings.
89
+ * Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability.
90
+ * Numerous documentation fixes and improvements.
91
+ * Other obscure and minor bug fixes - see the timeline for details.
3092
3193
<h2>Changes For Version 1.29 (2014-06-12)</h2>
3294
* Add the ability to display content, diffs and annotations for UTF16
3395
text files in the web interface.
3496
* Add the "SaveAs..." and "Invert" buttons
3597
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,34 +1,96 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.30 (as yet unreleased)</h2>
4 * Add setting to control the number of times autosync will be tried before
5 returning an error.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6 * Add the [/help/fusefs|fossil fusefs DIRECTORY] command that mounts a
7 Fuse Filesystem at the given DIRECTORY and populates it with read-only
8 copies of all historical check-ins. This only works on systems that
9 support FuseFS.
 
 
 
 
 
 
 
 
 
 
 
 
10 * Added a compile-time option (--with-miniz) to build using miniz instead
11 of zlib. Disabled by default.
12 * Several fixes to the TH1 expression parser.
13 * Support customization of commands and webpages, including the ability to
14 add new ones, via the "TH1 hooks" feature. Disabled by default. Enabled
15 via a compile-time option.
16 * Add the <nowiki>[checkout], [render], [styleHeader], [styleFooter],
17 [trace], [getParameter], [setParameter], [artifact], and
18 [globalState]</nowiki> commands to TH1, primarily for use by TH1 hooks.
19 * Bring in the latest version of autosetup from upstream.
20 * When committing a (non-binary) file which contains bytes forming an
21 invalid UTF-8 stream, fossil now adds the possibility to convert it
22 to a valid UTF-8 stream ('c') if you like.
23 * Let [/help?cmd=new|fossil new] no longer create an initial empty commit
24 by default. The first commit after checking out an empty repository will
25 become the initial commit. (NOT PLANNED FOR 1.30, BUT DONE TO EXPOSE
26 [/help?cmd=new|fossil new --empty] TO MORE FIELD TESTING BEFORE
27 MAKING ANY DECISION ON IT!)
28 * Added a line-number toggle option to the [/help?cmd=/info|/info]
29 and [/help?cmd=/artifact|/artifact] pages.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
31 <h2>Changes For Version 1.29 (2014-06-12)</h2>
32 * Add the ability to display content, diffs and annotations for UTF16
33 text files in the web interface.
34 * Add the "SaveAs..." and "Invert" buttons
35
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,34 +1,96 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.31 (2015-??-??)</h2>
4 * Add direct Subversion import support to
5 [/help?cmd=import|fossil import]. (??)
6 * Add IPv6 support to [/help?cmd=sync|fossil sync] and
7 [/help?cmd=clone|fossil clone]
8 * Add more skins such as "San Francisco Modern" and "Eagle".
9 * Update SQLite to version 3.8.9. (??)
10 * Improve the display of the history of changes to a single
11 file. A [/help?cmd=rebuild|fossil rebuild] is needed for that.
12 * Enable ZIP and Tarball downloads for user "nobody" by default.
13 * Make the now() SQL function available in the
14 [/help?cmd=sqlite|fossil sqlite] command.
15 * Improve table sorting in various pages.
16 * Add support for setting environment variables from within CGI script
17 files.
18 * Enhance the Ad-Unit processing to allow a choice of two different
19 ad-units.
20 * During shutdown, check to see if the check-out database (".fslckout")
21 contains a lot of free space, and if it does, VACUUM it.
22
23 <h2>Changes For Version 1.30 (2015-01-19)</h2>
24 * Added the [/help?cmd=bundle|fossil bundle] command.
25 * Added the [/help?cmd=purge|fossil purge] command.
26 * Added the [/help?cmd=publish|fossil publish] command.
27 * Added the [/help?cmd=unpublished|fossil unpublished] command.
28 * Enhance the [/tree] webpage to show the age of each file with the option
29 to sort by age.
30 * Enhance the [/brlist] webpage to show additional information about each branch
31 and to be sortable by clicking on column headers.
32 * Add support for Docker. Just install docker and type
33 "sudo docker run -d -p 8080:8080 nijtmans/fossil" to get it running.
34 * Add the [/help/fusefs|fossil fusefs DIRECTORY] command that mounts a
35 Fuse Filesystem at the given DIRECTORY and populates it with read-only
36 copies of all historical check-ins. This only works on systems that
37 support FuseFS.
38 * Add the administrative log that records all configuration.
39 * Added the [/sitemap] webpage.
40 * Added the [/bloblist] web page.
41 * Let [/help?cmd=new|fossil new] no longer create an initial empty commit
42 by default. The first commit after checking out an empty repository will
43 become the initial commit.
44 * Added the [/help?cmd=all|fossil all dbstat] and
45 [/help?cmd=all|fossil all info] commands.
46 * Update SQLite to version 3.8.8.
47 * Added the --verily option to the [/help?cmd=clean|fossil clean] command.
48 * Add the "autosync-tries" setting to control the number of autosync attempts
49 before returning an error.
50 * Added a compile-time option (--with-miniz) to build using miniz instead
51 of zlib. Disabled by default.
 
52 * Support customization of commands and webpages, including the ability to
53 add new ones, via the "TH1 hooks" feature. Disabled by default. Enabled
54 via a compile-time option.
55 * Add the <nowiki>[checkout], [render], [styleHeader], [styleFooter],
56 [trace], [getParameter], [setParameter], [artifact], and
57 [globalState]</nowiki> commands to TH1, primarily for use by TH1 hooks.
58 * Automatically adjust the width of command-line timeline output according to the
59 detected width of the terminal.
60 * Prompt the user to optionally fix invalid UTF-8 at check-in.
 
 
 
 
 
 
61 * Added a line-number toggle option to the [/help?cmd=/info|/info]
62 and [/help?cmd=/artifact|/artifact] pages.
63 * Most commands now issue errors rather than silently ignoring unrecognized
64 command-line options.
65 * Use full 40-character SHA1 hashes (instead of abbreviations) in most
66 internal URLs.
67 * The "ssh:" sync method on windows now uses "plink.exe" instead of "ssh" as
68 the secure-shell client program.
69 * Prevent a partial clone when the connection is lost.
70 * Make the distinction between 301 and 302 redirects.
71 * Allow commits against a closed check-in as long as the commit goes onto
72 a different branch.
73 * Improved cache control in the web interface reduces unnecessary requests
74 for common resources like the page logo and CSS.
75 * Fix a rare and long-standing sync protocol bug
76 that would silently prevent the sync from running to completion. Before
77 this bug-fix it was sometimes necessary to do "fossil sync --verily" to
78 get two repositories in sync.
79 * Add the [/finfo?name=src/foci.c|files_of_checkin] virtual table - useful
80 for ad hoc queries in the [/help?cmd=sqlite3|fossil sql] interface,
81 and also used internally.
82 * Added the "$secureurl" TH1 variable for use in headers and footers.
83 * (Internal:) Add the ability to include resources as separate files in the
84 source tree that are converted into constant byte arrays in the compiled
85 binary. Use this feature to store the Tk script that implements the --tk
86 diff option in a separate file for easier editing.
87 * (Internal:) Implement a system of compile-time checks to help ensure
88 the correctness of printf-style formatting strings.
89 * Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability.
90 * Numerous documentation fixes and improvements.
91 * Other obscure and minor bug fixes - see the timeline for details.
92
93 <h2>Changes For Version 1.29 (2014-06-12)</h2>
94 * Add the ability to display content, diffs and annotations for UTF16
95 text files in the web interface.
96 * Add the "SaveAs..." and "Invert" buttons
97
--- www/delta_format.wiki
+++ www/delta_format.wiki
@@ -66,11 +66,11 @@
6666
<a name="slist"></a><h3>1.3 Segment-List</h3>
6767
<img src="delta2.gif" align="left" hspace="10">
6868
6969
<p>The segment-list of a delta describes how to create the target from
7070
the original by a combination of inserting literal byte-sequences and
71
-copying ranges of bytes from the original. This is there the
71
+copying ranges of bytes from the original. This is where the
7272
compression takes place, by encoding the large common parts of
7373
original and target in small copy instructions.</p>
7474
7575
<p>The target is constructed from beginning to end, with the data
7676
generated by each instruction appended after the data of all previous
@@ -213,11 +213,11 @@
213213
<ul>
214214
<li>Pure text files generate a pure text delta.
215215
</li>
216216
<li>Binary files generate a delta that may contain some binary data.
217217
</li>
218
-<li>The delta encoding does not attempt to compress the content
218
+<li>The delta encoding does not attempt to compress the content.
219219
It was considered to be much
220220
more sensible to do compression using a separate general-purpose
221221
compression library, like <a href="http://www.zlib.net">zlib</a>.
222222
</li>
223223
</ul>
224224
--- www/delta_format.wiki
+++ www/delta_format.wiki
@@ -66,11 +66,11 @@
66 <a name="slist"></a><h3>1.3 Segment-List</h3>
67 <img src="delta2.gif" align="left" hspace="10">
68
69 <p>The segment-list of a delta describes how to create the target from
70 the original by a combination of inserting literal byte-sequences and
71 copying ranges of bytes from the original. This is there the
72 compression takes place, by encoding the large common parts of
73 original and target in small copy instructions.</p>
74
75 <p>The target is constructed from beginning to end, with the data
76 generated by each instruction appended after the data of all previous
@@ -213,11 +213,11 @@
213 <ul>
214 <li>Pure text files generate a pure text delta.
215 </li>
216 <li>Binary files generate a delta that may contain some binary data.
217 </li>
218 <li>The delta encoding does not attempt to compress the content
219 It was considered to be much
220 more sensible to do compression using a separate general-purpose
221 compression library, like <a href="http://www.zlib.net">zlib</a>.
222 </li>
223 </ul>
224
--- www/delta_format.wiki
+++ www/delta_format.wiki
@@ -66,11 +66,11 @@
66 <a name="slist"></a><h3>1.3 Segment-List</h3>
67 <img src="delta2.gif" align="left" hspace="10">
68
69 <p>The segment-list of a delta describes how to create the target from
70 the original by a combination of inserting literal byte-sequences and
71 copying ranges of bytes from the original. This is where the
72 compression takes place, by encoding the large common parts of
73 original and target in small copy instructions.</p>
74
75 <p>The target is constructed from beginning to end, with the data
76 generated by each instruction appended after the data of all previous
@@ -213,11 +213,11 @@
213 <ul>
214 <li>Pure text files generate a pure text delta.
215 </li>
216 <li>Binary files generate a delta that may contain some binary data.
217 </li>
218 <li>The delta encoding does not attempt to compress the content.
219 It was considered to be much
220 more sensible to do compression using a separate general-purpose
221 compression library, like <a href="http://www.zlib.net">zlib</a>.
222 </li>
223 </ul>
224
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -49,11 +49,11 @@
4949
</ul>
5050
5151
These seven artifact types are described in the following sections.
5252
5353
In the current implementation (as of 2009-01-25) the artifacts that
54
-make up a fossil repository are stored in in as delta- and zlib-compressed
54
+make up a fossil repository are stored as delta- and zlib-compressed
5555
blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
5656
is an implementation detail and might change in a future release. For
5757
the purpose of this article "file format" means the format of the artifacts,
5858
not how the artifacts are stored on disk. It is the artifact format that
5959
is intended to be enduring. The specifics of how artifacts are stored on
@@ -184,11 +184,11 @@
184184
ancestor, the Q-card is used to identify a single check-in or a small
185185
range of check-ins which were cherry-picked for inclusion in or
186186
exclusion from the current manifest. The first argument of
187187
the Q-card is the artifact ID of another manifest (the "target")
188188
which has had its changes included or excluded in the current manifest.
189
-The target is preceeded by "+" or "-" to show inclusion or
189
+The target is preceded by "+" or "-" to show inclusion or
190190
exclusion, respectively. The optional second argument to the
191191
Q-card is another manifest artifact ID which is the "baseline"
192192
for the cherry-pick. If omitted, the baseline is the primary
193193
parent of the target. The
194194
changes included or excluded consist of all changes moving from
@@ -315,11 +315,11 @@
315315
is either "+", "-", or "*". The "+" means the tag should be added
316316
to the artifact. The "-" means the tag should be removed.
317317
The "*" character means the tag should be added to the artifact
318318
and all direct descendants (but not descendents through a merge) down
319319
to but not including the first descendant that contains a
320
-more recent "-" or "+" tag with the same name.
320
+more recent "-", "*", or "+" tag with the same name.
321321
The optional third argument is the value of the tag. A tag
322322
without a value is a boolean.
323323
324324
When two or more tags with the same name are applied to the
325325
same artifact, the tag with the latest (most recent) date is
@@ -362,11 +362,11 @@
362362
gives the name of the wiki page. The optional N card specifies
363363
the mimetype of the wiki text. If the N card is omitted, the
364364
mimetype is assumed to be text/x-fossil-wiki.
365365
The U card specifies the login
366366
of the user who made this edit to the wiki page. The Z card is
367
-the usual checksum over the either artifact and is required.
367
+the usual checksum over the entire artifact and is required.
368368
369369
The W card is used to specify the text of the wiki page. The
370370
argument to the W card is an integer which is the number of bytes
371371
of text in the wiki page. That text follows the newline character
372372
that terminates the W card. The wiki text is always followed by one
@@ -453,11 +453,11 @@
453453
454454
There may be zero or one N cards. The N card specifies the mimetype of the
455455
comment text provided in the C card. If the N card is omitted, the C card
456456
mimetype is taken to be text/plain.
457457
458
-A single U card gives the name of the user to added the attachment.
458
+A single U card gives the name of the user who added the attachment.
459459
If an attachment is added anonymously, then the U card may be omitted.
460460
461461
The Z card is the usual checksum over the rest of the attachment artifact.
462462
The Z card is required.
463463
464464
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -49,11 +49,11 @@
49 </ul>
50
51 These seven artifact types are described in the following sections.
52
53 In the current implementation (as of 2009-01-25) the artifacts that
54 make up a fossil repository are stored in in as delta- and zlib-compressed
55 blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
56 is an implementation detail and might change in a future release. For
57 the purpose of this article "file format" means the format of the artifacts,
58 not how the artifacts are stored on disk. It is the artifact format that
59 is intended to be enduring. The specifics of how artifacts are stored on
@@ -184,11 +184,11 @@
184 ancestor, the Q-card is used to identify a single check-in or a small
185 range of check-ins which were cherry-picked for inclusion in or
186 exclusion from the current manifest. The first argument of
187 the Q-card is the artifact ID of another manifest (the "target")
188 which has had its changes included or excluded in the current manifest.
189 The target is preceeded by "+" or "-" to show inclusion or
190 exclusion, respectively. The optional second argument to the
191 Q-card is another manifest artifact ID which is the "baseline"
192 for the cherry-pick. If omitted, the baseline is the primary
193 parent of the target. The
194 changes included or excluded consist of all changes moving from
@@ -315,11 +315,11 @@
315 is either "+", "-", or "*". The "+" means the tag should be added
316 to the artifact. The "-" means the tag should be removed.
317 The "*" character means the tag should be added to the artifact
318 and all direct descendants (but not descendents through a merge) down
319 to but not including the first descendant that contains a
320 more recent "-" or "+" tag with the same name.
321 The optional third argument is the value of the tag. A tag
322 without a value is a boolean.
323
324 When two or more tags with the same name are applied to the
325 same artifact, the tag with the latest (most recent) date is
@@ -362,11 +362,11 @@
362 gives the name of the wiki page. The optional N card specifies
363 the mimetype of the wiki text. If the N card is omitted, the
364 mimetype is assumed to be text/x-fossil-wiki.
365 The U card specifies the login
366 of the user who made this edit to the wiki page. The Z card is
367 the usual checksum over the either artifact and is required.
368
369 The W card is used to specify the text of the wiki page. The
370 argument to the W card is an integer which is the number of bytes
371 of text in the wiki page. That text follows the newline character
372 that terminates the W card. The wiki text is always followed by one
@@ -453,11 +453,11 @@
453
454 There may be zero or one N cards. The N card specifies the mimetype of the
455 comment text provided in the C card. If the N card is omitted, the C card
456 mimetype is taken to be text/plain.
457
458 A single U card gives the name of the user to added the attachment.
459 If an attachment is added anonymously, then the U card may be omitted.
460
461 The Z card is the usual checksum over the rest of the attachment artifact.
462 The Z card is required.
463
464
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -49,11 +49,11 @@
49 </ul>
50
51 These seven artifact types are described in the following sections.
52
53 In the current implementation (as of 2009-01-25) the artifacts that
54 make up a fossil repository are stored as delta- and zlib-compressed
55 blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
56 is an implementation detail and might change in a future release. For
57 the purpose of this article "file format" means the format of the artifacts,
58 not how the artifacts are stored on disk. It is the artifact format that
59 is intended to be enduring. The specifics of how artifacts are stored on
@@ -184,11 +184,11 @@
184 ancestor, the Q-card is used to identify a single check-in or a small
185 range of check-ins which were cherry-picked for inclusion in or
186 exclusion from the current manifest. The first argument of
187 the Q-card is the artifact ID of another manifest (the "target")
188 which has had its changes included or excluded in the current manifest.
189 The target is preceded by "+" or "-" to show inclusion or
190 exclusion, respectively. The optional second argument to the
191 Q-card is another manifest artifact ID which is the "baseline"
192 for the cherry-pick. If omitted, the baseline is the primary
193 parent of the target. The
194 changes included or excluded consist of all changes moving from
@@ -315,11 +315,11 @@
315 is either "+", "-", or "*". The "+" means the tag should be added
316 to the artifact. The "-" means the tag should be removed.
317 The "*" character means the tag should be added to the artifact
318 and all direct descendants (but not descendents through a merge) down
319 to but not including the first descendant that contains a
320 more recent "-", "*", or "+" tag with the same name.
321 The optional third argument is the value of the tag. A tag
322 without a value is a boolean.
323
324 When two or more tags with the same name are applied to the
325 same artifact, the tag with the latest (most recent) date is
@@ -362,11 +362,11 @@
362 gives the name of the wiki page. The optional N card specifies
363 the mimetype of the wiki text. If the N card is omitted, the
364 mimetype is assumed to be text/x-fossil-wiki.
365 The U card specifies the login
366 of the user who made this edit to the wiki page. The Z card is
367 the usual checksum over the entire artifact and is required.
368
369 The W card is used to specify the text of the wiki page. The
370 argument to the W card is an integer which is the number of bytes
371 of text in the wiki page. That text follows the newline character
372 that terminates the W card. The wiki text is always followed by one
@@ -453,11 +453,11 @@
453
454 There may be zero or one N cards. The N card specifies the mimetype of the
455 comment text provided in the C card. If the N card is omitted, the C card
456 mimetype is taken to be text/plain.
457
458 A single U card gives the name of the user who added the attachment.
459 If an attachment is added anonymously, then the U card may be omitted.
460
461 The Z card is the usual checksum over the rest of the attachment artifact.
462 The Z card is required.
463
464
+2 -1
--- www/hints.wiki
+++ www/hints.wiki
@@ -9,11 +9,12 @@
99
window is run as a separate Tcl/Tk process, so you will need to
1010
have Tcl/Tk installed on your machine for this to work. Visit
1111
[http://www.activestate.com/activetcl] to for a quick download of
1212
Tcl/Tk if you do not already have it on your system.)
1313
14
- 3. The "[/help?cmd=clean | fossil clean -f]" command makes a great
14
+ 3. The "[/help/clean | fossil clean -f]" or
15
+ "[/help/clean | fossil clean --verily]" command is a great
1516
alternative to "make clean".
1617
1718
4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
1819
edits in any of your Fossil projects. Use
1920
"[/help?cmd=all | fossil all pull]" on your laptop
2021
--- www/hints.wiki
+++ www/hints.wiki
@@ -9,11 +9,12 @@
9 window is run as a separate Tcl/Tk process, so you will need to
10 have Tcl/Tk installed on your machine for this to work. Visit
11 [http://www.activestate.com/activetcl] to for a quick download of
12 Tcl/Tk if you do not already have it on your system.)
13
14 3. The "[/help?cmd=clean | fossil clean -f]" command makes a great
 
15 alternative to "make clean".
16
17 4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
18 edits in any of your Fossil projects. Use
19 "[/help?cmd=all | fossil all pull]" on your laptop
20
--- www/hints.wiki
+++ www/hints.wiki
@@ -9,11 +9,12 @@
9 window is run as a separate Tcl/Tk process, so you will need to
10 have Tcl/Tk installed on your machine for this to work. Visit
11 [http://www.activestate.com/activetcl] to for a quick download of
12 Tcl/Tk if you do not already have it on your system.)
13
14 3. The "[/help/clean | fossil clean -f]" or
15 "[/help/clean | fossil clean --verily]" command is a great
16 alternative to "make clean".
17
18 4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
19 edits in any of your Fossil projects. Use
20 "[/help?cmd=all | fossil all pull]" on your laptop
21
+3 -1
--- www/qandc.wiki
+++ www/qandc.wiki
@@ -146,11 +146,13 @@
146146
You do not need any other packages
147147
(diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache,
148148
sqlite, and so forth)
149149
in order to run fossil. Fossil runs just fine in a chroot jail all
150150
by itself. And the self-contained fossil
151
-executable is much less than 1MB in size.
151
+executable is much less than 1MB in size. (Update 2015-01-12: Fossil has
152
+grown in the years since the previous sentence was written but is still
153
+much less than 2MB according to "size" when compiled using -Os on x64 Linux.)
152154
Fossil is the very opposite of bloat.</p>
153155
</blockquote>
154156
155157
156158
</nowiki>
157159
--- www/qandc.wiki
+++ www/qandc.wiki
@@ -146,11 +146,13 @@
146 You do not need any other packages
147 (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache,
148 sqlite, and so forth)
149 in order to run fossil. Fossil runs just fine in a chroot jail all
150 by itself. And the self-contained fossil
151 executable is much less than 1MB in size.
 
 
152 Fossil is the very opposite of bloat.</p>
153 </blockquote>
154
155
156 </nowiki>
157
--- www/qandc.wiki
+++ www/qandc.wiki
@@ -146,11 +146,13 @@
146 You do not need any other packages
147 (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache,
148 sqlite, and so forth)
149 in order to run fossil. Fossil runs just fine in a chroot jail all
150 by itself. And the self-contained fossil
151 executable is much less than 1MB in size. (Update 2015-01-12: Fossil has
152 grown in the years since the previous sentence was written but is still
153 much less than 2MB according to "size" when compiled using -Os on x64 Linux.)
154 Fossil is the very opposite of bloat.</p>
155 </blockquote>
156
157
158 </nowiki>
159

Keyboard Shortcuts

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